feat(environment): feature flags (#4343)

Co-authored-by: Edd <edd@vega.xyz>
This commit is contained in:
Art 2023-07-25 11:12:53 +02:00 committed by GitHub
parent 47ce68455a
commit c12ac45890
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 703 additions and 213 deletions

View File

@ -5,8 +5,6 @@ const windowOrDefault = (key: string) => {
return (process.env[key] as string) || '';
};
const truthy = ['1', 'true'];
export const ENV = {
// Data sources
// Environment
@ -20,19 +18,6 @@ export const ENV = {
governanceUrl: windowOrDefault('NX_VEGA_GOVERNANCE_URL'),
vegaRepoUrl: windowOrDefault('NX_VEGA_REPO_URL'),
},
flags: {
assets: truthy.includes(windowOrDefault('NX_EXPLORER_ASSETS')),
genesis: truthy.includes(windowOrDefault('NX_EXPLORER_GENESIS')),
governance: truthy.includes(windowOrDefault('NX_EXPLORER_GOVERNANCE')),
markets: truthy.includes(windowOrDefault('NX_EXPLORER_MARKETS')),
oracles: truthy.includes(windowOrDefault('NX_EXPLORER_ORACLES')),
txsList: truthy.includes(windowOrDefault('NX_EXPLORER_TXS_LIST')),
networkParameters: truthy.includes(
windowOrDefault('NX_EXPLORER_NETWORK_PARAMETERS')
),
parties: truthy.includes(windowOrDefault('NX_EXPLORER_PARTIES')),
validators: truthy.includes(windowOrDefault('NX_EXPLORER_VALIDATORS')),
},
addresses: {
feedback: windowOrDefault('NX_GITHUB_FEEDBACK_URL'),
},

View File

@ -1,5 +0,0 @@
import { ENV } from './env';
export default {
...ENV.flags,
};

View File

@ -14,7 +14,6 @@ import { Block } from './blocks/id';
import { Blocks } from './blocks/home';
import { Tx } from './txs/id';
import { TxsList } from './txs/home';
import flags from '../config/flags';
import { t } from '@vegaprotocol/i18n';
import { Routes } from './route-names';
import { NetworkParameters } from './network-parameters';
@ -30,6 +29,7 @@ import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
import { remove0x } from '@vegaprotocol/utils';
import { PartyAccountsByAsset } from './parties/id/accounts';
import { Disclaimer } from './pages/disclaimer';
import { FLAGS } from '@vegaprotocol/environment';
export type Navigable = {
path: string;
@ -59,7 +59,7 @@ type Route = RouteItem & {
children?: RouteItem[];
};
const partiesRoutes: Route[] = flags.parties
const partiesRoutes: Route[] = FLAGS.EXPLORER_PARTIES
? [
{
path: Routes.PARTIES,
@ -119,7 +119,7 @@ const partiesRoutes: Route[] = flags.parties
]
: [];
const assetsRoutes: Route[] = flags.assets
const assetsRoutes: Route[] = FLAGS.EXPLORER_ASSETS
? [
{
path: Routes.ASSETS,
@ -147,7 +147,7 @@ const assetsRoutes: Route[] = flags.assets
]
: [];
const genesisRoutes: Route[] = flags.genesis
const genesisRoutes: Route[] = FLAGS.EXPLORER_GENESIS
? [
{
path: Routes.GENESIS,
@ -163,7 +163,7 @@ const genesisRoutes: Route[] = flags.genesis
]
: [];
const governanceRoutes: Route[] = flags.governance
const governanceRoutes: Route[] = FLAGS.EXPLORER_GOVERNANCE
? [
{
path: Routes.GOVERNANCE,
@ -179,7 +179,7 @@ const governanceRoutes: Route[] = flags.governance
]
: [];
const marketsRoutes: Route[] = flags.markets
const marketsRoutes: Route[] = FLAGS.EXPLORER_MARKETS
? [
{
path: Routes.MARKETS,
@ -207,7 +207,7 @@ const marketsRoutes: Route[] = flags.markets
]
: [];
const networkParametersRoutes: Route[] = flags.networkParameters
const networkParametersRoutes: Route[] = FLAGS.EXPLORER_NETWORK_PARAMETERS
? [
{
path: Routes.NETWORK_PARAMETERS,
@ -225,7 +225,7 @@ const networkParametersRoutes: Route[] = flags.networkParameters
]
: [];
const validators: Route[] = flags.validators
const validators: Route[] = FLAGS.EXPLORER_VALIDATORS
? [
{
path: Routes.VALIDATORS,

View File

@ -2,14 +2,13 @@ import * as Sentry from '@sentry/react';
import { toBigNum } from '@vegaprotocol/utils';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet, useEagerConnect } from '@vegaprotocol/wallet';
import { useEnvironment } from '@vegaprotocol/environment';
import { FLAGS, useEnvironment } from '@vegaprotocol/environment';
import { useWeb3React } from '@web3-react/core';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { SplashError } from './components/splash-error';
import { SplashLoader } from './components/splash-loader';
import { Flags } from './config';
import {
AppStateActionType,
useAppState,
@ -80,7 +79,7 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
}
};
if (!Flags.NETWORK_DOWN) {
if (!FLAGS.GOVERNANCE_NETWORK_DOWN) {
run();
}
}, [token, appDispatch, staking, vesting]);
@ -148,7 +147,7 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
};
// Only begin polling if network limits flag is set, as this is a new API not yet on mainnet 7/3/22
if (Flags.NETWORK_LIMITS) {
if (FLAGS.GOVERNANCE_NETWORK_LIMITS) {
getNetworkLimits();
}
@ -157,7 +156,7 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
};
}, [appDispatch, VEGA_URL, t]);
if (Flags.NETWORK_DOWN) {
if (FLAGS.GOVERNANCE_NETWORK_DOWN) {
return (
<Splash>
<SplashError />

View File

@ -67,12 +67,6 @@ export const ENV = {
localProviderUrl: windowOrDefault('NX_LOCAL_PROVIDER_URL'),
delegationsPagination: windowOrDefault('NX_DELEGATIONS_PAGINATION'),
rest: windowOrDefault('NX_VEGA_REST_URL'),
flags: {
NETWORK_DOWN: TRUTHY.includes(windowOrDefault('NX_NETWORK_DOWN')),
MOCK: TRUTHY.includes(windowOrDefault('NX_MOCKED')),
FAIRGROUND: TRUTHY.includes(windowOrDefault('NX_FAIRGROUND')),
NETWORK_LIMITS: TRUTHY.includes(windowOrDefault('NX_NETWORK_LIMITS')),
},
addresses:
ContractAddresses[(envName === 'local' ? 'CUSTOM' : envName) as Networks],
};

View File

@ -1,5 +0,0 @@
import { ENV } from './env';
export const Flags = {
...ENV.flags,
};

View File

@ -1,2 +1 @@
export * from './flags';
export * from './env';

View File

@ -33,3 +33,7 @@ CYPRESS_VEGA_TOKEN_URL=https://governance.fairground.wtf
CYPRESS_VEGA_URL=http://localhost:3008/graphql
CYPRESS_VEGA_WALLET_URL=http://localhost:1789
CYPRESS_VEGA_WALLET_API_TOKEN=
# Cosmic elevator flags (MUST be doubled with CYPRESS_ prefix)
NX_SUCCESSOR_MARKETS=true
CYPRESS_NX_SUCCESSOR_MARKETS=true

View File

@ -363,10 +363,13 @@ describe('Closed markets', { tags: '@smoke' }, () => {
.first()
.find('button svg')
.should('exist');
cy.get(rowSelector)
.find('[col-id="successorMarketID"]')
.first()
.should('have.text', ' - ');
if (Cypress.env('NX_SUCCESSOR_MARKETS')) {
cy.get(rowSelector)
.find('[col-id="successorMarketID"]')
.first()
.should('have.text', ' - ');
}
});
// test market list for market in terminated state

View File

@ -68,7 +68,10 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
validateMarketDataRow(0, 'Name', 'BTCUSD Monthly (30 Jun 2022)');
validateMarketDataRow(1, 'Market ID', 'market-0');
validateMarketDataRow(2, 'Parent Market ID', 'market-1');
if (Cypress.env('NX_SUCCESSOR_MARKETS')) {
validateMarketDataRow(2, 'Parent Market ID', 'PARENT-A');
}
validateMarketDataRow(
3,
'Trading Mode',

View File

@ -33,6 +33,9 @@ import {
networkParamQuery,
liquidityProvisionsQuery,
liquidityProviderFeeShareQuery,
successorMarketQuery,
parentMarketIdQuery,
successorMarketIdsQuery,
} from '@vegaprotocol/mock';
import type { PartialDeep } from 'type-fest';
import type { MarketDataQuery, MarketsQuery } from '@vegaprotocol/markets';
@ -180,6 +183,9 @@ const mockTradingPage = (
protocolUpgradeProposalsQuery()
);
aliasGQLQuery(req, 'BlockStatistics', blockStatisticsQuery());
aliasGQLQuery(req, 'SuccessorMarket', successorMarketQuery());
aliasGQLQuery(req, 'ParentMarketId', parentMarketIdQuery());
aliasGQLQuery(req, 'SuccessorMarketIds', successorMarketIdsQuery());
};
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace

View File

@ -13,3 +13,9 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
# NX_STOP_ORDERS
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS

View File

@ -15,3 +15,9 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
# NX_STOP_ORDERS
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS

View File

@ -13,3 +13,9 @@ NX_VEGA_DOCS_URL=#
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
# NX_STOP_ORDERS
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS

View File

@ -15,3 +15,9 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
# TAG name of the current app version - TODO: bump to the latest upon release
NX_APP_VERSION=v0.20.21-core-0.71.6
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
# NX_STOP_ORDERS
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS

View File

@ -15,3 +15,9 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
# TAG name of the current app version - TODO: bump to the latest upon release
NX_APP_VERSION=v0.20.19-core-0.71.6
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
# NX_STOP_ORDERS
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS

View File

@ -13,3 +13,9 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
# NX_STOP_ORDERS
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS

View File

@ -14,3 +14,9 @@ NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
# NX_STOP_ORDERS
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS

View File

@ -14,3 +14,9 @@ NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
# NX_STOP_ORDERS
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS

View File

@ -18,6 +18,8 @@ import {
} from '../../components/resizable-grid';
import { TradingViews } from './trade-views';
import { MarketSuccessorBanner } from '../../components/market-banner';
import { FLAGS } from '@vegaprotocol/environment';
interface TradeGridProps {
market: Market | null;
onSelect: (marketId: string, metaKey?: boolean) => void;
@ -160,7 +162,7 @@ export const TradeGrid = ({ market, pinnedAsset }: TradeGridProps) => {
return (
<div className={wrapperClasses}>
<div>
<MarketSuccessorBanner market={market} />
{FLAGS.SUCCESSOR_MARKETS && <MarketSuccessorBanner market={market} />}
<OracleBanner marketId={market?.id || ''} />
</div>
<div className="min-h-0 p-0.5">

View File

@ -13,6 +13,7 @@ import { NO_MARKET } from './constants';
import AutoSizer from 'react-virtualized-auto-sizer';
import classNames from 'classnames';
import { MarketSuccessorBanner } from '../../components/market-banner';
import { FLAGS } from '@vegaprotocol/environment';
interface TradePanelsProps {
market: Market | null;
@ -64,7 +65,7 @@ export const TradePanels = ({
return (
<div className="h-full grid grid-rows-[min-content_1fr_min-content]">
<div>
<MarketSuccessorBanner market={market} />
{FLAGS.SUCCESSOR_MARKETS && <MarketSuccessorBanner market={market} />}
<OracleBanner marketId={market?.id || ''} />
</div>
<div className="h-full">

View File

@ -25,6 +25,31 @@ import {
marketsDataQuery,
createMarketsDataFragment,
} from '@vegaprotocol/mock';
import type { FeatureFlags } from '@vegaprotocol/environment';
jest.mock('@vegaprotocol/markets', () => ({
...jest.requireActual('@vegaprotocol/markets'),
useSuccessorMarket: (marketId: string) =>
marketId === 'include-0'
? {
data: {
id: 'successorMarketID',
state: 'STATE_ACTIVE',
tradableInstrument: {
instrument: {
name: 'Successor Market Name',
code: 'SuccessorCode',
},
},
},
}
: { data: undefined },
}));
jest.mock('@vegaprotocol/environment', () => ({
...jest.requireActual('@vegaprotocol/environment'),
FLAGS: { SUCCESSOR_MARKETS: true } as Partial<FeatureFlags>,
}));
describe('Closed', () => {
let originalNow: typeof Date.now;
@ -322,27 +347,8 @@ describe('Closed', () => {
node: createMarketFragment({
id: 'include-0',
state: MarketState.STATE_SETTLED,
successorMarketID: 'successorMarketID',
}),
},
{
__typename: 'MarketEdge' as const,
node: {
...createMarketFragment({
id: 'successorMarketID',
state: MarketState.STATE_ACTIVE,
}),
tradableInstrument: {
...createMarketFragment().tradableInstrument,
instrument: {
...createMarketFragment().tradableInstrument.instrument,
id: 'successorAssset',
name: 'Successor Market Name',
code: 'SuccessorCode',
},
},
},
},
];
const mixedMarketsMock: MockedResponse<MarketsQuery> = {

View File

@ -23,7 +23,7 @@ import type {
import {
MarketActionsDropdown,
closedMarketsWithDataProvider,
marketProvider,
useSuccessorMarket,
} from '@vegaprotocol/markets';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import type { ColDef } from 'ag-grid-community';
@ -31,6 +31,7 @@ import { SettlementDateCell } from './settlement-date-cell';
import { SettlementPriceCell } from './settlement-price-cell';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
import { FLAGS } from '@vegaprotocol/environment';
type SettlementAsset =
MarketMaybeWithData['tradableInstrument']['instrument']['product']['settlementAsset'];
@ -51,7 +52,6 @@ interface Row {
setlementDataSourceFilter: DataSourceFilterFragment | undefined;
tradingTerminationOracleId: string;
settlementAsset: SettlementAsset;
successorMarketID: string | undefined | null;
}
export const Closed = () => {
@ -60,8 +60,6 @@ export const Closed = () => {
variables: undefined,
});
// find a position for each market and add the realised pnl to
// a normalized object
const rowData = compact(marketData).map((market) => {
const instrument = market.tradableInstrument.instrument;
@ -97,7 +95,6 @@ export const Closed = () => {
tradingTerminationOracleId:
instrument.product.dataSourceSpecForTradingTermination.id,
settlementAsset: instrument.product.settlementAsset,
successorMarketID: market.successorMarketID,
};
return row;
@ -111,14 +108,8 @@ export const Closed = () => {
export const SuccessorMarketRenderer = ({
value,
}: VegaICellRendererParams<Row, 'successorMarketID'>) => {
const { data } = useDataProvider({
dataProvider: marketProvider,
variables: {
marketId: value || '',
},
skip: !value,
});
}: VegaICellRendererParams<Row, 'id'>) => {
const { data } = useSuccessorMarket(value);
const onMarketClick = useMarketClickHandler();
return data ? (
<MarketNameCell
@ -139,8 +130,9 @@ const ClosedMarketsDataGrid = ({
error: Error | undefined;
}) => {
const openAssetDialog = useAssetDetailsDialogStore((store) => store.open);
const colDefs = useMemo(() => {
const cols: ColDef[] = [
const cols: ColDef[] = compact([
{
headerName: t('Market'),
field: 'code',
@ -208,9 +200,10 @@ const ClosedMarketsDataGrid = ({
},
},
},
{
FLAGS.SUCCESSOR_MARKETS && {
headerName: t('Successor market'),
field: 'successorMarketID',
colId: 'successorMarketID',
field: 'id',
cellRenderer: 'SuccessorMarketRenderer',
},
{
@ -298,7 +291,7 @@ const ClosedMarketsDataGrid = ({
);
},
},
];
]);
return cols;
}, [openAssetDialog]);

View File

@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import { MockedProvider } from '@apollo/react-testing';
import * as dataProviders from '@vegaprotocol/data-provider';
import { MarketSuccessorBanner } from './market-successor-banner';
import * as Types from '@vegaprotocol/types';
import * as allUtils from '@vegaprotocol/utils';
@ -19,7 +18,6 @@ const market = {
marketTimestamps: {
close: null,
},
successorMarketID: 'successorMarketID',
} as unknown as Market;
let mockDataSuccessorMarket: PartialDeep<Market> | null = null;
@ -45,6 +43,12 @@ jest.mock('@vegaprotocol/utils', () => ({
let mockCandles = {};
jest.mock('@vegaprotocol/markets', () => ({
...jest.requireActual('@vegaprotocol/markets'),
useSuccessorMarket: (marketId: string) =>
marketId
? {
data: mockDataSuccessorMarket,
}
: { data: undefined },
useCandles: () => mockCandles,
}));
@ -70,35 +74,12 @@ describe('MarketSuccessorBanner', () => {
expect(container).toBeEmptyDOMElement();
});
it('when no successorMarketID', () => {
const amendedMarket = {
...market,
successorMarketID: null,
};
const { container } = render(
<MarketSuccessorBanner market={amendedMarket} />,
{
wrapper: MockedProvider,
}
);
expect(container).toBeEmptyDOMElement();
expect(dataProviders.useDataProvider).lastCalledWith(
expect.objectContaining({ skip: true })
);
});
it('no successor market data', () => {
mockDataSuccessorMarket = null;
const { container } = render(<MarketSuccessorBanner market={market} />, {
wrapper: MockedProvider,
});
expect(container).toBeEmptyDOMElement();
expect(dataProviders.useDataProvider).lastCalledWith(
expect.objectContaining({
variables: { marketId: 'successorMarketID' },
skip: false,
})
);
});
it('successor market not in continuous mode', () => {
@ -110,12 +91,6 @@ describe('MarketSuccessorBanner', () => {
wrapper: MockedProvider,
});
expect(container).toBeEmptyDOMElement();
expect(dataProviders.useDataProvider).lastCalledWith(
expect.objectContaining({
variables: { marketId: 'successorMarketID' },
skip: false,
})
);
expect(allUtils.getMarketExpiryDate).toHaveBeenCalled();
});
@ -128,12 +103,6 @@ describe('MarketSuccessorBanner', () => {
wrapper: MockedProvider,
});
expect(container).toBeEmptyDOMElement();
expect(dataProviders.useDataProvider).lastCalledWith(
expect.objectContaining({
variables: { marketId: 'successorMarketID' },
skip: false,
})
);
expect(allUtils.getMarketExpiryDate).toHaveBeenCalled();
});
});

View File

@ -1,11 +1,10 @@
import { useState } from 'react';
import { isBefore, formatDuration, intervalToDuration } from 'date-fns';
import { useDataProvider } from '@vegaprotocol/data-provider';
import type { Market } from '@vegaprotocol/markets';
import {
calcCandleVolume,
marketProvider,
useCandles,
useSuccessorMarket,
} from '@vegaprotocol/markets';
import {
ExternalLink,
@ -30,13 +29,8 @@ export const MarketSuccessorBanner = ({
}: {
market: Market | null;
}) => {
const { data: successorData } = useDataProvider({
dataProvider: marketProvider,
variables: {
marketId: market?.successorMarketID || '',
},
skip: !market?.successorMarketID,
});
const { data: successorData } = useSuccessorMarket(market?.id);
const [visible, setVisible] = useState(true);
const expiry = market

View File

@ -12,7 +12,7 @@ import {
NodeCheckDocument,
NodeCheckTimeUpdateDocument,
} from '../utils/__generated__/NodeCheck';
import type { Environment } from '../types';
import type { CosmicElevatorFlags, Environment, FeatureFlags } from '../types';
import { Networks } from '../types';
import { compileErrors } from '../utils/compile-errors';
import { envSchema } from '../utils/validate-environment';
@ -39,8 +39,12 @@ const VERSION = 1;
export const STORAGE_KEY = `vega_url_${VERSION}`;
const SUBSCRIPTION_TIMEOUT = 3000;
export const ENV = compileEnvVars();
export const FLAGS = compileFeatureFlags();
export const useEnvironment = create<EnvStore>()((set, get) => ({
...compileEnvVars(),
...compileFeatureFlags(),
nodes: [],
status: 'default',
error: null,
@ -372,6 +376,108 @@ function compileEnvVars() {
return env;
}
function compileFeatureFlags(): FeatureFlags {
const TRUTHY = ['1', 'true'];
const COSMIC_ELEVATOR_FLAGS: CosmicElevatorFlags = {
ICEBERG_ORDERS: TRUTHY.includes(
windowOrDefault(
'NX_ICEBERG_ORDERS',
process.env['NX_ICEBERG_ORDERS']
) as string
),
STOP_ORDERS: TRUTHY.includes(
windowOrDefault('NX_STOP_ORDERS', process.env['NX_STOP_ORDERS']) as string
),
SUCCESSOR_MARKETS: TRUTHY.includes(
windowOrDefault(
'NX_SUCCESSOR_MARKETS',
process.env['NX_SUCCESSOR_MARKETS']
) as string
),
PRODUCT_PERPETUALS: TRUTHY.includes(
windowOrDefault(
'NX_PRODUCT_PERPETUALS',
process.env['NX_PRODUCT_PERPETUALS']
) as string
),
};
const EXPLORER_FLAGS = {
EXPLORER_ASSETS: TRUTHY.includes(
windowOrDefault(
'NX_EXPLORER_ASSETS',
process.env['NX_EXPLORER_ASSETS']
) as string
),
EXPLORER_GENESIS: TRUTHY.includes(
windowOrDefault(
'NX_EXPLORER_GENESIS',
process.env['NX_EXPLORER_GENESIS']
) as string
),
EXPLORER_GOVERNANCE: TRUTHY.includes(
windowOrDefault(
'NX_EXPLORER_GOVERNANCE',
process.env['NX_EXPLORER_GOVERNANCE']
) as string
),
EXPLORER_MARKETS: TRUTHY.includes(
windowOrDefault(
'NX_EXPLORER_MARKETS',
process.env['NX_EXPLORER_MARKETS']
) as string
),
EXPLORER_ORACLES: TRUTHY.includes(
windowOrDefault(
'NX_EXPLORER_ORACLES',
process.env['NX_EXPLORER_ORACLES']
) as string
),
EXPLORER_TXS_LIST: TRUTHY.includes(
windowOrDefault(
'NX_EXPLORER_TXS_LIST',
process.env['NX_EXPLORER_TXS_LIST']
) as string
),
EXPLORER_NETWORK_PARAMETERS: TRUTHY.includes(
windowOrDefault(
'NX_EXPLORER_NETWORK_PARAMETERS',
process.env['NX_EXPLORER_NETWORK_PARAMETERS']
) as string
),
EXPLORER_PARTIES: TRUTHY.includes(
windowOrDefault(
'NX_EXPLORER_PARTIES',
process.env['NX_EXPLORER_PARTIES']
) as string
),
EXPLORER_VALIDATORS: TRUTHY.includes(
windowOrDefault(
'NX_EXPLORER_VALIDATORS',
process.env['NX_EXPLORER_VALIDATORS']
) as string
),
};
const GOVERNANCE_FLAGS = {
GOVERNANCE_NETWORK_DOWN: TRUTHY.includes(
windowOrDefault(
'NX_NETWORK_DOWN',
process.env['NX_NETWORK_DOWN']
) as string
),
GOVERNANCE_NETWORK_LIMITS: TRUTHY.includes(
windowOrDefault(
'NX_GOVERNANCE_NETWORK_LIMITS',
process.env['NX_GOVERNANCE_NETWORK_LIMITS']
) as string
),
};
return {
...COSMIC_ELEVATOR_FLAGS,
...EXPLORER_FLAGS,
...GOVERNANCE_FLAGS,
};
}
function parseNetworks(value?: string) {
if (value) {
try {
@ -414,7 +520,7 @@ function getEtherscanUrl(
export function windowOrDefault(key: string, defaultValue?: string) {
if (typeof window !== 'undefined') {
// @ts-ignore avoid conflic in env
// @ts-ignore avoid conflict in env
if (window._env_ && window._env_[key]) {
// @ts-ignore presence has been check above
return window._env_[key];

View File

@ -1,6 +1,9 @@
import type z from 'zod';
import type { tomlConfigSchema } from './utils/validate-configuration';
import type { envSchema } from './utils/validate-environment';
import type {
envSchema,
featureFlagsSchema,
} from './utils/validate-environment';
export enum Networks {
VALIDATOR_TESTNET = 'VALIDATOR_TESTNET',
@ -12,5 +15,10 @@ export enum Networks {
MAINNET = 'MAINNET',
}
export type Environment = z.infer<typeof envSchema>;
export type FeatureFlags = z.infer<typeof featureFlagsSchema>;
export type CosmicElevatorFlags = Pick<
FeatureFlags,
'ICEBERG_ORDERS' | 'STOP_ORDERS' | 'SUCCESSOR_MARKETS' | 'PRODUCT_PERPETUALS'
>;
export type Configuration = z.infer<typeof tomlConfigSchema>;
export const CUSTOM_NODE_KEY = 'custom' as const;

View File

@ -10,62 +10,92 @@ export enum Networks {
MAINNET = 'MAINNET',
}
const schemaObject = {
VEGA_URL: z.optional(z.string()),
VEGA_WALLET_URL: z.optional(z.string()),
VEGA_CONFIG_URL: z.optional(z.string()),
GIT_BRANCH: z.optional(z.string()),
GIT_COMMIT_HASH: z.optional(z.string()),
GIT_ORIGIN_URL: z.optional(z.string()),
GITHUB_FEEDBACK_URL: z.optional(z.string()),
ORACLE_PROOFS_URL: z.optional(z.string().url()),
VEGA_ENV: z.nativeEnum(Networks),
VEGA_CONSOLE_URL: z.optional(z.string()),
VEGA_EXPLORER_URL: z.optional(z.string()),
VEGA_TOKEN_URL: z.optional(z.string()),
VEGA_DOCS_URL: z.optional(z.string()),
VEGA_NETWORKS: z
.object(
Object.keys(Networks).reduce(
(acc, env) => ({
...acc,
[env]: z.optional(z.string()),
}),
{}
) as Record<Networks, z.ZodOptional<z.ZodString>>
)
.strict({
message: `All keys in NX_VEGA_NETWORKS must represent a valid environment: ${Object.keys(
Networks
).join(' | ')}`,
}),
ETHEREUM_PROVIDER_URL: z.string().url({
message:
'The NX_ETHEREUM_PROVIDER_URL environment variable must be a valid url',
}),
ETHERSCAN_URL: z.string().url({
message: 'The NX_ETHERSCAN_URL environment variable must be a valid url',
}),
HOSTED_WALLET_URL: z.optional(z.string()),
MAINTENANCE_PAGE: z.optional(z.boolean()),
ETH_LOCAL_PROVIDER_URL: z.optional(z.string()),
ETH_WALLET_MNEMONIC: z.optional(z.string()),
ANNOUNCEMENTS_CONFIG_URL: z.optional(z.string()),
VEGA_INCIDENT_URL: z.optional(z.string()),
APP_VERSION: z.optional(z.string()),
SENTRY_DSN: z.optional(z.string()),
TENDERMINT_URL: z.optional(z.string()),
TENDERMINT_WEBSOCKET_URL: z.optional(z.string()),
};
// combine schema above with custom rule to ensure either
// VEGA_URL or VEGA_CONFIG_URL are provided
export const envSchema = z.object(schemaObject).refine(
(data) => {
return !(!data.VEGA_URL && !data.VEGA_CONFIG_URL);
},
{
message:
'Must provide either NX_VEGA_CONFIG_URL or NX_VEGA_URL in the environment.',
}
);
export const envSchema = z
.object({
VEGA_URL: z.optional(z.string()),
VEGA_WALLET_URL: z.optional(z.string()),
VEGA_CONFIG_URL: z.optional(z.string()),
GIT_BRANCH: z.optional(z.string()),
GIT_COMMIT_HASH: z.optional(z.string()),
GIT_ORIGIN_URL: z.optional(z.string()),
GITHUB_FEEDBACK_URL: z.optional(z.string()),
ORACLE_PROOFS_URL: z.optional(z.string().url()),
VEGA_ENV: z.nativeEnum(Networks),
VEGA_CONSOLE_URL: z.optional(z.string()),
VEGA_EXPLORER_URL: z.optional(z.string()),
VEGA_TOKEN_URL: z.optional(z.string()),
VEGA_DOCS_URL: z.optional(z.string()),
VEGA_NETWORKS: z
.object(
Object.keys(Networks).reduce(
(acc, env) => ({
...acc,
[env]: z.optional(z.string()),
}),
{}
) as Record<Networks, z.ZodOptional<z.ZodString>>
)
.strict({
message: `All keys in NX_VEGA_NETWORKS must represent a valid environment: ${Object.keys(
Networks
).join(' | ')}`,
}),
ETHEREUM_PROVIDER_URL: z.string().url({
message:
'The NX_ETHEREUM_PROVIDER_URL environment variable must be a valid url',
}),
ETHERSCAN_URL: z.string().url({
message: 'The NX_ETHERSCAN_URL environment variable must be a valid url',
}),
HOSTED_WALLET_URL: z.optional(z.string()),
MAINTENANCE_PAGE: z.optional(z.boolean()),
ETH_LOCAL_PROVIDER_URL: z.optional(z.string()),
ETH_WALLET_MNEMONIC: z.optional(z.string()),
ANNOUNCEMENTS_CONFIG_URL: z.optional(z.string()),
VEGA_INCIDENT_URL: z.optional(z.string()),
APP_VERSION: z.optional(z.string()),
SENTRY_DSN: z.optional(z.string()),
TENDERMINT_URL: z.optional(z.string()),
TENDERMINT_WEBSOCKET_URL: z.optional(z.string()),
})
.refine(
(data) => {
return !(!data.VEGA_URL && !data.VEGA_CONFIG_URL);
},
{
message:
'Must provide either NX_VEGA_CONFIG_URL or NX_VEGA_URL in the environment.',
}
);
const COSMIC_ELEVATOR_FLAGS = {
SUCCESSOR_MARKETS: z.optional(z.boolean()),
STOP_ORDERS: z.optional(z.boolean()),
ICEBERG_ORDERS: z.optional(z.boolean()),
PRODUCT_PERPETUALS: z.optional(z.boolean()),
};
const EXPLORER_FLAGS = {
EXPLORER_ASSETS: z.optional(z.boolean()),
EXPLORER_GENESIS: z.optional(z.boolean()),
EXPLORER_GOVERNANCE: z.optional(z.boolean()),
EXPLORER_NETWORK_PARAMETERS: z.optional(z.boolean()),
EXPLORER_PARTIES: z.optional(z.boolean()),
EXPLORER_VALIDATORS: z.optional(z.boolean()),
EXPLORER_MARKETS: z.optional(z.boolean()),
EXPLORER_ORACLES: z.optional(z.boolean()),
EXPLORER_TXS_LIST: z.optional(z.boolean()),
};
const GOVERNANCE_FLAGS = {
GOVERNANCE_NETWORK_DOWN: z.optional(z.boolean()),
GOVERNANCE_NETWORK_LIMITS: z.optional(z.boolean()),
};
export const featureFlagsSchema = z.object({
...COSMIC_ELEVATOR_FLAGS,
...EXPLORER_FLAGS,
...GOVERNANCE_FLAGS,
});

View File

@ -0,0 +1,37 @@
query SuccessorMarketId($marketId: ID!) {
market(id: $marketId) {
successorMarketID
}
}
query ParentMarketId($marketId: ID!) {
market(id: $marketId) {
parentMarketID
}
}
query SuccessorMarketIds {
marketsConnection {
edges {
node {
id
successorMarketID
}
}
}
}
query SuccessorMarket($marketId: ID!) {
market(id: $marketId) {
id
state
tradingMode
positionDecimalPlaces
tradableInstrument {
instrument {
name
code
}
}
}
}

View File

@ -0,0 +1,185 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type SuccessorMarketIdQueryVariables = Types.Exact<{
marketId: Types.Scalars['ID'];
}>;
export type SuccessorMarketIdQuery = { __typename?: 'Query', market?: { __typename?: 'Market', successorMarketID?: string | null } | null };
export type ParentMarketIdQueryVariables = Types.Exact<{
marketId: Types.Scalars['ID'];
}>;
export type ParentMarketIdQuery = { __typename?: 'Query', market?: { __typename?: 'Market', parentMarketID?: string | null } | null };
export type SuccessorMarketIdsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type SuccessorMarketIdsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, successorMarketID?: string | null } }> } | null };
export type SuccessorMarketQueryVariables = Types.Exact<{
marketId: Types.Scalars['ID'];
}>;
export type SuccessorMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, state: Types.MarketState, tradingMode: Types.MarketTradingMode, positionDecimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string } } } | null };
export const SuccessorMarketIdDocument = gql`
query SuccessorMarketId($marketId: ID!) {
market(id: $marketId) {
successorMarketID
}
}
`;
/**
* __useSuccessorMarketIdQuery__
*
* To run a query within a React component, call `useSuccessorMarketIdQuery` and pass it any options that fit your needs.
* When your component renders, `useSuccessorMarketIdQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useSuccessorMarketIdQuery({
* variables: {
* marketId: // value for 'marketId'
* },
* });
*/
export function useSuccessorMarketIdQuery(baseOptions: Apollo.QueryHookOptions<SuccessorMarketIdQuery, SuccessorMarketIdQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<SuccessorMarketIdQuery, SuccessorMarketIdQueryVariables>(SuccessorMarketIdDocument, options);
}
export function useSuccessorMarketIdLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<SuccessorMarketIdQuery, SuccessorMarketIdQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<SuccessorMarketIdQuery, SuccessorMarketIdQueryVariables>(SuccessorMarketIdDocument, options);
}
export type SuccessorMarketIdQueryHookResult = ReturnType<typeof useSuccessorMarketIdQuery>;
export type SuccessorMarketIdLazyQueryHookResult = ReturnType<typeof useSuccessorMarketIdLazyQuery>;
export type SuccessorMarketIdQueryResult = Apollo.QueryResult<SuccessorMarketIdQuery, SuccessorMarketIdQueryVariables>;
export const ParentMarketIdDocument = gql`
query ParentMarketId($marketId: ID!) {
market(id: $marketId) {
parentMarketID
}
}
`;
/**
* __useParentMarketIdQuery__
*
* To run a query within a React component, call `useParentMarketIdQuery` and pass it any options that fit your needs.
* When your component renders, `useParentMarketIdQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useParentMarketIdQuery({
* variables: {
* marketId: // value for 'marketId'
* },
* });
*/
export function useParentMarketIdQuery(baseOptions: Apollo.QueryHookOptions<ParentMarketIdQuery, ParentMarketIdQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<ParentMarketIdQuery, ParentMarketIdQueryVariables>(ParentMarketIdDocument, options);
}
export function useParentMarketIdLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ParentMarketIdQuery, ParentMarketIdQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<ParentMarketIdQuery, ParentMarketIdQueryVariables>(ParentMarketIdDocument, options);
}
export type ParentMarketIdQueryHookResult = ReturnType<typeof useParentMarketIdQuery>;
export type ParentMarketIdLazyQueryHookResult = ReturnType<typeof useParentMarketIdLazyQuery>;
export type ParentMarketIdQueryResult = Apollo.QueryResult<ParentMarketIdQuery, ParentMarketIdQueryVariables>;
export const SuccessorMarketIdsDocument = gql`
query SuccessorMarketIds {
marketsConnection {
edges {
node {
id
successorMarketID
}
}
}
}
`;
/**
* __useSuccessorMarketIdsQuery__
*
* To run a query within a React component, call `useSuccessorMarketIdsQuery` and pass it any options that fit your needs.
* When your component renders, `useSuccessorMarketIdsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useSuccessorMarketIdsQuery({
* variables: {
* },
* });
*/
export function useSuccessorMarketIdsQuery(baseOptions?: Apollo.QueryHookOptions<SuccessorMarketIdsQuery, SuccessorMarketIdsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<SuccessorMarketIdsQuery, SuccessorMarketIdsQueryVariables>(SuccessorMarketIdsDocument, options);
}
export function useSuccessorMarketIdsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<SuccessorMarketIdsQuery, SuccessorMarketIdsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<SuccessorMarketIdsQuery, SuccessorMarketIdsQueryVariables>(SuccessorMarketIdsDocument, options);
}
export type SuccessorMarketIdsQueryHookResult = ReturnType<typeof useSuccessorMarketIdsQuery>;
export type SuccessorMarketIdsLazyQueryHookResult = ReturnType<typeof useSuccessorMarketIdsLazyQuery>;
export type SuccessorMarketIdsQueryResult = Apollo.QueryResult<SuccessorMarketIdsQuery, SuccessorMarketIdsQueryVariables>;
export const SuccessorMarketDocument = gql`
query SuccessorMarket($marketId: ID!) {
market(id: $marketId) {
id
state
tradingMode
positionDecimalPlaces
tradableInstrument {
instrument {
name
code
}
}
}
}
`;
/**
* __useSuccessorMarketQuery__
*
* To run a query within a React component, call `useSuccessorMarketQuery` and pass it any options that fit your needs.
* When your component renders, `useSuccessorMarketQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useSuccessorMarketQuery({
* variables: {
* marketId: // value for 'marketId'
* },
* });
*/
export function useSuccessorMarketQuery(baseOptions: Apollo.QueryHookOptions<SuccessorMarketQuery, SuccessorMarketQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<SuccessorMarketQuery, SuccessorMarketQueryVariables>(SuccessorMarketDocument, options);
}
export function useSuccessorMarketLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<SuccessorMarketQuery, SuccessorMarketQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<SuccessorMarketQuery, SuccessorMarketQueryVariables>(SuccessorMarketDocument, options);
}
export type SuccessorMarketQueryHookResult = ReturnType<typeof useSuccessorMarketQuery>;
export type SuccessorMarketLazyQueryHookResult = ReturnType<typeof useSuccessorMarketLazyQuery>;
export type SuccessorMarketQueryResult = Apollo.QueryResult<SuccessorMarketQuery, SuccessorMarketQueryVariables>;

View File

@ -5,3 +5,4 @@ export * from './markets-candles';
export * from './markets-data';
export * from './OracleMarketsSpec';
export * from './OracleSpecDataConnection';
export * from './SuccessorMarket'

View File

@ -7,12 +7,12 @@ export type DataSourceFilterFragment = { __typename?: 'Filter', key: { __typenam
export type DataSourceSpecFragment = { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } };
export type MarketFieldsFragment = { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, successorMarketID?: string | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number, quantum: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } };
export type MarketFieldsFragment = { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number, quantum: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } };
export type MarketsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type MarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, successorMarketID?: string | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number, quantum: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } } }> } | null };
export type MarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number, quantum: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } } }> } | null };
export const DataSourceFilterFragmentDoc = gql`
fragment DataSourceFilter on Filter {
@ -104,7 +104,6 @@ export const MarketFieldsFragmentDoc = gql`
open
close
}
successorMarketID
}
${DataSourceSpecFragmentDoc}`;
export const MarketsDocument = gql`

View File

@ -152,6 +152,5 @@ query MarketInfo($marketId: ID!) {
}
}
}
parentMarketID
}
}

View File

@ -10,7 +10,7 @@ export type MarketInfoQueryVariables = Types.Exact<{
}>;
export type MarketInfoQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, lpPriceRange: string, parentMarketID?: string | null, proposal?: { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any }, openingAuction: { __typename?: 'AuctionDuration', durationSecs: number, volume: number }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string } } } | null> | null } | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, priceMonitoringSettings: { __typename?: 'PriceMonitoringSettings', parameters?: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null } | null }, riskFactors?: { __typename?: 'RiskFactor', market: string, short: string, long: string } | null, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } } } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } }, riskModel: { __typename?: 'LogNormalRiskModel', tau: number, riskAversionParameter: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, marginCalculator?: { __typename?: 'MarginCalculator', scalingFactors: { __typename?: 'ScalingFactors', searchLevel: number, initialMargin: number, collateralRelease: number } } | null } } | null };
export type MarketInfoQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, lpPriceRange: string, proposal?: { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any }, openingAuction: { __typename?: 'AuctionDuration', durationSecs: number, volume: number }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string } } } | null> | null } | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, priceMonitoringSettings: { __typename?: 'PriceMonitoringSettings', parameters?: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null } | null }, riskFactors?: { __typename?: 'RiskFactor', market: string, short: string, long: string } | null, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } } } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } }, riskModel: { __typename?: 'LogNormalRiskModel', tau: number, riskAversionParameter: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, marginCalculator?: { __typename?: 'MarginCalculator', scalingFactors: { __typename?: 'ScalingFactors', searchLevel: number, initialMargin: number, collateralRelease: number } } | null } } | null };
export const DataSourceFragmentDoc = gql`
fragment DataSource on DataSourceDefinition {

View File

@ -23,12 +23,13 @@ import BigNumber from 'bignumber.js';
import type { DataSourceDefinition, SignerKind } from '@vegaprotocol/types';
import { ConditionOperatorMapping } from '@vegaprotocol/types';
import { MarketTradingModeMapping } from '@vegaprotocol/types';
import { useEnvironment } from '@vegaprotocol/environment';
import { FLAGS, useEnvironment } from '@vegaprotocol/environment';
import type { Provider } from '../../oracle-schema';
import { OracleBasicProfile } from '../../components/oracle-basic-profile';
import { useOracleProofs } from '../../hooks';
import { OracleDialog } from '../oracle-dialog/oracle-dialog';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { useParentMarketIdQuery } from '../../__generated__';
type MarketInfoProps = {
market: MarketInfo;
@ -137,20 +138,41 @@ export const InsurancePoolInfoPanel = ({
};
export const KeyDetailsInfoPanel = ({ market }: MarketInfoProps) => {
const { data: parentData } = useParentMarketIdQuery({
variables: {
marketId: market.id,
},
skip: !FLAGS.SUCCESSOR_MARKETS,
});
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
return (
<MarketInfoTable
data={{
name: market.tradableInstrument.instrument.name,
marketID: market.id,
parentMarketID: market.parentMarketID,
tradingMode:
market.tradingMode && MarketTradingModeMapping[market.tradingMode],
marketDecimalPlaces: market.decimalPlaces,
positionDecimalPlaces: market.positionDecimalPlaces,
settlementAssetDecimalPlaces: assetDecimals,
}}
data={
FLAGS.SUCCESSOR_MARKETS
? {
name: market.tradableInstrument.instrument.name,
marketID: market.id,
parentMarketID: parentData?.market?.parentMarketID || '-',
tradingMode:
market.tradingMode &&
MarketTradingModeMapping[market.tradingMode],
marketDecimalPlaces: market.decimalPlaces,
positionDecimalPlaces: market.positionDecimalPlaces,
settlementAssetDecimalPlaces: assetDecimals,
}
: {
name: market.tradableInstrument.instrument.name,
marketID: market.id,
tradingMode:
market.tradingMode &&
MarketTradingModeMapping[market.tradingMode],
marketDecimalPlaces: market.decimalPlaces,
positionDecimalPlaces: market.positionDecimalPlaces,
settlementAssetDecimalPlaces: assetDecimals,
}
}
/>
);
};

View File

@ -191,7 +191,6 @@ export const marketInfoQuery = (
},
},
},
parentMarketID: 'market-1',
},
};

View File

@ -3,3 +3,4 @@ export * from './use-oracle-markets';
export * from './use-oracle-proofs';
export * from './use-oracle-spec-binding-data';
export * from './use-candles';
export * from './use-successor-market';

View File

@ -0,0 +1,30 @@
import {
useSuccessorMarketIdQuery,
useSuccessorMarketQuery,
} from '../__generated__';
export const useSuccessorMarket = (marketId?: string) => {
const {
data: idData,
loading: idLoading,
error: idError,
} = useSuccessorMarketIdQuery({
variables: {
marketId: marketId || '',
},
skip: !marketId,
});
const successorMarketId = idData?.market?.successorMarketID;
const { data, loading, error } = useSuccessorMarketQuery({
variables: {
marketId: successorMarketId || '',
},
skip: !successorMarketId,
});
const successorData = data?.market;
return {
data: successorData,
loading: loading || idLoading,
error: error || idError,
};
};

View File

@ -85,7 +85,6 @@ fragment MarketFields on Market {
open
close
}
successorMarketID
}
query Markets {

View File

@ -5,6 +5,12 @@ import type {
MarketFieldsFragment,
MarketsQuery,
} from './__generated__/markets';
import type {
ParentMarketIdQuery,
SuccessorMarketIdQuery,
SuccessorMarketIdsQuery,
SuccessorMarketQuery,
} from './__generated__';
export const marketsQuery = (
override?: PartialDeep<MarketsQuery>
@ -141,7 +147,6 @@ export const createMarketFragment = (
},
__typename: 'TradableInstrument',
},
successorMarketID: null,
__typename: 'Market',
};
@ -230,3 +235,76 @@ const marketFieldsFragments: MarketFieldsFragment[] = [
},
}),
];
export const successorMarketIdQuery = (
override?: Partial<SuccessorMarketIdQuery>
) => {
const res: SuccessorMarketIdQuery = {
__typename: 'Query',
market: {
__typename: 'Market',
successorMarketID: 'SUCCESSOR-A',
},
};
return merge(res, override);
};
export const parentMarketIdQuery = (
override?: Partial<ParentMarketIdQuery>
) => {
const res: ParentMarketIdQuery = {
__typename: 'Query',
market: {
__typename: 'Market',
parentMarketID: 'PARENT-A',
},
};
return merge(res, override);
};
export const successorMarketIdsQuery = (
override?: Partial<SuccessorMarketIdsQuery>
) => {
const res: SuccessorMarketIdsQuery = {
__typename: 'Query',
marketsConnection: {
__typename: 'MarketConnection',
edges: [
{
__typename: 'MarketEdge',
node: {
__typename: 'Market',
id: 'PARENT-A',
successorMarketID: 'SUCCESSOR-A',
},
},
],
},
};
return merge(res, override);
};
export const successorMarketQuery = (
override?: Partial<SuccessorMarketQuery>
) => {
const res: SuccessorMarketQuery = {
__typename: 'Query',
market: {
__typename: 'Market',
id: 'SUCCESSOR-A',
positionDecimalPlaces: 2,
state: Schema.MarketState.STATE_ACTIVE,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
code: 'SUCCESSOR-A',
name: 'Successor Market A',
},
},
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
},
};
return merge(res, override);
};