Compare commits

...
Author SHA1 Message Date
Daniel cb7c4a7b5e feat(ci): fix condition for tools define-dist-variables (#5542) 2023-12-22 17:27:10 +00:00
Daniel 9fd945dc17 feat(ci): allow both validators-testnet and validator-testnet for env name (#5540) 2023-12-22 17:07:53 +00:00
Jeremy Letang 9fbb7a13e6 Merge pull request #5526 from vegaprotocol/5409-funding-countdown
feat(trading): poll market info, and last fundingPeriod
2023-12-22 15:21:40 +01:00
Dariusz Majcherczyk 1874095222 feat: skip test 2023-12-22 14:36:38 +01:00
Dariusz Majcherczyk e459e92127 feat: update sim version 2023-12-22 13:58:20 +01:00
Bartłomiej Głownia 4dd65b4923 feat: rollback using market.data as a source of current fundingPeriod startTime 2023-12-22 12:01:32 +01:00
Bartłomiej Głownia 5d792d2458 feat: pool market info, use market data as source of current funding period startTime 2023-12-21 16:42:25 +00:00
Ben 59b2f75b13 chore(trading): update market-sim (#5535) 2023-12-21 13:51:34 +00:00
ArtandMatthew Russell 95775679ca fix(trading): reward pot total value (#5531)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-12-21 13:41:37 +00:00
m.ray 4cffee29f8 chore(trading): rollback current traded volume change (#5527) 2023-12-21 10:38:09 +00:00
Edd bd70b0c233 fix(governance): fix lp vote counts (#5521) 2023-12-21 09:30:23 +00:00
Ben 145792f216 chore(trading): static vega port trading e2e (#5520) 2023-12-20 15:49:10 +00:00
m.ray 10add7c236 fix(trading): update copy on tooltips fills update (#5512) 2023-12-20 08:12:35 +00:00
Edd 362a2031c7 fix(explorer): pass through tendermint error responses from usefetch (#5507) 2023-12-20 08:08:56 +00:00
Edd 5aaeb87059 feat(governance): enable snaps (#5511) 2023-12-19 18:38:49 +00:00
Matthew Russell d240dddab5 fix(trading): alpha lyrae font (#5518) 2023-12-19 16:52:56 +00:00
Ben 0af1d0ba82 chore(trading): fees e2e tests (#5496) 2023-12-19 12:22:15 +00:00
Bartłomiej Głownia 665ab6693a feat(trading): show commission earned on referrer stats from last 30 days (#5467) 2023-12-18 15:33:40 +01:00
Ben 902ee2696c chore(trading): black formatting and removed double fixtures (#5506) 2023-12-18 10:54:40 +00:00
Art 3beeb0140c feat(wallet): disconnect if wallet unreachable (#5501) 2023-12-18 10:39:18 +00:00
m.ray 4b208e90bf fix(trading): internal timestamp date unix formatting (#5505) 2023-12-14 15:10:17 +00:00
Bartłomiej Głownia ec837854cf chore(trading): avoid portfolio and market page re-rendering on sidebar view change (#5499) 2023-12-14 14:12:19 +00:00
Bartłomiej Głownia 8b94a75ba4 feat(positions): improve tooltips (#5481) 2023-12-13 14:36:57 +00:00
Ben 08c57b6759 chore(trading): run against local console (#5500) 2023-12-13 12:46:16 +00:00
Ben bb2184498f chore(trading): update vega version (#5498) 2023-12-13 11:16:52 +00:00
Bartłomiej Głownia 8b07ce3024 fix(trading): fix tabs covered by orderbook splash (#5497) 2023-12-13 09:10:54 +00:00
Bartłomiej Głownia 8a110584dd feat(trading): improve desposit and withraw asset selection (#5493) 2023-12-13 08:47:22 +00:00
Bartłomiej Głownia b82615a3d8 fix(trading): do not add candles if they are older than requested date range (#5484) 2023-12-13 08:06:02 +00:00
Matthew Russell f178b85846 feat(trading): trading view (#5348) 2023-12-12 17:33:41 -08:00
Bartłomiej Głownia 0796f2b31f feat(environment): users controlled feature flags (#5425) 2023-12-12 13:53:20 +01:00
dalebennett1992 67be224138 Merge pull request #5492 from vegaprotocol/test/referrals2
test: add referrals tests
2023-12-12 10:33:57 +00:00
188 changed files with 4871 additions and 1853 deletions
+1
View File
@@ -1,3 +1,4 @@
* text eol=lf * text eol=lf
*.png binary *.png binary
*.ico binary *.ico binary
*.woff2 binary
+6 -2
View File
@@ -12,7 +12,8 @@ import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-web
import { Loader, Splash } from '@vegaprotocol/ui-toolkit'; import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client'; import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
import { RouterProvider } from 'react-router-dom'; import { RouterProvider } from 'react-router-dom';
import { router } from './routes/router-config'; import { useRouterConfig } from './routes/router-config';
import { createBrowserRouter } from 'react-router-dom';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { Suspense } from 'react'; import { Suspense } from 'react';
@@ -38,7 +39,10 @@ function App() {
} }
> >
<Suspense fallback={splashLoading}> <Suspense fallback={splashLoading}>
<RouterProvider router={router} fallbackElement={splashLoading} /> <RouterProvider
router={createBrowserRouter(useRouterConfig())}
fallbackElement={splashLoading}
/>
</Suspense> </Suspense>
</NodeGuard> </NodeGuard>
<NodeSwitcherDialog <NodeSwitcherDialog
@@ -14,7 +14,7 @@ import { Routes } from '../../routes/route-names';
import { NetworkSwitcher } from '@vegaprotocol/environment'; import { NetworkSwitcher } from '@vegaprotocol/environment';
import type { Navigable } from '../../routes/router-config'; import type { Navigable } from '../../routes/router-config';
import { isNavigable } from '../../routes/router-config'; import { isNavigable } from '../../routes/router-config';
import { routerConfig } from '../../routes/router-config'; import { useRouterConfig } from '../../routes/router-config';
import { useMemo } from 'react'; import { useMemo } from 'react';
import compact from 'lodash/compact'; import compact from 'lodash/compact';
import { Search } from '../search'; import { Search } from '../search';
@@ -26,6 +26,7 @@ const routeToNavigationItem = (r: Navigable) => (
); );
export const Header = () => { export const Header = () => {
const routerConfig = useRouterConfig();
const isHome = Boolean(useMatch(Routes.HOME)); const isHome = Boolean(useMatch(Routes.HOME));
const pages = routerConfig[0].children || []; const pages = routerConfig[0].children || [];
const mainItems = compact( const mainItems = compact(
@@ -54,7 +54,7 @@ const Block = () => {
</Button> </Button>
</Link> </Link>
</div> </div>
{blockData && ( {blockData && 'result' in blockData && (
<> <>
<TableWithTbody className="mb-8"> <TableWithTbody className="mb-8">
<TableRow modifier="bordered"> <TableRow modifier="bordered">
+292 -289
View File
@@ -18,7 +18,6 @@ import { t } from '@vegaprotocol/i18n';
import { Routes } from './route-names'; import { Routes } from './route-names';
import { NetworkParameters } from './network-parameters'; import { NetworkParameters } from './network-parameters';
import type { Params, RouteObject } from 'react-router-dom'; import type { Params, RouteObject } from 'react-router-dom';
import { createBrowserRouter } from 'react-router-dom';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { MarketPage, MarketsPage } from './markets'; import { MarketPage, MarketsPage } from './markets';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
@@ -29,7 +28,7 @@ import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
import { remove0x } from '@vegaprotocol/utils'; import { remove0x } from '@vegaprotocol/utils';
import { PartyAccountsByAsset } from './parties/id/accounts'; import { PartyAccountsByAsset } from './parties/id/accounts';
import { Disclaimer } from './pages/disclaimer'; import { Disclaimer } from './pages/disclaimer';
import { FLAGS } from '@vegaprotocol/environment'; import { useFeatureFlags } from '@vegaprotocol/environment';
import RestrictedPage from './restricted'; import RestrictedPage from './restricted';
export type Navigable = { export type Navigable = {
@@ -60,311 +59,315 @@ type Route = RouteItem & {
children?: RouteItem[]; children?: RouteItem[];
}; };
const partiesRoutes: Route[] = FLAGS.EXPLORER_PARTIES export const useRouterConfig = () => {
? [ const featureFlags = useFeatureFlags((state) => state.flags);
{
path: Routes.PARTIES,
element: <Party />,
handle: {
name: t('Parties'),
text: t('Parties'),
breadcrumb: () => <Link to={Routes.PARTIES}>{t('Parties')}</Link>,
},
children: [
{
index: true,
element: <Parties />,
},
{
path: ':party',
element: <Party />,
children: [ const partiesRoutes: Route[] = featureFlags.EXPLORER_PARTIES
{ ? [
index: true, {
element: <PartySingle />, path: Routes.PARTIES,
handle: { element: <Party />,
breadcrumb: (params: Params<string>) => ( handle: {
<Link to={linkTo(Routes.PARTIES, params.party)}> name: t('Parties'),
{truncateMiddle(params.party as string)} text: t('Parties'),
</Link> breadcrumb: () => <Link to={Routes.PARTIES}>{t('Parties')}</Link>,
), },
children: [
{
index: true,
element: <Parties />,
},
{
path: ':party',
element: <Party />,
children: [
{
index: true,
element: <PartySingle />,
handle: {
breadcrumb: (params: Params<string>) => (
<Link to={linkTo(Routes.PARTIES, params.party)}>
{truncateMiddle(params.party as string)}
</Link>
),
},
}, },
}, {
{ path: 'assets',
path: 'assets', element: <Party />,
element: <Party />, handle: {
handle: { breadcrumb: (params: Params<string>) => (
breadcrumb: (params: Params<string>) => ( <Link to={linkTo(Routes.PARTIES, params.party)}>
<Link to={linkTo(Routes.PARTIES, params.party)}> {truncateMiddle(params.party as string)}
{truncateMiddle(params.party as string)} </Link>
</Link> ),
), },
}, children: [
children: [ {
{ index: true,
index: true, element: <PartyAccountsByAsset />,
element: <PartyAccountsByAsset />, handle: {
handle: { breadcrumb: () => {
breadcrumb: () => { return t('Assets');
return t('Assets'); },
}, },
}, },
}, ],
], },
],
},
],
},
]
: [];
const assetsRoutes: Route[] = featureFlags.EXPLORER_ASSETS
? [
{
path: Routes.ASSETS,
handle: {
name: t('Assets'),
text: t('Assets'),
breadcrumb: () => <Link to={Routes.ASSETS}>{t('Assets')}</Link>,
},
children: [
{
index: true,
element: <AssetsPage />,
},
{
path: ':assetId',
element: <AssetPage />,
handle: {
breadcrumb: (params: Params<string>) => (
<AssetLink assetId={params.assetId as string} />
),
}, },
], },
}, ],
],
},
]
: [];
const assetsRoutes: Route[] = FLAGS.EXPLORER_ASSETS
? [
{
path: Routes.ASSETS,
handle: {
name: t('Assets'),
text: t('Assets'),
breadcrumb: () => <Link to={Routes.ASSETS}>{t('Assets')}</Link>,
}, },
children: [ ]
{ : [];
index: true,
element: <AssetsPage />, const genesisRoutes: Route[] = featureFlags.EXPLORER_GENESIS
? [
{
path: Routes.GENESIS,
handle: {
name: t('Genesis'),
text: t('Genesis Parameters'),
breadcrumb: () => (
<Link to={Routes.GENESIS}>{t('Genesis Parameters')}</Link>
),
}, },
element: <Genesis />,
},
]
: [];
const governanceRoutes: Route[] = featureFlags.EXPLORER_GOVERNANCE
? [
{
path: Routes.GOVERNANCE,
handle: {
name: t('Governance proposals'),
text: t('Governance Proposals'),
breadcrumb: () => (
<Link to={Routes.GOVERNANCE}>{t('Governance Proposals')}</Link>
),
},
element: <Proposals />,
},
]
: [];
const marketsRoutes: Route[] = featureFlags.EXPLORER_MARKETS
? [
{
path: Routes.MARKETS,
handle: {
name: t('Markets'),
text: t('Markets'),
breadcrumb: () => <Link to={Routes.MARKETS}>{t('Markets')}</Link>,
},
children: [
{
index: true,
element: <MarketsPage />,
},
{
path: ':marketId',
element: <MarketPage />,
handle: {
breadcrumb: (params: Params<string>) => (
<MarketLink id={params.marketId as string} />
),
},
},
],
},
]
: [];
const networkParametersRoutes: Route[] =
featureFlags.EXPLORER_NETWORK_PARAMETERS
? [
{ {
path: ':assetId', path: Routes.NETWORK_PARAMETERS,
element: <AssetPage />,
handle: { handle: {
breadcrumb: (params: Params<string>) => ( name: t('NetworkParameters'),
<AssetLink assetId={params.assetId as string} /> text: t('Network Parameters'),
breadcrumb: () => (
<Link to={Routes.NETWORK_PARAMETERS}>
{t('Network Parameters')}
</Link>
), ),
}, },
element: <NetworkParameters />,
}, },
], ]
}, : [];
]
: [];
const genesisRoutes: Route[] = FLAGS.EXPLORER_GENESIS const validators: Route[] = featureFlags.EXPLORER_VALIDATORS
? [ ? [
{ {
path: Routes.GENESIS, path: Routes.VALIDATORS,
handle: { handle: {
name: t('Genesis'), name: t('Validators'),
text: t('Genesis Parameters'), text: t('Validators'),
breadcrumb: () => ( breadcrumb: () => (
<Link to={Routes.GENESIS}>{t('Genesis Parameters')}</Link> <Link to={Routes.VALIDATORS}>{t('Validators')}</Link>
), ),
},
element: <Genesis />,
},
]
: [];
const governanceRoutes: Route[] = FLAGS.EXPLORER_GOVERNANCE
? [
{
path: Routes.GOVERNANCE,
handle: {
name: t('Governance proposals'),
text: t('Governance Proposals'),
breadcrumb: () => (
<Link to={Routes.GOVERNANCE}>{t('Governance Proposals')}</Link>
),
},
element: <Proposals />,
},
]
: [];
const marketsRoutes: Route[] = FLAGS.EXPLORER_MARKETS
? [
{
path: Routes.MARKETS,
handle: {
name: t('Markets'),
text: t('Markets'),
breadcrumb: () => <Link to={Routes.MARKETS}>{t('Markets')}</Link>,
},
children: [
{
index: true,
element: <MarketsPage />,
}, },
{ element: <ValidatorsPage />,
path: ':marketId', },
element: <MarketPage />, ]
handle: { : [];
breadcrumb: (params: Params<string>) => (
<MarketLink id={params.marketId as string} /> const linkTo = (...segments: (string | undefined)[]) =>
), compact(segments).join('/');
const routerConfig: Route[] = [
{
path: Routes.HOME,
element: <Layout />,
handle: {
name: t('Home'),
text: t('Home'),
breadcrumb: () => <Link to={Routes.HOME}>{t('Home')}</Link>,
},
errorElement: <ErrorBoundary />,
children: [
{
index: true,
element: <Home />,
},
{
path: Routes.TX,
handle: {
name: t('Txs'),
text: t('Transactions'),
breadcrumb: () => <Link to={Routes.TX}>{t('Transactions')}</Link>,
},
children: [
{
path: ':txHash',
element: <Tx />,
handle: {
breadcrumb: (params: Params<string>) => (
<Link to={linkTo(Routes.TX, params.txHash)}>
{truncateMiddle(remove0x(params.txHash as string))}
</Link>
),
},
}, },
{
index: true,
element: <TxsList />,
},
],
},
{
path: Routes.BLOCKS,
handle: {
name: t('Blocks'),
text: t('Blocks'),
breadcrumb: () => <Link to={Routes.BLOCKS}>{t('Blocks')}</Link>,
}, },
], element: <BlockPage />,
}, children: [
] {
: []; index: true,
element: <Blocks />,
const networkParametersRoutes: Route[] = FLAGS.EXPLORER_NETWORK_PARAMETERS },
? [ {
{ path: ':block',
path: Routes.NETWORK_PARAMETERS, element: <Block />,
handle: { handle: {
name: t('NetworkParameters'), breadcrumb: (params: Params<string>) => (
text: t('Network Parameters'), <Link to={linkTo(Routes.BLOCKS, params.block)}>
breadcrumb: () => ( {params.block}
<Link to={Routes.NETWORK_PARAMETERS}> </Link>
{t('Network Parameters')} ),
</Link> },
), },
],
}, },
element: <NetworkParameters />, {
}, path: Routes.ORACLES,
] handle: {
: []; name: t('Oracles'),
text: t('Oracles'),
const validators: Route[] = FLAGS.EXPLORER_VALIDATORS breadcrumb: () => <Link to={Routes.ORACLES}>{t('Oracles')}</Link>,
? [ },
{ element: <OraclePage />,
path: Routes.VALIDATORS, children: [
handle: { {
name: t('Validators'), index: true,
text: t('Validators'), element: <Oracles />,
breadcrumb: () => ( },
<Link to={Routes.VALIDATORS}>{t('Validators')}</Link> {
), path: ':id',
element: <Oracle />,
handle: {
breadcrumb: (params: Params<string>) => (
<Link to={linkTo(Routes.ORACLES, params.id)}>
{truncateMiddle(params.id as string)}
</Link>
),
},
},
],
}, },
element: <ValidatorsPage />, {
}, path: Routes.DISCLAIMER,
] element: <Disclaimer />,
: []; handle: {
name: t('Disclaimer'),
const linkTo = (...segments: (string | undefined)[]) => text: t('Disclaimer'),
compact(segments).join('/'); breadcrumb: () => (
<Link to={Routes.DISCLAIMER}>{t('Disclaimer')}</Link>
export const routerConfig: Route[] = [ ),
{ },
path: Routes.HOME, },
element: <Layout />, ...partiesRoutes,
handle: { ...assetsRoutes,
name: t('Home'), ...genesisRoutes,
text: t('Home'), ...governanceRoutes,
breadcrumb: () => <Link to={Routes.HOME}>{t('Home')}</Link>, ...marketsRoutes,
...networkParametersRoutes,
...validators,
],
}, },
errorElement: <ErrorBoundary />, {
children: [ path: Routes.RESTRICTED,
{ element: <RestrictedPage />,
index: true, handle: {
element: <Home />, name: t('Restricted'),
text: t('Restricted'),
}, },
{
path: Routes.TX,
handle: {
name: t('Txs'),
text: t('Transactions'),
breadcrumb: () => <Link to={Routes.TX}>{t('Transactions')}</Link>,
},
children: [
{
path: ':txHash',
element: <Tx />,
handle: {
breadcrumb: (params: Params<string>) => (
<Link to={linkTo(Routes.TX, params.txHash)}>
{truncateMiddle(remove0x(params.txHash as string))}
</Link>
),
},
},
{
index: true,
element: <TxsList />,
},
],
},
{
path: Routes.BLOCKS,
handle: {
name: t('Blocks'),
text: t('Blocks'),
breadcrumb: () => <Link to={Routes.BLOCKS}>{t('Blocks')}</Link>,
},
element: <BlockPage />,
children: [
{
index: true,
element: <Blocks />,
},
{
path: ':block',
element: <Block />,
handle: {
breadcrumb: (params: Params<string>) => (
<Link to={linkTo(Routes.BLOCKS, params.block)}>
{params.block}
</Link>
),
},
},
],
},
{
path: Routes.ORACLES,
handle: {
name: t('Oracles'),
text: t('Oracles'),
breadcrumb: () => <Link to={Routes.ORACLES}>{t('Oracles')}</Link>,
},
element: <OraclePage />,
children: [
{
index: true,
element: <Oracles />,
},
{
path: ':id',
element: <Oracle />,
handle: {
breadcrumb: (params: Params<string>) => (
<Link to={linkTo(Routes.ORACLES, params.id)}>
{truncateMiddle(params.id as string)}
</Link>
),
},
},
],
},
{
path: Routes.DISCLAIMER,
element: <Disclaimer />,
handle: {
name: t('Disclaimer'),
text: t('Disclaimer'),
breadcrumb: () => (
<Link to={Routes.DISCLAIMER}>{t('Disclaimer')}</Link>
),
},
},
...partiesRoutes,
...assetsRoutes,
...genesisRoutes,
...governanceRoutes,
...marketsRoutes,
...networkParametersRoutes,
...validators,
],
},
{
path: Routes.RESTRICTED,
element: <RestrictedPage />,
handle: {
name: t('Restricted'),
text: t('Restricted'),
}, },
}, ];
]; return routerConfig;
};
export const router = createBrowserRouter(routerConfig);
+1 -1
View File
@@ -32,7 +32,7 @@ CYPRESS_FAIRGROUND=false
# Cosmic elevator flags # Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true NX_SUCCESSOR_MARKETS=true
NX_METAMASK_SNAPS=false NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=true NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true NX_REFERRALS=true
+1 -1
View File
@@ -23,7 +23,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
# Cosmic elevator flags # Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true NX_SUCCESSOR_MARKETS=true
NX_METAMASK_SNAPS=false NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=true NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true NX_REFERRALS=true
+1 -1
View File
@@ -22,7 +22,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
# Cosmic elevator flags # Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true NX_SUCCESSOR_MARKETS=true
NX_METAMASK_SNAPS=false NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=true NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true NX_REFERRALS=true
+1 -1
View File
@@ -21,7 +21,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.
# Cosmic elevator flags # Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true NX_SUCCESSOR_MARKETS=true
NX_METAMASK_SNAPS=false NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=true NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true NX_REFERRALS=true
+17 -9
View File
@@ -2,7 +2,7 @@ import * as Sentry from '@sentry/react';
import { toBigNum } from '@vegaprotocol/utils'; import { toBigNum } from '@vegaprotocol/utils';
import { Splash } from '@vegaprotocol/ui-toolkit'; import { Splash } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet, useEagerConnect } from '@vegaprotocol/wallet'; import { useVegaWallet, useEagerConnect } from '@vegaprotocol/wallet';
import { FLAGS, useEnvironment } from '@vegaprotocol/environment'; import { useFeatureFlags, useEnvironment } from '@vegaprotocol/environment';
import { useWeb3React } from '@web3-react/core'; import { useWeb3React } from '@web3-react/core';
import React, { Suspense } from 'react'; import React, { Suspense } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@@ -15,21 +15,23 @@ import {
} from './contexts/app-state/app-state-context'; } from './contexts/app-state/app-state-context';
import { useContracts } from './contexts/contracts/contracts-context'; import { useContracts } from './contexts/contracts/contracts-context';
import { useRefreshAssociatedBalances } from './hooks/use-refresh-associated-balances'; import { useRefreshAssociatedBalances } from './hooks/use-refresh-associated-balances';
import { Connectors } from './lib/vega-connectors'; import { useConnectors } from './lib/vega-connectors';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
const useVegaWalletEagerConnect = () => { const useVegaWalletEagerConnect = () => {
const vegaConnecting = useEagerConnect(Connectors); const connectors = useConnectors();
const vegaConnecting = useEagerConnect(connectors);
const { pubKey, connect } = useVegaWallet(); const { pubKey, connect } = useVegaWallet();
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const [query] = React.useState(searchParams.get('address')); const [query] = React.useState(searchParams.get('address'));
if (query && !pubKey) { if (query && !pubKey) {
connect(Connectors['view']); connect(connectors.view);
} }
return vegaConnecting; return vegaConnecting;
}; };
export const AppLoader = ({ children }: { children: React.ReactElement }) => { export const AppLoader = ({ children }: { children: React.ReactElement }) => {
const featureFlags = useFeatureFlags((state) => state.flags);
const { t } = useTranslation(); const { t } = useTranslation();
const { account } = useWeb3React(); const { account } = useWeb3React();
const { VEGA_URL } = useEnvironment(); const { VEGA_URL } = useEnvironment();
@@ -79,10 +81,16 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
} }
}; };
if (!FLAGS.GOVERNANCE_NETWORK_DOWN) { if (!featureFlags.GOVERNANCE_NETWORK_DOWN) {
run(); run();
} }
}, [token, appDispatch, staking, vesting]); }, [
token,
appDispatch,
staking,
vesting,
featureFlags.GOVERNANCE_NETWORK_DOWN,
]);
React.useEffect(() => { React.useEffect(() => {
if (account && pubKey) { if (account && pubKey) {
@@ -147,16 +155,16 @@ 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 // Only begin polling if network limits flag is set, as this is a new API not yet on mainnet 7/3/22
if (FLAGS.GOVERNANCE_NETWORK_LIMITS) { if (featureFlags.GOVERNANCE_NETWORK_LIMITS) {
getNetworkLimits(); getNetworkLimits();
} }
return () => { return () => {
stopPoll(); stopPoll();
}; };
}, [appDispatch, VEGA_URL, t]); }, [appDispatch, VEGA_URL, t, featureFlags.GOVERNANCE_NETWORK_LIMITS]);
if (FLAGS.GOVERNANCE_NETWORK_DOWN) { if (featureFlags.GOVERNANCE_NETWORK_DOWN) {
return ( return (
<Splash> <Splash>
<SplashError /> <SplashError />
@@ -7,16 +7,16 @@ import {
AppStateActionType, AppStateActionType,
useAppState, useAppState,
} from '../../contexts/app-state/app-state-context'; } from '../../contexts/app-state/app-state-context';
import { Connectors } from '../../lib/vega-connectors'; import { useConnectors } from '../../lib/vega-connectors';
import { RiskMessage } from './risk-message'; import { RiskMessage } from './risk-message';
export const VegaWalletDialogs = () => { export const VegaWalletDialogs = () => {
const { appState, appDispatch } = useAppState(); const { appState, appDispatch } = useAppState();
const connectors = useConnectors();
return ( return (
<> <>
<VegaConnectDialog <VegaConnectDialog
connectors={Connectors} connectors={connectors}
riskMessage={<RiskMessage />} riskMessage={<RiskMessage />}
/> />
@@ -30,7 +30,7 @@ export const VegaWalletDialogs = () => {
} }
/> />
<ViewAsDialog connector={Connectors.view} /> <ViewAsDialog connector={connectors.view} />
</> </>
); );
}; };
+14 -9
View File
@@ -1,4 +1,5 @@
import { FLAGS } from '@vegaprotocol/environment'; import { useFeatureFlags } from '@vegaprotocol/environment';
import { useMemo } from 'react';
import { import {
JsonRpcConnector, JsonRpcConnector,
ViewConnector, ViewConnector,
@@ -13,13 +14,17 @@ export const jsonRpc = new JsonRpcConnector();
export const injected = new InjectedConnector(); export const injected = new InjectedConnector();
export const view = new ViewConnector(urlParams.get('address')); export const view = new ViewConnector(urlParams.get('address'));
export const snap = FLAGS.METAMASK_SNAPS export const snap = new SnapConnector(DEFAULT_SNAP_ID);
? new SnapConnector(DEFAULT_SNAP_ID)
: undefined;
export const Connectors = { export const useConnectors = () => {
injected, const featureFlags = useFeatureFlags((state) => state.flags);
jsonRpc, return useMemo(
view, () => ({
snap, injected,
jsonRpc,
view,
snap: featureFlags.METAMASK_SNAPS ? snap : undefined,
}),
[featureFlags.METAMASK_SNAPS]
);
}; };
+5 -4
View File
@@ -12,7 +12,7 @@ import { useRefreshAfterEpoch } from '../../hooks/use-refresh-after-epoch';
import { ProposalsListItem } from '../proposals/components/proposals-list-item'; import { ProposalsListItem } from '../proposals/components/proposals-list-item';
import { ProtocolUpgradeProposalsListItem } from '../proposals/components/protocol-upgrade-proposals-list-item/protocol-upgrade-proposals-list-item'; import { ProtocolUpgradeProposalsListItem } from '../proposals/components/protocol-upgrade-proposals-list-item/protocol-upgrade-proposals-list-item';
import Routes from '../routes'; import Routes from '../routes';
import { ExternalLinks, FLAGS } from '@vegaprotocol/environment'; import { ExternalLinks, useFeatureFlags } from '@vegaprotocol/environment';
import { removePaginationWrapper } from '@vegaprotocol/utils'; import { removePaginationWrapper } from '@vegaprotocol/utils';
import { useNodesQuery } from '../staking/home/__generated__/Nodes'; import { useNodesQuery } from '../staking/home/__generated__/Nodes';
import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals'; import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals';
@@ -175,6 +175,7 @@ export const ValidatorDetailsLink = ({
}; };
const GovernanceHome = ({ name }: RouteChildProps) => { const GovernanceHome = ({ name }: RouteChildProps) => {
const featureFlags = useFeatureFlags((state) => state.flags);
useDocumentTitle(name); useDocumentTitle(name);
const { t } = useTranslation(); const { t } = useTranslation();
const { const {
@@ -186,9 +187,9 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
fetchPolicy: 'network-only', fetchPolicy: 'network-only',
errorPolicy: 'ignore', errorPolicy: 'ignore',
variables: { variables: {
includeNewMarketProductFields: !!FLAGS.PRODUCT_PERPETUALS, includeNewMarketProductFields: !!featureFlags.PRODUCT_PERPETUALS,
includeUpdateMarketStates: !!FLAGS.UPDATE_MARKET_STATE, includeUpdateMarketStates: !!featureFlags.UPDATE_MARKET_STATE,
includeUpdateReferralPrograms: !!FLAGS.REFERRALS, includeUpdateReferralPrograms: !!featureFlags.REFERRALS,
}, },
}); });
@@ -19,7 +19,7 @@ import {
mockWalletContext, mockWalletContext,
createUserVoteQueryMock, createUserVoteQueryMock,
} from '../../test-helpers/mocks'; } from '../../test-helpers/mocks';
import { FLAGS } from '@vegaprotocol/environment'; import { useFeatureFlags } from '@vegaprotocol/environment';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import { VoteState } from '../vote-details/use-user-vote'; import { VoteState } from '../vote-details/use-user-vote';
import { useNewTransferProposalDetails } from '@vegaprotocol/proposals'; import { useNewTransferProposalDetails } from '@vegaprotocol/proposals';
@@ -62,8 +62,7 @@ describe('Proposal header', () => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('Renders New market proposal', () => { it('Renders New market proposal', () => {
const mockedFlags = jest.mocked(FLAGS); useFeatureFlags.setState({ flags: { SUCCESSOR_MARKETS: true } });
mockedFlags.SUCCESSOR_MARKETS = true;
renderComponent( renderComponent(
generateProposal({ generateProposal({
rationale: { rationale: {
@@ -12,7 +12,7 @@ import {
useNewTransferProposalDetails, useNewTransferProposalDetails,
useSuccessorMarketProposalDetails, useSuccessorMarketProposalDetails,
} from '@vegaprotocol/proposals'; } from '@vegaprotocol/proposals';
import { FLAGS } from '@vegaprotocol/environment'; import { useFeatureFlags } from '@vegaprotocol/environment';
import Routes from '../../../routes'; import Routes from '../../../routes';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import type { VoteState } from '../vote-details/use-user-vote'; import type { VoteState } from '../vote-details/use-user-vote';
@@ -28,6 +28,7 @@ export const ProposalHeader = ({
isListItem?: boolean; isListItem?: boolean;
voteState?: VoteState | null; voteState?: VoteState | null;
}) => { }) => {
const featureFlags = useFeatureFlags((state) => state.flags);
const { t } = useTranslation(); const { t } = useTranslation();
const change = proposal?.terms.change; const change = proposal?.terms.change;
@@ -54,13 +55,14 @@ export const ProposalHeader = ({
switch (change?.__typename) { switch (change?.__typename) {
case 'NewMarket': { case 'NewMarket': {
proposalType = proposalType =
FLAGS.PRODUCT_PERPETUALS && change?.instrument?.product?.__typename featureFlags.PRODUCT_PERPETUALS &&
change?.instrument?.product?.__typename
? `NewMarket${change?.instrument?.product?.__typename}` ? `NewMarket${change?.instrument?.product?.__typename}`
: 'NewMarket'; : 'NewMarket';
fallbackTitle = t('NewMarketProposal'); fallbackTitle = t('NewMarketProposal');
details = ( details = (
<> <>
{FLAGS.SUCCESSOR_MARKETS && ( {featureFlags.SUCCESSOR_MARKETS && (
<SuccessorCode proposalId={proposal?.id} /> <SuccessorCode proposalId={proposal?.id} />
)} )}
<span> <span>
@@ -82,13 +84,13 @@ export const ProposalHeader = ({
} }
case 'UpdateMarketState': { case 'UpdateMarketState': {
proposalType = proposalType =
FLAGS.UPDATE_MARKET_STATE && change?.updateType featureFlags.UPDATE_MARKET_STATE && change?.updateType
? t(change.updateType) ? t(change.updateType)
: 'UpdateMarketState'; : 'UpdateMarketState';
fallbackTitle = t('UpdateMarketStateProposal'); fallbackTitle = t('UpdateMarketStateProposal');
details = ( details = (
<span> <span>
{FLAGS.UPDATE_MARKET_STATE && {featureFlags.UPDATE_MARKET_STATE &&
change?.market?.id && change?.market?.id &&
change.updateType ? ( change.updateType ? (
<> <>
@@ -177,14 +179,14 @@ export const ProposalHeader = ({
case 'NewTransfer': case 'NewTransfer':
proposalType = 'NewTransfer'; proposalType = 'NewTransfer';
fallbackTitle = t('NewTransferProposal'); fallbackTitle = t('NewTransferProposal');
details = FLAGS.GOVERNANCE_TRANSFERS ? ( details = featureFlags.GOVERNANCE_TRANSFERS ? (
<NewTransferSummary proposalId={proposal?.id} /> <NewTransferSummary proposalId={proposal?.id} />
) : null; ) : null;
break; break;
case 'CancelTransfer': case 'CancelTransfer':
proposalType = 'CancelTransfer'; proposalType = 'CancelTransfer';
fallbackTitle = t('CancelTransferProposal'); fallbackTitle = t('CancelTransferProposal');
details = FLAGS.GOVERNANCE_TRANSFERS ? ( details = featureFlags.GOVERNANCE_TRANSFERS ? (
<CancelTransferSummary proposalId={proposal?.id} /> <CancelTransferSummary proposalId={proposal?.id} />
) : null; ) : null;
break; break;
@@ -26,7 +26,7 @@ import {
ProposalCancelTransferDetails, ProposalCancelTransferDetails,
ProposalTransferDetails, ProposalTransferDetails,
} from '../proposal-transfer'; } from '../proposal-transfer';
import { FLAGS } from '@vegaprotocol/environment'; import { useFeatureFlags } from '@vegaprotocol/environment';
import { ProposalUpdateBenefitTiers } from '../proposal-update-benefit-tiers'; import { ProposalUpdateBenefitTiers } from '../proposal-update-benefit-tiers';
export interface ProposalProps { export interface ProposalProps {
@@ -53,6 +53,7 @@ export const Proposal = ({
originalMarketProposalRestData, originalMarketProposalRestData,
mostRecentlyEnactedAssociatedMarketProposal, mostRecentlyEnactedAssociatedMarketProposal,
}: ProposalProps) => { }: ProposalProps) => {
const featureFlags = useFeatureFlags((state) => state.flags);
const { t } = useTranslation(); const { t } = useTranslation();
const { submit, Dialog, finalizedVote, transaction } = useVoteSubmit(); const { submit, Dialog, finalizedVote, transaction } = useVoteSubmit();
const { voteState, voteDatetime } = useUserVote(proposal?.id, finalizedVote); const { voteState, voteDatetime } = useUserVote(proposal?.id, finalizedVote);
@@ -132,7 +133,7 @@ export const Proposal = ({
} }
// Show governance transfer details only if the GOVERNANCE_TRANSFERS flag is on. // Show governance transfer details only if the GOVERNANCE_TRANSFERS flag is on.
const governanceTransferDetails = FLAGS.GOVERNANCE_TRANSFERS && ( const governanceTransferDetails = featureFlags.GOVERNANCE_TRANSFERS && (
<> <>
{proposal.terms.change.__typename === 'NewTransfer' && ( {proposal.terms.change.__typename === 'NewTransfer' && (
/** Governance New Transfer Details */ /** Governance New Transfer Details */
@@ -281,8 +281,8 @@ describe('VoteBreakdown', () => {
}); });
it('Progress bar displays status - LP majority', () => { it('Progress bar displays status - LP majority', () => {
const yesVotesLP = 800; const yesVotesLP = 0.8;
const noVotesLP = 200; const noVotesLP = 0.2;
const expectedProgress = (yesVotesLP / (yesVotesLP + noVotesLP)) * 100; // 80% const expectedProgress = (yesVotesLP / (yesVotesLP + noVotesLP)) * 100; // 80%
renderComponent( renderComponent(
@@ -105,8 +105,6 @@ export const VoteBreakdown = ({ proposal }: VoteBreakdownProps) => {
yesLPPercentage, yesLPPercentage,
yesTokens, yesTokens,
noTokens, noTokens,
yesEquityLikeShareWeight,
noEquityLikeShareWeight,
totalEquityLikeShareWeight, totalEquityLikeShareWeight,
requiredMajorityPercentage, requiredMajorityPercentage,
requiredMajorityLPPercentage, requiredMajorityLPPercentage,
@@ -135,6 +133,7 @@ export const VoteBreakdown = ({ proposal }: VoteBreakdownProps) => {
.multipliedBy(100), .multipliedBy(100),
new BigNumber(100) new BigNumber(100)
); );
const willPass = willPassByTokenVote || willPassByLPVote; const willPass = willPassByTokenVote || willPassByLPVote;
const updateMarketVotePassMethod = willPassByTokenVote const updateMarketVotePassMethod = willPassByTokenVote
? t('byTokenVote') ? t('byTokenVote')
@@ -202,50 +201,24 @@ export const VoteBreakdown = ({ proposal }: VoteBreakdownProps) => {
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<span>{t('liquidityProviderVotesFor')}:</span> <span>{t('liquidityProviderVotesFor')}:</span>
<Tooltip <Tooltip
description={formatNumber( description={
yesEquityLikeShareWeight, <span>{yesLPPercentage.toFixed(defaultDP)}%</span>
defaultDP }
)}
> >
<button> <button>{yesLPPercentage.toFixed(1)}%</button>
<CompactVotes number={yesEquityLikeShareWeight} />
</button>
</Tooltip> </Tooltip>
<span>
(
<Tooltip
description={
<span>{yesLPPercentage.toFixed(defaultDP)}%</span>
}
>
<button>{yesLPPercentage.toFixed(0)}%</button>
</Tooltip>
)
</span>
</div> </div>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<span>{t('liquidityProviderVotesAgainst')}:</span> <span>{t('liquidityProviderVotesAgainst')}:</span>
<Tooltip
description={formatNumber(
noEquityLikeShareWeight,
defaultDP
)}
>
<button>
<CompactVotes number={noEquityLikeShareWeight} />
</button>
</Tooltip>
<span> <span>
(
<Tooltip <Tooltip
description={ description={
<span>{noLPPercentage.toFixed(defaultDP)}%</span> <span>{noLPPercentage.toFixed(defaultDP)}%</span>
} }
> >
<button>{noLPPercentage.toFixed(0)}%</button> <button>{noLPPercentage.toFixed(1)}%</button>
</Tooltip> </Tooltip>
)
</span> </span>
</div> </div>
</div> </div>
@@ -282,13 +255,8 @@ export const VoteBreakdown = ({ proposal }: VoteBreakdownProps) => {
defaultDP defaultDP
)} )}
> >
<button> <span>{totalEquityLikeShareWeight.toFixed(1)}%</span>
<CompactVotes number={totalEquityLikeShareWeight} />
</button>
</Tooltip> </Tooltip>
<span>
({totalEquityLikeShareWeight.toFixed(defaultDP)}%)
</span>
</div> </div>
</div> </div>
</section> </section>
@@ -54,8 +54,8 @@ describe('use-vote-information', () => {
it('returns all required vote information', () => { it('returns all required vote information', () => {
const yesVotes = 40; const yesVotes = 40;
const noVotes = 60; const noVotes = 60;
const yesEquityLikeShareWeight = '30'; const yesEquityLikeShareWeight = '0.30';
const noEquityLikeShareWeight = '70'; const noEquityLikeShareWeight = '0.70';
// Note - giving a fixedTokenValue of 1 means a ratio of 1:1 votes to tokens, making sums easier :) // Note - giving a fixedTokenValue of 1 means a ratio of 1:1 votes to tokens, making sums easier :)
const fixedTokenValue = 1000000000000000000; const fixedTokenValue = 1000000000000000000;
@@ -195,10 +195,10 @@ describe('use-vote-information', () => {
}); });
it('correctly shows whether an update market proposal will pass by token or LP vote - both failing', () => { it('correctly shows whether an update market proposal will pass by token or LP vote - both failing', () => {
const yesVotes = 20; const yesVotes = 0.2;
const noVotes = 70; const noVotes = 0.7;
const yesEquityLikeShareWeight = '30'; const yesEquityLikeShareWeight = '0.30';
const noEquityLikeShareWeight = '60'; const noEquityLikeShareWeight = '0.60';
const fixedTokenValue = 1000000000000000000; const fixedTokenValue = 1000000000000000000;
const proposal = generateProposal({ const proposal = generateProposal({
@@ -61,7 +61,7 @@ export const useVoteInformation = ({
const noEquityLikeShareWeight = !proposal?.votes.no const noEquityLikeShareWeight = !proposal?.votes.no
.totalEquityLikeShareWeight .totalEquityLikeShareWeight
? new BigNumber(0) ? new BigNumber(0)
: new BigNumber(proposal.votes.no.totalEquityLikeShareWeight); : new BigNumber(proposal.votes.no.totalEquityLikeShareWeight).times(100);
const yesTokens = new BigNumber( const yesTokens = new BigNumber(
addDecimal(proposal?.votes.yes.totalTokens ?? 0, decimals) addDecimal(proposal?.votes.yes.totalTokens ?? 0, decimals)
@@ -70,7 +70,7 @@ export const useVoteInformation = ({
const yesEquityLikeShareWeight = !proposal?.votes.yes const yesEquityLikeShareWeight = !proposal?.votes.yes
.totalEquityLikeShareWeight .totalEquityLikeShareWeight
? new BigNumber(0) ? new BigNumber(0)
: new BigNumber(proposal.votes.yes.totalEquityLikeShareWeight); : new BigNumber(proposal.votes.yes.totalEquityLikeShareWeight).times(100);
const totalTokensVoted = yesTokens.plus(noTokens); const totalTokensVoted = yesTokens.plus(noTokens);
@@ -81,12 +81,7 @@ export const useVoteInformation = ({
const yesPercentage = totalTokensVoted.isZero() const yesPercentage = totalTokensVoted.isZero()
? new BigNumber(0) ? new BigNumber(0)
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted); : yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
const yesLPPercentage = yesEquityLikeShareWeight;
const yesLPPercentage = totalEquityLikeShareWeight.isZero()
? new BigNumber(0)
: yesEquityLikeShareWeight
.multipliedBy(100)
.dividedBy(totalEquityLikeShareWeight);
const noPercentage = totalTokensVoted.isZero() const noPercentage = totalTokensVoted.isZero()
? new BigNumber(0) ? new BigNumber(0)
@@ -103,9 +98,7 @@ export const useVoteInformation = ({
); );
const participationLPMet = requiredParticipationLP const participationLPMet = requiredParticipationLP
? totalEquityLikeShareWeight.isGreaterThan( ? totalEquityLikeShareWeight.isGreaterThan(requiredParticipationLP)
totalSupply.multipliedBy(requiredParticipationLP)
)
: false; : false;
const majorityMet = yesPercentage.isGreaterThanOrEqualTo( const majorityMet = yesPercentage.isGreaterThanOrEqualTo(
@@ -120,9 +113,7 @@ export const useVoteInformation = ({
.multipliedBy(100) .multipliedBy(100)
.dividedBy(totalSupply); .dividedBy(totalSupply);
const totalLPTokensPercentage = totalEquityLikeShareWeight const totalLPTokensPercentage = totalEquityLikeShareWeight;
.multipliedBy(100)
.dividedBy(totalSupply);
const willPassByTokenVote = const willPassByTokenVote =
participationMet && participationMet &&
@@ -15,10 +15,11 @@ import {
useNetworkParams, useNetworkParams,
} from '@vegaprotocol/network-parameters'; } from '@vegaprotocol/network-parameters';
import { useParentMarketIdQuery } from '@vegaprotocol/markets'; import { useParentMarketIdQuery } from '@vegaprotocol/markets';
import { FLAGS } from '@vegaprotocol/environment'; import { useFeatureFlags } from '@vegaprotocol/environment';
import { useSuccessorMarketProposalDetails } from '@vegaprotocol/proposals'; import { useSuccessorMarketProposalDetails } from '@vegaprotocol/proposals';
export const ProposalContainer = () => { export const ProposalContainer = () => {
const featureFlags = useFeatureFlags((state) => state.flags);
const [ const [
mostRecentlyEnactedAssociatedMarketProposal, mostRecentlyEnactedAssociatedMarketProposal,
setMostRecentlyEnactedAssociatedMarketProposal, setMostRecentlyEnactedAssociatedMarketProposal,
@@ -59,9 +60,9 @@ export const ProposalContainer = () => {
errorPolicy: 'ignore', errorPolicy: 'ignore',
variables: { variables: {
proposalId: params.proposalId || '', proposalId: params.proposalId || '',
includeNewMarketProductField: !!FLAGS.PRODUCT_PERPETUALS, includeNewMarketProductField: !!featureFlags.PRODUCT_PERPETUALS,
includeUpdateMarketState: !!FLAGS.UPDATE_MARKET_STATE, includeUpdateMarketState: !!featureFlags.UPDATE_MARKET_STATE,
includeUpdateReferralProgram: !!FLAGS.REFERRALS, includeUpdateReferralProgram: !!featureFlags.REFERRALS,
}, },
skip: !params.proposalId, skip: !params.proposalId,
}); });
@@ -120,7 +121,7 @@ export const ProposalContainer = () => {
variables: { variables: {
marketId: marketData?.id || '', marketId: marketData?.id || '',
}, },
skip: !FLAGS.SUCCESSOR_MARKETS || !isSuccessor || !marketData?.id, skip: !featureFlags.SUCCESSOR_MARKETS || !isSuccessor || !marketData?.id,
}); });
const { const {
@@ -133,7 +134,7 @@ export const ProposalContainer = () => {
variables: { variables: {
marketId: parentMarketId?.market?.parentMarketID || '', marketId: parentMarketId?.market?.parentMarketID || '',
skip: skip:
!FLAGS.SUCCESSOR_MARKETS || !featureFlags.SUCCESSOR_MARKETS ||
!isSuccessor || !isSuccessor ||
!parentMarketId?.market?.parentMarketID, !parentMarketId?.market?.parentMarketID,
}, },
@@ -17,7 +17,7 @@ import {
} from './__generated__/Proposals'; } from './__generated__/Proposals';
import { type ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals'; import { type ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
import { useProtocolUpgradeProposalsQuery } from '@vegaprotocol/proposals'; import { useProtocolUpgradeProposalsQuery } from '@vegaprotocol/proposals';
import { FLAGS } from '@vegaprotocol/environment'; import { useFeatureFlags } from '@vegaprotocol/environment';
export function getNotRejectedProposals(data?: ProposalFieldsFragment[]) { export function getNotRejectedProposals(data?: ProposalFieldsFragment[]) {
return flow([ return flow([
@@ -43,15 +43,16 @@ export function getNotRejectedProtocolUpgradeProposals<
} }
export const ProposalsContainer = () => { export const ProposalsContainer = () => {
const featureFlags = useFeatureFlags((state) => state.flags);
const { t } = useTranslation(); const { t } = useTranslation();
const { data, loading, error } = useProposalsQuery({ const { data, loading, error } = useProposalsQuery({
pollInterval: 5000, pollInterval: 5000,
fetchPolicy: 'network-only', fetchPolicy: 'network-only',
errorPolicy: 'ignore', errorPolicy: 'ignore',
variables: { variables: {
includeNewMarketProductFields: !!FLAGS.PRODUCT_PERPETUALS, includeNewMarketProductFields: !!featureFlags.PRODUCT_PERPETUALS,
includeUpdateMarketStates: !!FLAGS.UPDATE_MARKET_STATE, includeUpdateMarketStates: !!featureFlags.UPDATE_MARKET_STATE,
includeUpdateReferralPrograms: !!FLAGS.REFERRALS, includeUpdateReferralPrograms: !!featureFlags.REFERRALS,
}, },
}); });
@@ -95,7 +95,7 @@ export const ProtocolUpgradeProposalContainer = () => {
time={ time={
pending && time ? ( pending && time ? (
convertToCountdownString(time, '0:00:00:00') convertToCountdownString(time, '0:00:00:00')
) : blockInfo?.result ? ( ) : blockInfo && 'result' in blockInfo && blockInfo?.result ? (
<span title={blockInfo.result.block.header.time}> <span title={blockInfo.result.block.header.time}>
{formatDateWithLocalTimezone( {formatDateWithLocalTimezone(
new Date(blockInfo.result.block.header.time) new Date(blockInfo.result.block.header.time)
@@ -10,7 +10,7 @@ import { removePaginationWrapper } from '@vegaprotocol/utils';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import orderBy from 'lodash/orderBy'; import orderBy from 'lodash/orderBy';
import { ProposalState } from '@vegaprotocol/types'; import { ProposalState } from '@vegaprotocol/types';
import { FLAGS } from '@vegaprotocol/environment'; import { useFeatureFlags } from '@vegaprotocol/environment';
const orderByDate = (arr: ProposalFieldsFragment[]) => const orderByDate = (arr: ProposalFieldsFragment[]) =>
orderBy( orderBy(
@@ -33,15 +33,16 @@ export function getRejectedProposals(data?: ProposalFieldsFragment[] | null) {
} }
export const RejectedProposalsContainer = () => { export const RejectedProposalsContainer = () => {
const featureFlags = useFeatureFlags((state) => state.flags);
const { t } = useTranslation(); const { t } = useTranslation();
const { data, loading, error } = useProposalsQuery({ const { data, loading, error } = useProposalsQuery({
pollInterval: 5000, pollInterval: 5000,
fetchPolicy: 'network-only', fetchPolicy: 'network-only',
errorPolicy: 'ignore', errorPolicy: 'ignore',
variables: { variables: {
includeNewMarketProductFields: !!FLAGS.PRODUCT_PERPETUALS, includeNewMarketProductFields: !!featureFlags.PRODUCT_PERPETUALS,
includeUpdateMarketStates: !!FLAGS.UPDATE_MARKET_STATE, includeUpdateMarketStates: !!featureFlags.UPDATE_MARKET_STATE,
includeUpdateReferralPrograms: !!FLAGS.REFERRALS, includeUpdateReferralPrograms: !!featureFlags.REFERRALS,
}, },
}); });
@@ -116,7 +116,8 @@ export const generateYesVotes = (
fixedTokenValue?: number, fixedTokenValue?: number,
totalEquityLikeShareWeight?: string totalEquityLikeShareWeight?: string
): Votes => { ): Votes => {
const votes = Array.from(Array(numberOfVotes)).map(() => { const votes = [];
for (let i = 0; i < numberOfVotes; i++) {
const vote: Vote = { const vote: Vote = {
__typename: 'Vote', __typename: 'Vote',
value: Schema.VoteValue.VALUE_YES, value: Schema.VoteValue.VALUE_YES,
@@ -152,8 +153,9 @@ export const generateYesVotes = (
datetime: faker.date.past().toISOString(), datetime: faker.date.past().toISOString(),
}; };
return vote; votes.push(vote);
}); }
return { return {
__typename: 'ProposalVoteSide', __typename: 'ProposalVoteSide',
totalNumber: votes.length.toString(), totalNumber: votes.length.toString(),
@@ -172,7 +174,8 @@ export const generateNoVotes = (
fixedTokenValue?: number, fixedTokenValue?: number,
totalEquityLikeShareWeight?: string totalEquityLikeShareWeight?: string
): Votes => { ): Votes => {
const votes = Array.from(Array(numberOfVotes)).map(() => { const votes = [];
for (let i = 0; i < numberOfVotes; i++) {
const vote: Vote = { const vote: Vote = {
__typename: 'Vote', __typename: 'Vote',
value: Schema.VoteValue.VALUE_NO, value: Schema.VoteValue.VALUE_NO,
@@ -207,8 +210,9 @@ export const generateNoVotes = (
}, },
datetime: faker.date.past().toISOString(), datetime: faker.date.past().toISOString(),
}; };
return vote; votes.push(vote);
}); }
return { return {
__typename: 'ProposalVoteSide', __typename: 'ProposalVoteSide',
totalNumber: votes.length.toString(), totalNumber: votes.length.toString(),
+4 -1
View File
@@ -24,4 +24,7 @@ NX_STOP_ORDERS=true
NX_ICEBERG_ORDERS=true NX_ICEBERG_ORDERS=true
# NX_PRODUCT_PERPETUALS # NX_PRODUCT_PERPETUALS
NX_METAMASK_SNAPS=true NX_METAMASK_SNAPS=true
NX_REFERRALS=true NX_REFERRALS=true
NX_CHARTING_LIBRARY_PATH=https://assets.vega.community/trading-view-bundle/v0.0.1/
NX_CHARTING_LIBRARY_HASH=PDjWaqPFndDp+LCvqbKvntWriaqNzNpZ5i9R/BULzCg=
+3
View File
@@ -28,3 +28,6 @@ NX_REFERRALS=true
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
NX_CHARTING_LIBRARY_PATH=https://assets.vega.community/trading-view-bundle/v0.0.1/
NX_CHARTING_LIBRARY_HASH=PDjWaqPFndDp+LCvqbKvntWriaqNzNpZ5i9R/BULzCg=
@@ -188,12 +188,11 @@ const useNow = () => {
return now; return now;
}; };
const useEvery = (marketId: string) => { const useEvery = (marketId: string, skip: boolean) => {
const { data: marketTradingMode } = useMarketTradingMode(marketId);
const { data: marketInfo } = useDataProvider({ const { data: marketInfo } = useDataProvider({
dataProvider: marketInfoProvider, dataProvider: marketInfoProvider,
variables: { marketId }, variables: { marketId },
skip: !marketTradingMode || isMarketInAuction(marketTradingMode), skip,
}); });
let every: number | undefined = undefined; let every: number | undefined = undefined;
const sourceType = const sourceType =
@@ -211,8 +210,10 @@ const useEvery = (marketId: string) => {
return every; return every;
}; };
const useStartTime = (marketId: string) => { const useStartTime = (marketId: string, skip: boolean) => {
const { data: fundingPeriods } = useFundingPeriodsQuery({ const { data: fundingPeriods } = useFundingPeriodsQuery({
pollInterval: 5000,
skip,
variables: { variables: {
marketId: marketId, marketId: marketId,
pagination: { first: 1 }, pagination: { first: 1 },
@@ -246,8 +247,10 @@ const useFormatCountdown = (
export const FundingCountdown = ({ marketId }: { marketId: string }) => { export const FundingCountdown = ({ marketId }: { marketId: string }) => {
const now = useNow(); const now = useNow();
const startTime = useStartTime(marketId); const { data: marketTradingMode } = useMarketTradingMode(marketId);
const every = useEvery(marketId); const skip = !marketTradingMode || isMarketInAuction(marketTradingMode);
const startTime = useStartTime(marketId, skip);
const every = useEvery(marketId, skip);
return ( return (
<div data-testid="funding-countdown"> <div data-testid="funding-countdown">
+1 -15
View File
@@ -9,8 +9,6 @@ import { TradeGrid } from './trade-grid';
import { TradePanels } from './trade-panels'; import { TradePanels } from './trade-panels';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { Links } from '../../lib/links'; import { Links } from '../../lib/links';
import { ViewType, useSidebar } from '../../components/sidebar';
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
import { useT, ns } from '../../lib/use-t'; import { useT, ns } from '../../lib/use-t';
import { Trans } from 'react-i18next'; import { Trans } from 'react-i18next';
@@ -61,9 +59,6 @@ export const MarketPage = () => {
const t = useT(); const t = useT();
const { marketId } = useParams(); const { marketId } = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
const currentRouteId = useGetCurrentRouteId();
const { setViews, getView } = useSidebar();
const view = getView(currentRouteId);
const { screenSize } = useScreenDimensions(); const { screenSize } = useScreenDimensions();
const largeScreen = ['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize); const largeScreen = ['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize);
const update = useGlobalStore((store) => store.update); const update = useGlobalStore((store) => store.update);
@@ -72,20 +67,11 @@ export const MarketPage = () => {
const { data, loading } = useMarket(marketId); const { data, loading } = useMarket(marketId);
useEffect(() => { useEffect(() => {
if (data?.id && data.id !== lastMarketId && !closed) { if (data?.id && data.id !== lastMarketId) {
update({ marketId: data.id }); update({ marketId: data.id });
} }
}, [update, lastMarketId, data?.id]); }, [update, lastMarketId, data?.id]);
useEffect(() => {
if (largeScreen && view === undefined) {
setViews(
{ type: closed ? ViewType.Info : ViewType.Order },
currentRouteId
);
}
}, [setViews, view, currentRouteId, largeScreen]);
const pinnedAsset = data && getAsset(data); const pinnedAsset = data && getAsset(data);
const tradeView = useMemo(() => { const tradeView = useMemo(() => {
@@ -18,7 +18,7 @@ import {
MarketSuccessorProposalBanner, MarketSuccessorProposalBanner,
MarketTerminationBanner, MarketTerminationBanner,
} from '../../components/market-banner'; } from '../../components/market-banner';
import { FLAGS } from '@vegaprotocol/environment'; import { useFeatureFlags } from '@vegaprotocol/environment';
import { useT } from '../../lib/use-t'; import { useT } from '../../lib/use-t';
import { ErrorBoundary } from '../../components/error-boundary'; import { ErrorBoundary } from '../../components/error-boundary';
@@ -35,6 +35,7 @@ const MainGrid = memo(
marketId: string; marketId: string;
pinnedAsset?: PinnedAsset; pinnedAsset?: PinnedAsset;
}) => { }) => {
const featureFlags = useFeatureFlags((state) => state.flags);
const t = useT(); const t = useT();
const { data: market } = useMarket(marketId); const { data: market } = useMarket(marketId);
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'top' }); const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'top' });
@@ -61,10 +62,10 @@ const MainGrid = memo(
id="chart" id="chart"
overflowHidden overflowHidden
name={t('Chart')} name={t('Chart')}
menu={<TradingViews.candles.menu />} menu={<TradingViews.chart.menu />}
> >
<ErrorBoundary feature="chart"> <ErrorBoundary feature="chart">
<TradingViews.candles.component marketId={marketId} /> <TradingViews.chart.component marketId={marketId} />
</ErrorBoundary> </ErrorBoundary>
</Tab> </Tab>
<Tab id="depth" name={t('Depth')}> <Tab id="depth" name={t('Depth')}>
@@ -165,7 +166,7 @@ const MainGrid = memo(
<TradingViews.orders.component /> <TradingViews.orders.component />
</ErrorBoundary> </ErrorBoundary>
</Tab> </Tab>
{FLAGS.STOP_ORDERS ? ( {featureFlags.STOP_ORDERS ? (
<Tab id="stop-orders" name={t('Stop orders')}> <Tab id="stop-orders" name={t('Stop orders')}>
<ErrorBoundary feature="stop-orders"> <ErrorBoundary feature="stop-orders">
<TradingViews.stopOrders.component /> <TradingViews.stopOrders.component />
@@ -196,6 +197,7 @@ const MainGrid = memo(
MainGrid.displayName = 'MainGrid'; MainGrid.displayName = 'MainGrid';
export const TradeGrid = ({ market, pinnedAsset }: TradeGridProps) => { export const TradeGrid = ({ market, pinnedAsset }: TradeGridProps) => {
const featureFlags = useFeatureFlags((state) => state.flags);
const wrapperClasses = classNames( const wrapperClasses = classNames(
'h-full grid', 'h-full grid',
'grid-rows-[min-content_1fr]' 'grid-rows-[min-content_1fr]'
@@ -204,7 +206,7 @@ export const TradeGrid = ({ market, pinnedAsset }: TradeGridProps) => {
return ( return (
<div className={wrapperClasses}> <div className={wrapperClasses}>
<div> <div>
{FLAGS.SUCCESSOR_MARKETS && ( {featureFlags.SUCCESSOR_MARKETS && (
<> <>
<MarketSuccessorBanner market={market} /> <MarketSuccessorBanner market={market} />
<MarketSuccessorProposalBanner marketId={market?.id} /> <MarketSuccessorProposalBanner marketId={market?.id} />
@@ -4,7 +4,6 @@ import { OracleBanner } from '@vegaprotocol/markets';
import { useState } from 'react'; import { useState } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer'; import AutoSizer from 'react-virtualized-auto-sizer';
import classNames from 'classnames'; import classNames from 'classnames';
import { FLAGS } from '@vegaprotocol/environment';
import { Splash } from '@vegaprotocol/ui-toolkit'; import { Splash } from '@vegaprotocol/ui-toolkit';
import { useT } from '../../lib/use-t'; import { useT } from '../../lib/use-t';
import { import {
@@ -15,6 +14,7 @@ import {
import { ErrorBoundary } from '../../components/error-boundary'; import { ErrorBoundary } from '../../components/error-boundary';
import { type TradingView } from './trade-views'; import { type TradingView } from './trade-views';
import { TradingViews } from './trade-views'; import { TradingViews } from './trade-views';
import { useFeatureFlags } from '@vegaprotocol/environment';
interface TradePanelsProps { interface TradePanelsProps {
market: Market | null; market: Market | null;
@@ -22,7 +22,8 @@ interface TradePanelsProps {
} }
export const TradePanels = ({ market, pinnedAsset }: TradePanelsProps) => { export const TradePanels = ({ market, pinnedAsset }: TradePanelsProps) => {
const [view, setView] = useState<TradingView>('candles'); const featureFlags = useFeatureFlags((state) => state.flags);
const [view, setView] = useState<TradingView>('chart');
const renderView = () => { const renderView = () => {
const Component = TradingViews[view].component; const Component = TradingViews[view].component;
@@ -49,7 +50,7 @@ export const TradePanels = ({ market, pinnedAsset }: TradePanelsProps) => {
const Menu = viewCfg.menu; const Menu = viewCfg.menu;
return ( return (
<div className="flex gap-1 p-1 bg-vega-clight-800 dark:bg-vega-cdark-800 border-b border-default"> <div className="flex items-center justify-end gap-1 p-1 bg-vega-clight-800 dark:bg-vega-cdark-800 border-b border-default">
<Menu /> <Menu />
</div> </div>
); );
@@ -61,7 +62,7 @@ export const TradePanels = ({ market, pinnedAsset }: TradePanelsProps) => {
return ( return (
<div className="h-full grid grid-rows-[min-content_min-content_1fr_min-content]"> <div className="h-full grid grid-rows-[min-content_min-content_1fr_min-content]">
<div> <div>
{FLAGS.SUCCESSOR_MARKETS && ( {featureFlags.SUCCESSOR_MARKETS && (
<> <>
<MarketSuccessorBanner market={market} /> <MarketSuccessorBanner market={market} />
<MarketSuccessorProposalBanner marketId={market?.id} /> <MarketSuccessorProposalBanner marketId={market?.id} />
@@ -148,7 +149,7 @@ const useViewLabel = (view: TradingView) => {
const t = useT(); const t = useT();
const labels = { const labels = {
candles: t('Candles'), chart: t('Chart'),
depth: t('Depth'), depth: t('Depth'),
liquidity: t('Liquidity'), liquidity: t('Liquidity'),
funding: t('Funding'), funding: t('Funding'),
@@ -1,8 +1,4 @@
import { DepthChartContainer } from '@vegaprotocol/market-depth'; import { DepthChartContainer } from '@vegaprotocol/market-depth';
import {
CandlesChartContainer,
CandlesMenu,
} from '@vegaprotocol/candles-chart';
import { Filter, OpenOrdersMenu } from '@vegaprotocol/orders'; import { Filter, OpenOrdersMenu } from '@vegaprotocol/orders';
import { TradesContainer } from '../../components/trades-container'; import { TradesContainer } from '../../components/trades-container';
import { OrderbookContainer } from '../../components/orderbook-container'; import { OrderbookContainer } from '../../components/orderbook-container';
@@ -16,13 +12,14 @@ import { OrdersContainer } from '../../components/orders-container';
import { StopOrdersContainer } from '../../components/stop-orders-container'; import { StopOrdersContainer } from '../../components/stop-orders-container';
import { AccountsMenu } from '../../components/accounts-menu'; import { AccountsMenu } from '../../components/accounts-menu';
import { PositionsMenu } from '../../components/positions-menu'; import { PositionsMenu } from '../../components/positions-menu';
import { ChartContainer, ChartMenu } from '../../components/chart-container';
export type TradingView = keyof typeof TradingViews; export type TradingView = keyof typeof TradingViews;
export const TradingViews = { export const TradingViews = {
candles: { chart: {
component: CandlesChartContainer, component: ChartContainer,
menu: CandlesMenu, menu: ChartMenu,
}, },
depth: { depth: {
component: DepthChartContainer, component: DepthChartContainer,
@@ -4,9 +4,26 @@ import {
SidebarButton, SidebarButton,
SidebarDivider, SidebarDivider,
ViewType, ViewType,
useSidebar,
} from '../../components/sidebar'; } from '../../components/sidebar';
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
import { useT } from '../../lib/use-t'; import { useT } from '../../lib/use-t';
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import { useEffect } from 'react';
const ViewInitializer = () => {
const currentRouteId = useGetCurrentRouteId();
const { setViews, getView } = useSidebar();
const view = getView(currentRouteId);
const { screenSize } = useScreenDimensions();
const largeScreen = ['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize);
useEffect(() => {
if (largeScreen && view === undefined) {
setViews({ type: ViewType.Order }, currentRouteId);
}
}, [setViews, view, currentRouteId, largeScreen]);
return null;
};
export const MarketsSidebar = () => { export const MarketsSidebar = () => {
const t = useT(); const t = useT();
@@ -37,6 +54,7 @@ export const MarketsSidebar = () => {
path=":marketId" path=":marketId"
element={ element={
<> <>
<ViewInitializer />
<SidebarDivider /> <SidebarDivider />
<SidebarButton <SidebarButton
view={ViewType.Order} view={ViewType.Order}
@@ -39,11 +39,21 @@ const WithdrawalsIndicator = () => {
); );
}; };
export const Portfolio = () => { const SidebarViewInitializer = () => {
const t = useT();
const currentRouteId = useGetCurrentRouteId(); const currentRouteId = useGetCurrentRouteId();
const { getView, setViews } = useSidebar(); const { getView, setViews } = useSidebar();
const view = getView(currentRouteId); const view = getView(currentRouteId);
// Make transfer sidebar open by default
useEffect(() => {
if (view === undefined) {
setViews({ type: ViewType.Transfer }, currentRouteId);
}
}, [view, setViews, currentRouteId]);
return null;
};
export const Portfolio = () => {
const t = useT();
const { updateTitle } = usePageTitleStore((store) => ({ const { updateTitle } = usePageTitleStore((store) => ({
updateTitle: store.updateTitle, updateTitle: store.updateTitle,
@@ -53,17 +63,11 @@ export const Portfolio = () => {
updateTitle(titlefy([t('Portfolio')])); updateTitle(titlefy([t('Portfolio')]));
}, [updateTitle, t]); }, [updateTitle, t]);
// Make transfer sidebar open by default
useEffect(() => {
if (view === undefined) {
setViews({ type: ViewType.Transfer }, currentRouteId);
}
}, [view, setViews, currentRouteId]);
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'portfolio' }); const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'portfolio' });
const wrapperClasses = 'p-0.5 h-full max-h-full flex flex-col'; const wrapperClasses = 'p-0.5 h-full max-h-full flex flex-col';
return ( return (
<div className={wrapperClasses}> <div className={wrapperClasses}>
<SidebarViewInitializer />
<ResizableGrid vertical onChange={handleOnLayoutChange}> <ResizableGrid vertical onChange={handleOnLayoutChange}>
<ResizableGridPanel minSize={75}> <ResizableGridPanel minSize={75}>
<PortfolioGridChild> <PortfolioGridChild>
@@ -2,6 +2,7 @@ import { removePaginationWrapper } from '@vegaprotocol/utils';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useRefereesQuery } from './__generated__/Referees'; import { useRefereesQuery } from './__generated__/Referees';
import compact from 'lodash/compact'; import compact from 'lodash/compact';
import pick from 'lodash/pick';
import type { import type {
ReferralSetsQuery, ReferralSetsQuery,
ReferralSetsQueryVariables, ReferralSetsQueryVariables,
@@ -122,6 +123,66 @@ export const useReferral = (args: UseReferralArgs) => {
}; };
}; };
type Referee = NonNullable<
NonNullable<ReturnType<typeof useReferral>['data']>['referee']
>;
type RefereeProperties = (keyof Referee)[];
const findReferee = (referee: Referee, referees: Referee[]) =>
referees.find((r) => r.refereeId === referee?.refereeId) || referee;
const updateReferee = (
referee: Referee,
referees: Referee[],
properties: RefereeProperties
) => ({
...referee,
...pick(findReferee(referee, referees), properties),
});
export const useUpdateReferees = (
referral: ReturnType<typeof useReferral>,
aggregationEpochs: number,
properties: RefereeProperties,
skip?: boolean
): ReturnType<typeof useReferral> => {
const { data, loading, error, refetch } = useRefereesQuery({
variables: {
code: referral?.data?.code as string,
aggregationEpochs,
},
skip: skip || !referral?.data?.code,
fetchPolicy: 'cache-and-network',
context: { isEnlargedTimeout: true },
});
const refetchAll = useCallback(() => {
refetch();
referral.refetch();
}, [refetch, referral]);
if (!referral.data || skip) {
return referral;
}
const referees = compact(
removePaginationWrapper(data?.referralSetReferees.edges)
);
return {
data: data && {
...referral.data,
referees: referral.data.referees.map((referee) =>
updateReferee(referee, referees, properties)
),
referee:
referral.data.referee &&
updateReferee(referral.data.referee, referees, properties),
},
loading: loading || referral.loading,
error: error || referral.error,
refetch: refetchAll,
};
};
const retrieveReferralSetData = (data: ReferralSetsQuery | undefined) => const retrieveReferralSetData = (data: ReferralSetsQuery | undefined) =>
data?.referralSets.edges && data.referralSets.edges.length > 0 data?.referralSets.edges && data.referralSets.edges.length > 0
? data.referralSets.edges[0]?.node ? data.referralSets.edges[0]?.node
@@ -151,6 +151,27 @@ const MOCK_REFEREES: RefereesQuery = {
}, },
}; };
const MOCK_REFEREES_30: RefereesQuery = {
referralSetReferees: {
__typename: 'ReferralSetRefereeConnection',
edges: [
{
node: {
atEpoch: 1,
joinedAt: '2023-11-21T14:17:09.257235Z',
refereeId:
'0987654321098765432109876543210987654321098765432109876543219876',
referralSetId:
'3772e570fbab89e50e563036b01dd949c554e5b5fe7908449672dfce9a8adffa',
totalRefereeGeneratedRewards: '12340',
totalRefereeNotionalTakerVolume: '56780',
__typename: 'ReferralSetReferee',
},
},
],
},
};
const programMock: MockedResponse<ReferralProgramQuery> = { const programMock: MockedResponse<ReferralProgramQuery> = {
request: { request: {
query: ReferralProgramDocument, query: ReferralProgramDocument,
@@ -262,6 +283,19 @@ const refereesMock: MockedResponse<RefereesQuery, RefereesQueryVariables> = {
}, },
}; };
const refereesMock30: MockedResponse<RefereesQuery, RefereesQueryVariables> = {
request: {
query: RefereesDocument,
variables: {
code: MOCK_REFERRER_SET.referralSets.edges[0]?.node.id as string,
aggregationEpochs: 30,
},
},
result: {
data: MOCK_REFEREES_30,
},
};
jest.mock('@vegaprotocol/wallet', () => { jest.mock('@vegaprotocol/wallet', () => {
return { return {
...jest.requireActual('@vegaprotocol/wallet'), ...jest.requireActual('@vegaprotocol/wallet'),
@@ -297,6 +331,7 @@ describe('ReferralStatistics', () => {
noReferralSetAsRefereeMock, noReferralSetAsRefereeMock,
stakeAvailableMock, stakeAvailableMock,
refereesMock, refereesMock,
refereesMock30,
]} ]}
showWarnings={false} showWarnings={false}
> >
@@ -313,6 +348,10 @@ describe('ReferralStatistics', () => {
expect(queryByTestId('referral-statistics')?.dataset.as).toEqual( expect(queryByTestId('referral-statistics')?.dataset.as).toEqual(
'referrer' 'referrer'
); );
// gets commision from 30 epochs query
expect(queryByTestId('total-commission-value')).toHaveTextContent(
'12,340'
);
}); });
}); });
@@ -4,10 +4,15 @@ import {
VegaIcon, VegaIcon,
VegaIconNames, VegaIconNames,
truncateMiddle, truncateMiddle,
TextChildrenTooltip as Tooltip,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet';
import { DEFAULT_AGGREGATION_DAYS, useReferral } from './hooks/use-referral'; import {
DEFAULT_AGGREGATION_DAYS,
useReferral,
useUpdateReferees,
} from './hooks/use-referral';
import classNames from 'classnames'; import classNames from 'classnames';
import { Table } from './table'; import { Table } from './table';
import { import {
@@ -41,11 +46,17 @@ export const ReferralStatistics = () => {
role: 'referee', role: 'referee',
aggregationEpochs: program.details?.windowLength, aggregationEpochs: program.details?.windowLength,
}); });
const { data: referrer, refetch: referrerRefetch } = useReferral({
pubKey, const { data: referrer, refetch: referrerRefetch } = useUpdateReferees(
role: 'referrer', useReferral({
aggregationEpochs: program.details?.windowLength, pubKey,
}); role: 'referrer',
aggregationEpochs: program.details?.windowLength,
}),
DEFAULT_AGGREGATION_DAYS,
['totalRefereeGeneratedRewards'],
DEFAULT_AGGREGATION_DAYS === program.details?.windowLength
);
const refetch = useCallback(() => { const refetch = useCallback(() => {
refereeRefetch(); refereeRefetch();
@@ -76,11 +87,9 @@ export const ReferralStatistics = () => {
export const useStats = ({ export const useStats = ({
data, data,
program, program,
as,
}: { }: {
data?: NonNullable<ReturnType<typeof useReferral>['data']>; data?: NonNullable<ReturnType<typeof useReferral>['data']>;
program: ReturnType<typeof useReferralProgram>; program: ReturnType<typeof useReferralProgram>;
as?: 'referrer' | 'referee';
}) => { }) => {
const { benefitTiers } = program; const { benefitTiers } = program;
const { data: epochData } = useCurrentEpochInfoQuery({ const { data: epochData } = useCurrentEpochInfoQuery({
@@ -181,7 +190,7 @@ export const Statistics = ({
nextBenefitTierValue, nextBenefitTierValue,
nextBenefitTierVolumeValue, nextBenefitTierVolumeValue,
nextBenefitTierEpochsValue, nextBenefitTierEpochsValue,
} = useStats({ data, program, as }); } = useStats({ data, program });
const isApplyCodePreview = useMemo( const isApplyCodePreview = useMemo(
() => data.referee === null, () => data.referee === null,
@@ -293,11 +302,27 @@ export const Statistics = ({
.reduce((all, r) => all.plus(r), new BigNumber(0)); .reduce((all, r) => all.plus(r), new BigNumber(0));
const totalCommissionTile = ( const totalCommissionTile = (
<StatTile <StatTile
title={t('totalCommission', 'Total commission (last {{count}} epochs)', {
count: details?.windowLength || DEFAULT_AGGREGATION_DAYS,
})}
description={<QUSDTooltip />}
testId="total-commission" testId="total-commission"
title={
<Trans
i18nKey="totalCommission"
defaults="Total commission (<0>last {{count}} epochs</0>)"
values={{
count: DEFAULT_AGGREGATION_DAYS,
}}
components={[
<Tooltip
key="1"
description={t(
'Depending on data node retention you may not be able see the full 30 days'
)}
>
last 30 epochs
</Tooltip>,
]}
/>
}
description={<QUSDTooltip />}
> >
{getNumberFormat(0).format(Number(totalCommissionValue))} {getNumberFormat(0).format(Number(totalCommissionValue))}
</StatTile> </StatTile>
@@ -503,12 +528,21 @@ export const RefereesTable = ({
displayName: ( displayName: (
<Trans <Trans
i18nKey="referralStatisticsCommission" i18nKey="referralStatisticsCommission"
defaults="Commission earned in <0>qUSD</0> (last {{count}} epochs)" defaults="Commission earned in <0>qUSD</0> (<1>last {{count}} epochs</1>)"
components={[
<QUSDTooltip key="0" />,
<Tooltip
key="1"
description={t(
'Depending on data node retention you may not be able see the full 30 days'
)}
>
last 30 epochs
</Tooltip>,
]}
values={{ values={{
count: count: DEFAULT_AGGREGATION_DAYS,
details?.windowLength || DEFAULT_AGGREGATION_DAYS,
}} }}
components={[<QUSDTooltip key="qusd" />]}
ns={ns} ns={ns}
/> />
), ),
+2 -2
View File
@@ -31,7 +31,7 @@ export const Tile = ({
}; };
type StatTileProps = { type StatTileProps = {
title: string; title: ReactNode;
testId?: string; testId?: string;
description?: ReactNode; description?: ReactNode;
children?: ReactNode; children?: ReactNode;
@@ -70,7 +70,7 @@ export const StatTile = ({
export const NoProgramTile = ({ title }: Pick<StatTileProps, 'title'>) => { export const NoProgramTile = ({ title }: Pick<StatTileProps, 'title'>) => {
const t = useT(); const t = useT();
return ( return (
<Tile title={title}> <Tile>
<h3 className="mb-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100 calt"> <h3 className="mb-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100 calt">
{title} {title}
</h3> </h3>
@@ -13,6 +13,7 @@ import { ViewType, useSidebar } from '../sidebar';
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler'; import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
import { useT } from '../../lib/use-t'; import { useT } from '../../lib/use-t';
import { usePersistentDepositStore } from '@vegaprotocol/deposits';
export const AccountsContainer = ({ export const AccountsContainer = ({
pinnedAsset, pinnedAsset,
@@ -25,6 +26,7 @@ export const AccountsContainer = ({
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore(); const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
const currentRouteId = useGetCurrentRouteId(); const currentRouteId = useGetCurrentRouteId();
const setViews = useSidebar((store) => store.setViews); const setViews = useSidebar((store) => store.setViews);
const setDepositAsset = usePersistentDepositStore((store) => store.saveValue);
const gridStore = useAccountStore((store) => store.gridStore); const gridStore = useAccountStore((store) => store.gridStore);
const updateGridStore = useAccountStore((store) => store.updateGridStore); const updateGridStore = useAccountStore((store) => store.updateGridStore);
@@ -55,7 +57,10 @@ export const AccountsContainer = ({
setViews({ type: ViewType.Withdraw, assetId }, currentRouteId); setViews({ type: ViewType.Withdraw, assetId }, currentRouteId);
}} }}
onClickDeposit={(assetId) => { onClickDeposit={(assetId) => {
setViews({ type: ViewType.Deposit, assetId }, currentRouteId); setViews({ type: ViewType.Deposit }, currentRouteId);
if (assetId) {
setDepositAsset({ assetId });
}
}} }}
onClickTransfer={(assetId) => { onClickTransfer={(assetId) => {
setViews({ type: ViewType.Transfer, assetId }, currentRouteId); setViews({ type: ViewType.Transfer, assetId }, currentRouteId);
+3
View File
@@ -8,15 +8,18 @@ export const Card = ({
className, className,
loading = false, loading = false,
highlight = false, highlight = false,
testId,
}: { }: {
children: ReactNode; children: ReactNode;
title: string; title: string;
className?: string; className?: string;
loading?: boolean; loading?: boolean;
highlight?: boolean; highlight?: boolean;
testId?: string;
}) => { }) => {
return ( return (
<div <div
data-testid={testId}
className={classNames( className={classNames(
'bg-vega-clight-800 dark:bg-vega-cdark-800 col-span-full p-0.5 lg:col-auto', 'bg-vega-clight-800 dark:bg-vega-cdark-800 col-span-full p-0.5 lg:col-auto',
'rounded-lg', 'rounded-lg',
@@ -0,0 +1,66 @@
import { render, screen } from '@testing-library/react';
import { ChartContainer } from './chart-container';
import { useChartSettingsStore } from './use-chart-settings';
import { useEnvironment } from '@vegaprotocol/environment';
jest.mock('@vegaprotocol/candles-chart', () => ({
...jest.requireActual('@vegaprotocol/candles-chart'),
CandlesChartContainer: ({ marketId }: { marketId: string }) => (
<div data-testid="pennant">{marketId}</div>
),
}));
jest.mock('@vegaprotocol/trading-view', () => ({
...jest.requireActual('@vegaprotocol/trading-view'),
TradingViewContainer: ({ marketId }: { marketId: string }) => (
<div data-testid="tradingview">{marketId}</div>
),
}));
describe('ChartContainer', () => {
it('renders pennant if no library path is set', () => {
useChartSettingsStore.setState({
chartlib: 'tradingview',
});
useEnvironment.setState({
CHARTING_LIBRARY_PATH: undefined,
CHARTING_LIBRARY_HASH: undefined,
});
const marketId = 'market-id';
render(<ChartContainer marketId={marketId} />);
expect(screen.getByTestId('pennant')).toHaveTextContent(marketId);
});
it('renders trading view if library path is set', () => {
useChartSettingsStore.setState({
chartlib: 'tradingview',
});
useEnvironment.setState({
CHARTING_LIBRARY_PATH: 'dummy-path',
CHARTING_LIBRARY_HASH: 'hash',
});
const marketId = 'market-id';
render(<ChartContainer marketId={marketId} />);
expect(screen.getByTestId('tradingview')).toHaveTextContent(marketId);
});
it('renders pennant chart if stored in settings', () => {
useChartSettingsStore.setState({
chartlib: 'pennant',
});
const marketId = 'market-id';
render(<ChartContainer marketId={marketId} />);
expect(screen.getByTestId('pennant')).toHaveTextContent(marketId);
});
});
@@ -0,0 +1,120 @@
import invert from 'lodash/invert';
import { type Interval } from '@vegaprotocol/types';
import {
TradingViewContainer,
ALLOWED_TRADINGVIEW_HOSTNAMES,
TRADINGVIEW_INTERVAL_MAP,
} from '@vegaprotocol/trading-view';
import {
CandlesChartContainer,
PENNANT_INTERVAL_MAP,
} from '@vegaprotocol/candles-chart';
import { useEnvironment } from '@vegaprotocol/environment';
import { useChartSettings, STUDY_SIZE } from './use-chart-settings';
/**
* Renders either the pennant chart or the tradingview chart
*/
export const ChartContainer = ({ marketId }: { marketId: string }) => {
const { CHARTING_LIBRARY_PATH, CHARTING_LIBRARY_HASH } = useEnvironment();
const {
chartlib,
interval,
chartType,
overlays,
studies,
studySizes,
tradingViewStudies,
setInterval,
setStudies,
setStudySizes,
setOverlays,
setTradingViewStudies,
} = useChartSettings();
const pennantChart = (
<CandlesChartContainer
marketId={marketId}
interval={toPennantInterval(interval)}
chartType={chartType}
overlays={overlays}
studies={studies}
studySizes={studySizes}
setStudySizes={setStudySizes}
setStudies={setStudies}
setOverlays={setOverlays}
defaultStudySize={STUDY_SIZE}
/>
);
if (!ALLOWED_TRADINGVIEW_HOSTNAMES.includes(window.location.hostname)) {
return pennantChart;
}
if (!CHARTING_LIBRARY_PATH || !CHARTING_LIBRARY_HASH) {
return pennantChart;
}
switch (chartlib) {
case 'tradingview': {
return (
<TradingViewContainer
libraryPath={CHARTING_LIBRARY_PATH}
libraryHash={CHARTING_LIBRARY_HASH}
marketId={marketId}
interval={toTradingViewResolution(interval)}
studies={tradingViewStudies}
onIntervalChange={(newInterval) => {
setInterval(fromTradingViewResolution(newInterval));
}}
onAutoSaveNeeded={(data: { studies: string[] }) => {
setTradingViewStudies(data.studies);
}}
/>
);
}
case 'pennant': {
return pennantChart;
}
default: {
throw new Error('invalid chart lib');
}
}
};
const toTradingViewResolution = (interval: Interval) => {
const resolution = TRADINGVIEW_INTERVAL_MAP[interval];
if (!resolution) {
throw new Error(
`failed to convert interval: ${interval} to valid resolution`
);
}
return resolution;
};
const fromTradingViewResolution = (resolution: string) => {
const interval = invert(TRADINGVIEW_INTERVAL_MAP)[resolution];
if (!interval) {
throw new Error(
`failed to convert resolution: ${resolution} to valid interval`
);
}
return interval as Interval;
};
const toPennantInterval = (interval: Interval) => {
const pennantInterval = PENNANT_INTERVAL_MAP[interval];
if (!pennantInterval) {
throw new Error(
`failed to convert interval: ${interval} to valid pennant interval`
);
}
return pennantInterval;
};
@@ -0,0 +1,140 @@
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ChartMenu } from './chart-menu';
import {
useChartSettingsStore,
DEFAULT_CHART_SETTINGS,
} from './use-chart-settings';
import { Overlay, Study, overlayLabels, studyLabels } from 'pennant';
import { useEnvironment } from '@vegaprotocol/environment';
describe('ChartMenu', () => {
it('doesnt show trading view option if library path undefined', () => {
useEnvironment.setState({ CHARTING_LIBRARY_PATH: undefined });
render(<ChartMenu />);
expect(
screen.queryByRole('button', { name: 'TradingView' })
).not.toBeInTheDocument();
expect(
screen.queryByRole('button', { name: 'Vega chart' })
).not.toBeInTheDocument();
});
it('can switch between charts if library path', async () => {
useEnvironment.setState({ CHARTING_LIBRARY_PATH: 'dummy' });
render(<ChartMenu />);
await userEvent.click(screen.getByRole('button', { name: 'TradingView' }));
expect(useChartSettingsStore.getState().chartlib).toEqual('tradingview');
await userEvent.click(screen.getByRole('button', { name: 'Vega chart' }));
expect(useChartSettingsStore.getState().chartlib).toEqual('pennant');
});
describe('tradingview', () => {
beforeEach(() => {
useEnvironment.setState({ CHARTING_LIBRARY_PATH: 'dummy-path' });
// clear store each time to avoid conditional testing of defaults
useChartSettingsStore.setState({
chartlib: 'tradingview',
});
});
it('only shows chartlib switch and attribution', () => {
render(<ChartMenu />);
const buttons = screen.getAllByRole('button');
expect(buttons).toHaveLength(1);
expect(buttons[0]).toHaveTextContent('Vega chart');
expect(screen.getByText('Chart by')).toBeInTheDocument();
});
});
describe('pennant', () => {
const openDropdown = async () => {
await userEvent.click(
screen.getByRole('button', {
name: 'Indicators',
})
);
};
beforeEach(() => {
// clear store each time to avoid conditional testing of defaults
useChartSettingsStore.setState({
chartlib: 'pennant',
overlays: [],
studies: [],
});
});
it.each(Object.values(Overlay))('can set %s overlay', async (overlay) => {
render(<ChartMenu />);
await openDropdown();
const menu = within(await screen.findByRole('menu'));
await userEvent.click(menu.getByText(overlayLabels[overlay as Overlay]));
// re-open the dropdown
await openDropdown();
expect(
screen.getByText(overlayLabels[overlay as Overlay])
).toHaveAttribute('data-state', 'checked');
});
it.each(Object.values(Study))('can set %s study', async (study) => {
render(<ChartMenu />);
await openDropdown();
const menu = within(await screen.findByRole('menu'));
await userEvent.click(menu.getByText(studyLabels[study as Study]));
// re-open the dropdown
await openDropdown();
expect(screen.getByText(studyLabels[study as Study])).toHaveAttribute(
'data-state',
'checked'
);
});
it('should render with the correct default studies and overlays', async () => {
useChartSettingsStore.setState({
...DEFAULT_CHART_SETTINGS,
chartlib: 'pennant',
});
render(<ChartMenu />);
await userEvent.click(
screen.getByRole('button', {
name: 'Indicators',
})
);
const menu = within(await screen.findByRole('menu'));
expect(menu.getByText(studyLabels.volume)).toHaveAttribute(
'data-state',
'checked'
);
expect(menu.getByText(studyLabels.macd)).toHaveAttribute(
'data-state',
'checked'
);
expect(menu.getByText(overlayLabels.movingAverage)).toHaveAttribute(
'data-state',
'checked'
);
});
});
});
@@ -1,14 +1,12 @@
import 'pennant/dist/style.css';
import { import {
ChartType, ChartType,
Interval,
Overlay, Overlay,
Study, Study,
chartTypeLabels, chartTypeLabels,
intervalLabels,
overlayLabels, overlayLabels,
studyLabels, studyLabels,
} from 'pennant'; } from 'pennant';
import { Trans } from 'react-i18next';
import { import {
TradingButton, TradingButton,
TradingDropdown, TradingDropdown,
@@ -20,10 +18,21 @@ import {
TradingDropdownTrigger, TradingDropdownTrigger,
Icon, Icon,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import { type IconName } from '@blueprintjs/icons'; import { Interval } from '@vegaprotocol/types';
import { IconNames } from '@blueprintjs/icons'; import { useEnvironment } from '@vegaprotocol/environment';
import { useCandlesChartSettings } from './use-candles-chart-settings'; import { ALLOWED_TRADINGVIEW_HOSTNAMES } from '@vegaprotocol/trading-view';
import { useT } from './use-t'; import { IconNames, type IconName } from '@blueprintjs/icons';
import { useChartSettings } from './use-chart-settings';
import { useT } from '../../lib/use-t';
const INTERVALS = [
Interval.INTERVAL_I1M,
Interval.INTERVAL_I5M,
Interval.INTERVAL_I15M,
Interval.INTERVAL_I1H,
Interval.INTERVAL_I6H,
Interval.INTERVAL_I1D,
];
const chartTypeIcon = new Map<ChartType, IconName>([ const chartTypeIcon = new Map<ChartType, IconName>([
[ChartType.AREA, IconNames.TIMELINE_AREA_CHART], [ChartType.AREA, IconNames.TIMELINE_AREA_CHART],
@@ -32,30 +41,46 @@ const chartTypeIcon = new Map<ChartType, IconName>([
[ChartType.OHLC, IconNames.WATERFALL_CHART], [ChartType.OHLC, IconNames.WATERFALL_CHART],
]); ]);
export const CandlesMenu = () => { export const ChartMenu = () => {
const { CHARTING_LIBRARY_PATH } = useEnvironment();
const { const {
chartlib,
interval, interval,
chartType, chartType,
studies, studies,
overlays, overlays,
setChartlib,
setInterval, setInterval,
setType, setType,
setStudies, setStudies,
setOverlays, setOverlays,
} = useCandlesChartSettings(); } = useChartSettings();
const t = useT(); const t = useT();
const triggerClasses = 'text-xs';
const contentAlign = 'end'; const contentAlign = 'end';
const triggerClasses = 'text-xs';
const triggerButtonProps = { size: 'extra-small' } as const; const triggerButtonProps = { size: 'extra-small' } as const;
return ( const isPennant = chartlib === 'pennant';
const commonMenuItems = (
<TradingButton
onClick={() => {
setChartlib(isPennant ? 'tradingview' : 'pennant');
}}
size="extra-small"
>
{isPennant ? 'TradingView' : t('Vega chart')}
</TradingButton>
);
const pennantMenuItems = (
<> <>
<TradingDropdown <TradingDropdown
trigger={ trigger={
<TradingDropdownTrigger className={triggerClasses}> <TradingDropdownTrigger className={triggerClasses}>
<TradingButton {...triggerButtonProps}> <TradingButton {...triggerButtonProps}>
{t('Interval: {{interval}}', { {t('Interval: {{interval}}', {
interval: intervalLabels[interval], interval: t(interval),
})} })}
</TradingButton> </TradingButton>
</TradingDropdownTrigger> </TradingDropdownTrigger>
@@ -68,13 +93,13 @@ export const CandlesMenu = () => {
setInterval(value as Interval); setInterval(value as Interval);
}} }}
> >
{Object.values(Interval).map((timeInterval) => ( {INTERVALS.map((timeInterval) => (
<TradingDropdownRadioItem <TradingDropdownRadioItem
key={timeInterval} key={timeInterval}
inset inset
value={timeInterval} value={timeInterval}
> >
{intervalLabels[timeInterval]} {t(timeInterval)}
<TradingDropdownItemIndicator /> <TradingDropdownItemIndicator />
</TradingDropdownRadioItem> </TradingDropdownRadioItem>
))} ))}
@@ -158,4 +183,50 @@ export const CandlesMenu = () => {
</TradingDropdown> </TradingDropdown>
</> </>
); );
const tradingViewMenuItems = (
<p className="text-xs mr-2 whitespace-nowrap">
<Trans
i18nKey="Chart by <0>TradingView</0>"
components={[
// eslint-disable-next-line
<a
className="underline"
target="_blank"
href="https://www.tradingview.com"
/>,
]}
/>
</p>
);
if (!ALLOWED_TRADINGVIEW_HOSTNAMES.includes(window.location.hostname)) {
return pennantMenuItems;
}
if (!CHARTING_LIBRARY_PATH) {
return pennantMenuItems;
}
switch (chartlib) {
case 'tradingview': {
return (
<>
{tradingViewMenuItems}
{commonMenuItems}
</>
);
}
case 'pennant': {
return (
<>
{pennantMenuItems}
{commonMenuItems}
</>
);
}
default: {
throw new Error('invalid chart lib');
}
}
}; };
@@ -0,0 +1,2 @@
export { ChartContainer } from './chart-container';
export { ChartMenu } from './chart-menu';
@@ -1,18 +1,23 @@
import { getValidItem, getValidSubset } from '@vegaprotocol/react-helpers'; import { ChartType, Overlay, Study } from 'pennant';
import { ChartType, Interval, Study } from 'pennant';
import { Overlay } from 'pennant';
import { create } from 'zustand'; import { create } from 'zustand';
import { persist } from 'zustand/middleware'; import { persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer'; import { immer } from 'zustand/middleware/immer';
import { Interval } from '@vegaprotocol/types';
import { getValidItem, getValidSubset } from '@vegaprotocol/react-helpers';
type StudySizes = { [S in Study]?: number }; type StudySizes = { [S in Study]?: number };
export type Chartlib = 'pennant' | 'tradingview';
interface StoredSettings { interface StoredSettings {
chartlib: Chartlib;
// For interval we use the enum from @vegaprotocol/types, this is to make mapping between different
// chart types easier and more consistent
interval: Interval; interval: Interval;
type: ChartType; type: ChartType;
overlays: Overlay[]; overlays: Overlay[];
studies: Study[]; studies: Study[];
studySizes: StudySizes; studySizes: StudySizes;
tradingViewStudies: string[];
} }
export const STUDY_SIZE = 90; export const STUDY_SIZE = 90;
@@ -25,20 +30,24 @@ const STUDY_ORDER: Study[] = [
]; ];
export const DEFAULT_CHART_SETTINGS = { export const DEFAULT_CHART_SETTINGS = {
interval: Interval.I15M, chartlib: 'pennant' as const,
interval: Interval.INTERVAL_I15M,
type: ChartType.CANDLE, type: ChartType.CANDLE,
overlays: [Overlay.MOVING_AVERAGE], overlays: [Overlay.MOVING_AVERAGE],
studies: [Study.MACD, Study.VOLUME], studies: [Study.MACD, Study.VOLUME],
studySizes: {}, studySizes: {},
tradingViewStudies: ['Volume'],
}; };
export const useCandlesChartSettingsStore = create< export const useChartSettingsStore = create<
StoredSettings & { StoredSettings & {
setType: (type: ChartType) => void; setType: (type: ChartType) => void;
setInterval: (interval: Interval) => void; setInterval: (interval: Interval) => void;
setOverlays: (overlays?: Overlay[]) => void; setOverlays: (overlays?: Overlay[]) => void;
setStudies: (studies?: Study[]) => void; setStudies: (studies?: Study[]) => void;
setStudySizes: (sizes: number[]) => void; setStudySizes: (sizes: number[]) => void;
setChartlib: (lib: Chartlib) => void;
setTradingViewStudies: (studies: string[]) => void;
} }
>()( >()(
persist( persist(
@@ -81,6 +90,16 @@ export const useCandlesChartSettingsStore = create<
}); });
}); });
}, },
setChartlib: (lib) => {
set((state) => {
state.chartlib = lib;
});
},
setTradingViewStudies: (studies: string[]) => {
set((state) => {
state.tradingViewStudies = studies;
});
},
})), })),
{ {
name: 'vega_candles_chart_store', name: 'vega_candles_chart_store',
@@ -88,13 +107,13 @@ export const useCandlesChartSettingsStore = create<
) )
); );
export const useCandlesChartSettings = () => { export const useChartSettings = () => {
const settings = useCandlesChartSettingsStore(); const settings = useChartSettingsStore();
const interval: Interval = getValidItem( const interval: Interval = getValidItem(
settings.interval, settings.interval,
Object.values(Interval), Object.values(Interval),
Interval.I15M Interval.INTERVAL_I15M
); );
const chartType: ChartType = getValidItem( const chartType: ChartType = getValidItem(
@@ -122,15 +141,19 @@ export const useCandlesChartSettings = () => {
}); });
return { return {
chartlib: settings.chartlib,
interval, interval,
chartType, chartType,
overlays, overlays,
studies, studies,
studySizes, studySizes,
tradingViewStudies: settings.tradingViewStudies,
setInterval: settings.setInterval, setInterval: settings.setInterval,
setType: settings.setType, setType: settings.setType,
setStudies: settings.setStudies, setStudies: settings.setStudies,
setOverlays: settings.setOverlays, setOverlays: settings.setOverlays,
setStudySizes: settings.setStudySizes, setStudySizes: settings.setStudySizes,
setChartlib: settings.setChartlib,
setTradingViewStudies: settings.setTradingViewStudies,
}; };
}; };
@@ -84,7 +84,10 @@ export const FeesContainer = () => {
); );
return ( return (
<div className="grid auto-rows-min grid-cols-4 gap-3"> <div
className="grid auto-rows-min grid-cols-4 gap-3"
data-testid="fees-container"
>
{isConnected && ( {isConnected && (
<> <>
<Card <Card
@@ -124,7 +127,10 @@ export const FeesContainer = () => {
windowLength={volumeDiscountWindowLength} windowLength={volumeDiscountWindowLength}
/> />
) : ( ) : (
<p className="text-muted pt-3 text-sm"> <p
className="text-muted pt-3 text-sm"
data-testid="no-volume-discount"
>
{t('No volume discount program active')} {t('No volume discount program active')}
</p> </p>
)} )}
@@ -133,17 +139,22 @@ export const FeesContainer = () => {
title={t('Referral benefits')} title={t('Referral benefits')}
className="sm:col-span-2" className="sm:col-span-2"
loading={loading} loading={loading}
data-testid="referral-benefits-card"
> >
{isReferrer ? ( {isReferrer ? (
<ReferrerInfo code={code} /> <ReferrerInfo code={code} data-testid="referrer-info" />
) : isReferralProgramRunning ? ( ) : isReferralProgramRunning ? (
<ReferralBenefits <ReferralBenefits
setRunningNotionalTakerVolume={referralVolumeInWindow} setRunningNotionalTakerVolume={referralVolumeInWindow}
epochsInSet={epochsInSet} epochsInSet={epochsInSet}
epochs={referralDiscountWindowLength} epochs={referralDiscountWindowLength}
data-testid="referral-benefits"
/> />
) : ( ) : (
<p className="text-muted pt-3 text-sm"> <p
className="text-muted pt-3 text-sm"
data-testid="no-referral-program"
>
{t('No referral program active')} {t('No referral program active')}
</p> </p>
)} )}
@@ -154,6 +165,7 @@ export const FeesContainer = () => {
title={t('Volume discount')} title={t('Volume discount')}
className="lg:col-span-full xl:col-span-2" className="lg:col-span-full xl:col-span-2"
loading={loading} loading={loading}
data-testid="volume-discount-card"
> >
<VolumeTiers <VolumeTiers
tiers={volumeTiers} tiers={volumeTiers}
@@ -166,6 +178,7 @@ export const FeesContainer = () => {
title={t('Referral discount')} title={t('Referral discount')}
className="lg:col-span-full xl:col-span-2" className="lg:col-span-full xl:col-span-2"
loading={loading} loading={loading}
data-testid="referral-discount-card"
> >
<ReferralTiers <ReferralTiers
tiers={referralTiers} tiers={referralTiers}
@@ -178,6 +191,7 @@ export const FeesContainer = () => {
title={t('Fees by market')} title={t('Fees by market')}
className="lg:col-span-full" className="lg:col-span-full"
loading={marketsLoading} loading={marketsLoading}
data-testid="fees-by-market-card"
> >
<MarketFees <MarketFees
markets={markets} markets={markets}
@@ -245,7 +259,7 @@ export const TradingFees = ({
} }
return ( return (
<div className="pt-4"> <div className="pt-4" data-testid="trading-fees">
<div className="leading-none"> <div className="leading-none">
<p className="block text-3xl leading-none" data-testid="adjusted-fees"> <p className="block text-3xl leading-none" data-testid="adjusted-fees">
{minAdjustedTotal !== undefined && maxAdjustedTotal !== undefined {minAdjustedTotal !== undefined && maxAdjustedTotal !== undefined
@@ -255,7 +269,7 @@ export const TradingFees = ({
: `${formatPercentage(adjustedTotal)}%`} : `${formatPercentage(adjustedTotal)}%`}
</p> </p>
<CardTable> <CardTable>
<tr className="text-default"> <tr className="text-default" data-testid="total-fee-before-discount">
<CardTableTH>{t('Total fee before discount')}</CardTableTH> <CardTableTH>{t('Total fee before discount')}</CardTableTH>
<CardTableTD> <CardTableTD>
{minTotal !== undefined && maxTotal !== undefined {minTotal !== undefined && maxTotal !== undefined
@@ -265,7 +279,7 @@ export const TradingFees = ({
: `${formatPercentage(total.toNumber())}%`} : `${formatPercentage(total.toNumber())}%`}
</CardTableTD> </CardTableTD>
</tr> </tr>
<tr> <tr data-testid="infrastructure-fees">
<CardTableTH>{t('Infrastructure')}</CardTableTH> <CardTableTH>{t('Infrastructure')}</CardTableTH>
<CardTableTD> <CardTableTD>
{formatPercentage( {formatPercentage(
@@ -274,14 +288,14 @@ export const TradingFees = ({
% %
</CardTableTD> </CardTableTD>
</tr> </tr>
<tr> <tr data-testid="maker-fees">
<CardTableTH>{t('Maker')}</CardTableTH> <CardTableTH>{t('Maker')}</CardTableTH>
<CardTableTD> <CardTableTD>
{formatPercentage(Number(params.market_fee_factors_makerFee))}% {formatPercentage(Number(params.market_fee_factors_makerFee))}%
</CardTableTD> </CardTableTD>
</tr> </tr>
{minLiq && maxLiq && ( {minLiq && maxLiq && (
<tr> <tr data-testid="liquidity-fees">
<CardTableTH>{t('Liquidity')}</CardTableTH> <CardTableTH>{t('Liquidity')}</CardTableTH>
<CardTableTD> <CardTableTD>
{formatPercentage(Number(minLiq.fees.factors.liquidityFee))}% {formatPercentage(Number(minLiq.fees.factors.liquidityFee))}%
@@ -317,21 +331,19 @@ export const CurrentVolume = ({
const currentVolume = new BigNumber(windowLengthVolume); const currentVolume = new BigNumber(windowLengthVolume);
return ( return (
<div className="flex flex-col gap-3 pt-4"> <div className="flex flex-col gap-3 pt-4" data-testid="current-volume">
<CardStat <CardStat
value={ value={formatNumberRounded(currentVolume)}
currentVolume.isZero()
? `<${formatNumberRounded(requiredForNextTier)}`
: formatNumberRounded(currentVolume)
}
text={t('pastEpochs', 'Past {{count}} epochs', { text={t('pastEpochs', 'Past {{count}} epochs', {
count: windowLength, count: windowLength,
})} })}
testId="past-epochs-volume"
/> />
{requiredForNextTier.isGreaterThan(0) && ( {requiredForNextTier.isGreaterThan(0) && (
<CardStat <CardStat
value={formatNumber(requiredForNextTier)} value={formatNumber(requiredForNextTier)}
text={t('Required for next tier')} text={t('Required for next tier')}
testId="required-for-next-tier"
/> />
)} )}
</div> </div>
@@ -349,7 +361,7 @@ const ReferralBenefits = ({
}) => { }) => {
const t = useT(); const t = useT();
return ( return (
<div className="flex flex-col gap-3 pt-4"> <div className="flex flex-col gap-3 pt-4" data-testid="referral-benefits">
<CardStat <CardStat
// all sets volume (not just current party) // all sets volume (not just current party)
value={formatNumber(setRunningNotionalTakerVolume)} value={formatNumber(setRunningNotionalTakerVolume)}
@@ -360,8 +372,13 @@ const ReferralBenefits = ({
count: epochs, count: epochs,
} }
)} )}
testId="running-notional-taker-volume"
/>
<CardStat
value={epochsInSet}
text={t('epochs in referral set')}
testId="epochs-in-referral-set"
/> />
<CardStat value={epochsInSet} text={t('epochs in referral set')} />
</div> </div>
); );
}; };
@@ -389,7 +406,7 @@ const TotalDiscount = ({
); );
return ( return (
<div className="pt-4"> <div className="pt-4" data-testid="total-discount-card-stats">
<CardStat <CardStat
description={ description={
<> <>
@@ -399,9 +416,10 @@ const TotalDiscount = ({
} }
value={formatPercentage(totalDiscount) + '%'} value={formatPercentage(totalDiscount) + '%'}
highlight={true} highlight={true}
testId="total-discount"
/> />
<CardTable> <CardTable>
<tr> <tr data-testid="volume-discount-row">
<CardTableTH>{t('Volume discount')}</CardTableTH> <CardTableTH>{t('Volume discount')}</CardTableTH>
<CardTableTD> <CardTableTD>
{formatPercentage(volumeDiscount)}% {formatPercentage(volumeDiscount)}%
@@ -415,7 +433,7 @@ const TotalDiscount = ({
)} )}
</CardTableTD> </CardTableTD>
</tr> </tr>
<tr> <tr data-testid="referral-discount-row">
<CardTableTH>{t('Referral discount')}</CardTableTH> <CardTableTH>{t('Referral discount')}</CardTableTH>
<CardTableTD> <CardTableTD>
{formatPercentage(referralDiscount)}% {formatPercentage(referralDiscount)}%
@@ -461,29 +479,37 @@ const VolumeTiers = ({
<div> <div>
<Table> <Table>
<THead> <THead>
<tr> <Tr>
<Th>{t('Tier')}</Th> <Th data-testid="tier-header">{t('Tier')}</Th>
<Th>{t('Discount')}</Th> <Th data-testid="discount-header">{t('Discount')}</Th>
<Th>{t('Min. trading volume')}</Th> <Th data-testid="min-volume-header">{t('Min. trading volume')}</Th>
<Th> <Th data-testid="my-volume-header">
{t('myVolume', 'My volume (last {{count}} epochs)', { {t('myVolume', 'My volume (last {{count}} epochs)', {
count: windowLength, count: windowLength,
})} })}
</Th> </Th>
<Th /> <Th data-testid="actions-header" />
</tr> </Tr>
</THead> </THead>
<tbody> <tbody>
{Array.from(tiers).map((tier, i) => { {Array.from(tiers).map((tier, i) => {
const isUserTier = tierIndex === i; const isUserTier = tierIndex === i;
return ( return (
<Tr key={i}> <Tr key={i} data-testid={`tier-row-${i}`}>
<Td>{i + 1}</Td> <Td data-testid={`tier-value-${i}`}>{i + 1}</Td>
<Td>{formatPercentage(Number(tier.volumeDiscountFactor))}%</Td> <Td data-testid={`discount-value-${i}`}>
<Td>{formatNumber(tier.minimumRunningNotionalTakerVolume)}</Td> {formatPercentage(Number(tier.volumeDiscountFactor))}%
<Td>{isUserTier ? formatNumber(lastEpochVolume) : ''}</Td> </Td>
<Td>{isUserTier ? <YourTier /> : null}</Td> <Td data-testid={`min-volume-value-${i}`}>
{formatNumber(tier.minimumRunningNotionalTakerVolume)}
</Td>
<Td data-testid={`my-volume-value-${i}`}>
{isUserTier ? formatNumber(lastEpochVolume) : ''}
</Td>
<Td data-testid={`your-tier-${i}`}>
{isUserTier ? <YourTier /> : null}
</Td>
</Tr> </Tr>
); );
})} })}
@@ -520,39 +546,53 @@ const ReferralTiers = ({
<div> <div>
<Table> <Table>
<THead> <THead>
<tr> <Tr>
<Th>{t('Tier')}</Th> <Th data-testid="tier-header">{t('Tier')}</Th>
<Th>{t('Discount')}</Th> <Th data-testid="discount-header">{t('Discount')}</Th>
<Th>{t('Min. trading volume')}</Th> <Th data-testid="min-volume-header">{t('Min. trading volume')}</Th>
<Th>{t('Required epochs')}</Th> <Th data-testid="required-epochs-header">{t('Required epochs')}</Th>
<Th /> <Th data-testid="extra-header" />
</tr> </Tr>
</THead> </THead>
<tbody> <tbody>
{Array.from(tiers).map((t, i) => { {Array.from(tiers).map((tier, i) => {
const isUserTier = tierIndex === i; const isUserTier = tierIndex === i;
const requiredVolume = Number(t.minimumRunningNotionalTakerVolume); const requiredVolume = Number(
tier.minimumRunningNotionalTakerVolume
);
let unlocksIn = null; let unlocksIn = null;
if ( if (
referralVolumeInWindow >= requiredVolume && referralVolumeInWindow >= requiredVolume &&
epochsInSet < t.minimumEpochs epochsInSet < tier.minimumEpochs
) { ) {
unlocksIn = ( unlocksIn = (
<span className="text-muted"> <span className="text-muted">
Unlocks in {t.minimumEpochs - epochsInSet} epochs Unlocks in {tier.minimumEpochs - epochsInSet} epochs
</span> </span>
); );
} }
return ( return (
<Tr key={i}> <Tr key={i} data-testid={`tier-row-${i}`}>
<Td>{i + 1}</Td> <Td data-testid={`tier-value-${i}`}>{i + 1}</Td>
<Td>{formatPercentage(Number(t.referralDiscountFactor))}%</Td> <Td data-testid={`discount-value-${i}`}>
<Td>{formatNumber(t.minimumRunningNotionalTakerVolume)}</Td> {formatPercentage(Number(tier.referralDiscountFactor))}%
<Td>{t.minimumEpochs}</Td> </Td>
<Td>{isUserTier ? <YourTier /> : unlocksIn}</Td> <Td data-testid={`min-volume-value-${i}`}>
{formatNumber(tier.minimumRunningNotionalTakerVolume)}
</Td>
<Td data-testid={`required-epochs-value-${i}`}>
{tier.minimumEpochs}
</Td>
<Td data-testid={`user-tier-or-unlocks-${i}`}>
{isUserTier ? (
<YourTier testId={`your-tier-${i}`} />
) : (
unlocksIn
)}
</Td>
</Tr> </Tr>
); );
})} })}
@@ -562,11 +602,18 @@ const ReferralTiers = ({
); );
}; };
const YourTier = () => { interface YourTierProps {
testId?: string;
}
const YourTier = ({ testId }: YourTierProps) => {
const t = useT(); const t = useT();
return ( return (
<span className="bg-rainbow whitespace-nowrap rounded-xl px-4 py-1.5 text-white"> <span
className="bg-rainbow whitespace-nowrap rounded-xl px-4 py-1.5 text-white"
data-testid={testId}
>
{t('Your tier')} {t('Your tier')}
</span> </span>
); );
@@ -3,21 +3,31 @@ import type { ReactNode } from 'react';
const cellClass = 'px-4 py-2 text-xs font-normal text-left last:text-right'; const cellClass = 'px-4 py-2 text-xs font-normal text-left last:text-right';
export const Th = ({ children }: { children?: ReactNode }) => { export const Th = ({ children, ...props }: { children?: ReactNode }) => {
return ( return (
<th className={classNames(cellClass, 'text-secondary leading-none py-3')}> <th
className={classNames(cellClass, 'text-secondary leading-none py-3')}
{...props}
>
{children} {children}
</th> </th>
); );
}; };
export const Td = ({ children }: { children?: ReactNode }) => { export const Td = ({ children, ...props }: { children?: ReactNode }) => {
return <th className={cellClass}>{children}</th>; return (
<th className={cellClass} {...props}>
{children}
</th>
);
}; };
export const Tr = ({ children }: { children?: ReactNode }) => { export const Tr = ({ children, ...props }: { children?: ReactNode }) => {
return ( return (
<tr className="hover:bg-vega-clight-600 dark:hover:bg-vega-cdark-700"> <tr
className="hover:bg-vega-clight-600 dark:hover:bg-vega-cdark-700"
{...props}
>
{children} {children}
</tr> </tr>
); );
@@ -5,7 +5,7 @@ import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { VegaWalletContext } from '@vegaprotocol/wallet'; import { VegaWalletContext } from '@vegaprotocol/wallet';
import { Navbar } from './navbar'; import { Navbar } from './navbar';
import { useGlobalStore } from '../../stores'; import { useGlobalStore } from '../../stores';
import { ENV, FLAGS } from '@vegaprotocol/environment'; import { ENV, useFeatureFlags } from '@vegaprotocol/environment';
jest.mock('@vegaprotocol/proposals', () => ({ jest.mock('@vegaprotocol/proposals', () => ({
ProtocolUpgradeCountdown: () => null, ProtocolUpgradeCountdown: () => null,
@@ -48,8 +48,7 @@ describe('Navbar', () => {
beforeAll(() => { beforeAll(() => {
useGlobalStore.setState({ marketId }); useGlobalStore.setState({ marketId });
const mockedFLAGS = jest.mocked(FLAGS); useFeatureFlags.setState({ flags: { REFERRALS: true } });
mockedFLAGS.REFERRALS = true;
const mockedENV = jest.mocked(ENV); const mockedENV = jest.mocked(ENV);
mockedENV.VEGA_TOKEN_URL = 'governance'; mockedENV.VEGA_TOKEN_URL = 'governance';
}); });
+3 -2
View File
@@ -6,7 +6,7 @@ import {
Networks, Networks,
DApp, DApp,
useLinks, useLinks,
FLAGS, useFeatureFlags,
useEnvNameMapping, useEnvNameMapping,
} from '@vegaprotocol/environment'; } from '@vegaprotocol/environment';
import { useGlobalStore } from '../../stores'; import { useGlobalStore } from '../../stores';
@@ -157,6 +157,7 @@ export const Navbar = ({
* of the navigation * of the navigation
*/ */
const NavbarMenu = ({ onClick }: { onClick: () => void }) => { const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
const featureFlags = useFeatureFlags((state) => state.flags);
const t = useT(); const t = useT();
const envNameMapping = useEnvNameMapping(); const envNameMapping = useEnvNameMapping();
const { VEGA_ENV, VEGA_NETWORKS, GITHUB_FEEDBACK_URL } = useEnvironment(); const { VEGA_ENV, VEGA_NETWORKS, GITHUB_FEEDBACK_URL } = useEnvironment();
@@ -201,7 +202,7 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
{t('Portfolio')} {t('Portfolio')}
</NavbarLink> </NavbarLink>
</NavbarItem> </NavbarItem>
{FLAGS.REFERRALS && ( {featureFlags.REFERRALS && (
<NavbarItem> <NavbarItem>
<NavbarLink end={false} to={Links.REFERRALS()} onClick={onClick}> <NavbarLink end={false} to={Links.REFERRALS()} onClick={onClick}>
{t('Referrals')} {t('Referrals')}
@@ -69,11 +69,13 @@ describe('RewardPot', () => {
balance: '100', balance: '100',
asset: rewardAsset, asset: rewardAsset,
}, },
// should include this in total:
{ {
type: AccountType.ACCOUNT_TYPE_VESTED_REWARDS, type: AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
balance: '100', balance: '100',
asset: rewardAsset, asset: rewardAsset,
}, },
// should include this in total:
{ {
type: AccountType.ACCOUNT_TYPE_VESTED_REWARDS, type: AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
balance: '50', balance: '50',
@@ -138,20 +140,20 @@ describe('RewardPot', () => {
renderComponent(props); renderComponent(props);
expect(screen.getByTestId('total-rewards')).toHaveTextContent(
`7.00 ${rewardAsset.symbol}`
);
expect(screen.getByText(/Locked/).nextElementSibling).toHaveTextContent( expect(screen.getByText(/Locked/).nextElementSibling).toHaveTextContent(
'2.50' '2.50'
); );
expect(screen.getByText(/Vesting/).nextElementSibling).toHaveTextContent( expect(screen.getByText(/Vesting/).nextElementSibling).toHaveTextContent(
'4.50' '4.50'
); );
expect( expect(
screen.getByText(/Available to withdraw/).nextElementSibling screen.getByText(/Available to withdraw/).nextElementSibling
).toHaveTextContent('1.50'); ).toHaveTextContent('1.50');
// should be sum of the above
expect(screen.getByTestId('total-rewards')).toHaveTextContent(
`8.50 ${rewardAsset.symbol}`
);
}); });
}); });
@@ -62,6 +62,10 @@ export const RewardsContainer = () => {
}, },
// Inclusion of activity streak in query currently fails // Inclusion of activity streak in query currently fails
errorPolicy: 'ignore', errorPolicy: 'ignore',
// polling here so that as rewards are are moved to ACCOUNT_TYPE_VESTED_REWARDS the vesting stats information stays
// almost up to sync with accounts updating from subscriptions. There is a chance the data could be out
// of sync for 10s if you happen to be on the page at the end of an epoch
pollInterval: 10000,
}); });
if (!epochData?.epoch || !assetMap) return null; if (!epochData?.epoch || !assetMap) return null;
@@ -295,7 +299,9 @@ export const RewardPot = ({
: [0]; : [0];
const totalVesting = BigNumber.sum.apply(null, vestingBalances); const totalVesting = BigNumber.sum.apply(null, vestingBalances);
const totalRewards = totalLocked.plus(totalVesting); const totalRewards = totalLocked
.plus(totalVesting)
.plus(totalVestedRewardsByRewardAsset);
let rewardAsset = undefined; let rewardAsset = undefined;
+13 -1
View File
@@ -10,6 +10,18 @@ import { useTelemetryApproval } from '../../lib/hooks/use-telemetry-approval';
import { useState, type ReactNode } from 'react'; import { useState, type ReactNode } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { useT } from '../../lib/use-t'; import { useT } from '../../lib/use-t';
import { useFeatureFlags, type FeatureFlags } from '@vegaprotocol/environment';
export const FeatureFlagSwitch = ({ flag }: { flag: keyof FeatureFlags }) => {
const flags = useFeatureFlags((state) => state.flags);
const setFeatureFlag = useFeatureFlags((state) => state.setFeatureFlag);
return (
<Switch
onCheckedChange={(checked) => setFeatureFlag(flag, !!checked)}
checked={flags[flag]}
/>
);
};
export const Settings = () => { export const Settings = () => {
const t = useT(); const t = useT();
@@ -120,7 +132,7 @@ const SettingsGroup = ({
})} })}
> >
<div className={classNames({ 'w-3/4': inline, 'mb-2': !inline })}> <div className={classNames({ 'w-3/4': inline, 'mb-2': !inline })}>
<label className="text-sm">{label}</label> <div className="text-sm">{label}</div>
{helpText && <p className="text-xs text-muted">{helpText}</p>} {helpText && <p className="text-xs text-muted">{helpText}</p>}
</div> </div>
{children} {children}
@@ -24,7 +24,13 @@ import classNames from 'classnames';
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
import { useT } from '../../lib/use-t'; import { useT } from '../../lib/use-t';
export const VegaWalletConnectButton = () => { export const VegaWalletConnectButton = ({
intent = Intent.None,
onClick,
}: {
intent?: Intent;
onClick?: () => void;
}) => {
const t = useT(); const t = useT();
const [dropdownOpen, setDropdownOpen] = useState(false); const [dropdownOpen, setDropdownOpen] = useState(false);
const openVegaWalletDialog = useVegaWalletDialogStore( const openVegaWalletDialog = useVegaWalletDialogStore(
@@ -117,9 +123,12 @@ export const VegaWalletConnectButton = () => {
return ( return (
<Button <Button
data-testid="connect-vega-wallet" data-testid="connect-vega-wallet"
onClick={openVegaWalletDialog} onClick={() => {
onClick?.();
openVegaWalletDialog();
}}
size="small" size="small"
intent={Intent.None} intent={intent}
icon={<VegaIcon name={VegaIconNames.ARROW_RIGHT} size={14} />} icon={<VegaIcon name={VegaIconNames.ARROW_RIGHT} size={14} />}
> >
<span className="whitespace-nowrap uppercase"> <span className="whitespace-nowrap uppercase">
@@ -3,7 +3,7 @@ import { matchPath, useLocation } from 'react-router-dom';
import { Dialog, Intent } from '@vegaprotocol/ui-toolkit'; import { Dialog, Intent } from '@vegaprotocol/ui-toolkit';
import { useEnvironment } from '@vegaprotocol/environment'; import { useEnvironment } from '@vegaprotocol/environment';
import { VegaConnectDialog } from '@vegaprotocol/wallet'; import { VegaConnectDialog } from '@vegaprotocol/wallet';
import { Connectors } from '../../lib/vega-connectors'; import { useConnectors } from '../../lib/vega-connectors';
import { useT } from '../../lib/use-t'; import { useT } from '../../lib/use-t';
import { Routes } from '../../lib/links'; import { Routes } from '../../lib/links';
import { RiskMessage } from './risk-message'; import { RiskMessage } from './risk-message';
@@ -20,6 +20,7 @@ export const WelcomeDialog = () => {
const { pathname } = useLocation(); const { pathname } = useLocation();
const t = useT(); const t = useT();
const { VEGA_ENV } = useEnvironment(); const { VEGA_ENV } = useEnvironment();
const connectors = useConnectors();
const dismissed = useOnboardingStore((store) => store.dismissed); const dismissed = useOnboardingStore((store) => store.dismissed);
const dialogOpen = useOnboardingStore((store) => store.dialogOpen); const dialogOpen = useOnboardingStore((store) => store.dialogOpen);
const dismiss = useOnboardingStore((store) => store.dismiss); const dismiss = useOnboardingStore((store) => store.dismiss);
@@ -43,7 +44,7 @@ export const WelcomeDialog = () => {
const content = walletDialogOpen ? ( const content = walletDialogOpen ? (
<VegaConnectDialog <VegaConnectDialog
connectors={Connectors} connectors={connectors}
riskMessage={<RiskMessage />} riskMessage={<RiskMessage />}
onClose={() => setWalletDialogOpen(false)} onClose={() => setWalletDialogOpen(false)}
contentOnly contentOnly
+2 -1
View File
@@ -1,2 +1,3 @@
CONSOLE_IMAGE_NAME=vegaprotocol/trading:latest CONSOLE_IMAGE_NAME=vegaprotocol/trading:latest
VEGA_VERSION=v0.73.8 VEGA_VERSION=v0.73.9
LOCAL_SERVER=false
+1 -1
View File
@@ -1,2 +1,2 @@
CONSOLE_IMAGE_NAME=vegaprotocol/trading:develop CONSOLE_IMAGE_NAME=vegaprotocol/trading:develop
VEGA_VERSION=v0.73.8 VEGA_VERSION=v0.73.9
+1
View File
@@ -1,2 +1,3 @@
CONSOLE_IMAGE_NAME=vegaprotocol/trading:main CONSOLE_IMAGE_NAME=vegaprotocol/trading:main
VEGA_VERSION=v0.73.8 VEGA_VERSION=v0.73.8
LOCAL_SERVER=false
+22 -2
View File
@@ -24,6 +24,12 @@ poetry shell
5. **Install python dependencies** 5. **Install python dependencies**
To make sure you are on the latest version of our market-sim branch.
```bash
poetry update vega-sim
```
```bash ```bash
poetry install poetry install
``` ```
@@ -87,10 +93,9 @@ docker build -f docker/node-outside-docker.Dockerfile --build-arg APP=trading --
## Running Tests 🧪 ## Running Tests 🧪
Before running make sure the docker daemon is runnign so that the app can be served. Before running make sure the docker daemon is running.
To run a specific test, use the `-k` option followed by the name of the test. To run a specific test, use the `-k` option followed by the name of the test.
Run all tests: Run all tests:
```bash ```bash
@@ -109,6 +114,21 @@ Run from anywhere:
yarn trading:test -- "test_name" -s --headed yarn trading:test -- "test_name" -s --headed
``` ```
Run using your locally served console:
Within one terminal
```bash
yarn nx build trading
```
```bash
yarn nx serve trading
```
Once console is served you can update the .env file to have local_server to true.
## Running Tests in Parallel 🔢 ## Running Tests in Parallel 🔢
To run tests in parallel, use the `--numprocesses auto` option. The `--dist loadfile` setting ensures that multiple runners are not assigned to a single test file. To run tests in parallel, use the `--numprocesses auto` option. The `--dist loadfile` setting ensures that multiple runners are not assigned to a single test file.
+3 -2
View File
@@ -55,14 +55,14 @@ def change_keys(page: Page, vega: VegaServiceNull, key_name):
page.reload() page.reload()
def forward_time(vega: VegaServiceNull, forward_epoch: bool = False): def forward_time(vega:VegaServiceNull, forward_epoch: bool = False):
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
if forward_epoch: if forward_epoch:
next_epoch(vega) next_epoch(vega)
# This is for when the element will initially load but contain an outdated value. It will wait for the element to contain the expected text, returning False after a timeout or exception # This is for when the element will initially load but contain an outdated value. It will wait for the element to contain the expected text, returning False after a timeout or exception
def selector_contains_text(page: Page, selector, expected_text, timeout=5000): def selector_contains_text(page: Page, selector, expected_text, timeout=5000):
try: try:
@@ -71,3 +71,4 @@ def selector_contains_text(page: Page, selector, expected_text, timeout=5000):
return True return True
except: except:
return False return False
+36 -22
View File
@@ -6,10 +6,10 @@ import requests
import time import time
import docker import docker
import http.server import http.server
import sys
from dotenv import load_dotenv
from contextlib import contextmanager from contextlib import contextmanager
from vega_sim.null_service import VegaServiceNull from vega_sim.null_service import VegaServiceNull, Ports
from playwright.sync_api import Browser, Page from playwright.sync_api import Browser, Page
from config import console_image_name, vega_version from config import console_image_name, vega_version
from datetime import datetime, timedelta from datetime import datetime, timedelta
@@ -20,7 +20,6 @@ from fixtures.market import (
setup_perps_market, setup_perps_market,
) )
import sys
# Workaround for current xdist issue with displaying live logs from multiple workers # Workaround for current xdist issue with displaying live logs from multiple workers
# https://github.com/pytest-dev/pytest-xdist/issues/402 # https://github.com/pytest-dev/pytest-xdist/issues/402
@@ -29,6 +28,8 @@ sys.stdout = sys.stderr
docker_client = docker.from_env() docker_client = docker.from_env()
logger = logging.getLogger() logger = logging.getLogger()
load_dotenv()
@pytest.hookimpl(tryfirst=True) @pytest.hookimpl(tryfirst=True)
def pytest_runtest_makereport(item, call): def pytest_runtest_makereport(item, call):
@@ -50,16 +51,24 @@ def pytest_configure(config):
level=config.getini("log_file_level"), level=config.getini("log_file_level"),
) )
class CustomHttpRequestHandler(http.server.SimpleHTTPRequestHandler): class CustomHttpRequestHandler(http.server.SimpleHTTPRequestHandler):
def do_GET(self): def do_GET(self):
# Set the path to your website's directory here # Set the path to your website's directory here
if self.path == '/': if self.path == "/":
self.path = 'dist/apps/trading/exported/index.html' self.path = "dist/apps/trading/exported/index.html"
return http.server.SimpleHTTPRequestHandler.do_GET(self) return http.server.SimpleHTTPRequestHandler.do_GET(self)
# Start VegaServiceNull # Start VegaServiceNull
@contextmanager @contextmanager
def init_vega(request=None): def init_vega(request=None):
local_server = os.getenv("LOCAL_SERVER", "false").lower() == "true"
port_config = None
if local_server:
port_config = {
Ports.DATA_NODE_REST: 8001,
}
default_seconds = 1 default_seconds = 1
seconds_per_block = default_seconds seconds_per_block = default_seconds
if request and hasattr(request, "param"): if request and hasattr(request, "param"):
@@ -71,21 +80,26 @@ def init_vega(request=None):
) )
logger.info(f"Using console image: {console_image_name}") logger.info(f"Using console image: {console_image_name}")
logger.info(f"Using vega version: {vega_version}") logger.info(f"Using vega version: {vega_version}")
with VegaServiceNull(
run_with_console=False, vega_service_args = {
launch_graphql=False, "run_with_console": False,
retain_log_files=True, "launch_graphql": False,
use_full_vega_wallet=True, "retain_log_files": True,
store_transactions=True, "use_full_vega_wallet": True,
transactions_per_block=1000, "store_transactions": True,
seconds_per_block=seconds_per_block, "transactions_per_block": 1000,
genesis_time= datetime.now() - timedelta(days=1), "seconds_per_block": seconds_per_block,
) as vega: "genesis_time": datetime.now() - timedelta(days=1),
}
if port_config is not None:
vega_service_args["port_config"] = port_config
with VegaServiceNull(**vega_service_args) as vega:
try: try:
container = docker_client.containers.run( container = docker_client.containers.run(
console_image_name, detach=True, ports={"80/tcp": vega.console_port} console_image_name, detach=True, ports={"80/tcp": vega.console_port}
) )
# docker setup
logger.info( logger.info(
f"Container {container.id} started", f"Container {container.id} started",
extra={"worker_id": os.environ.get("PYTEST_XDIST_WORKER")}, extra={"worker_id": os.environ.get("PYTEST_XDIST_WORKER")},
@@ -98,15 +112,17 @@ def init_vega(request=None):
finally: finally:
logger.info(f"Stopping container {container.id}") logger.info(f"Stopping container {container.id}")
container.stop() container.stop()
# Remove the container
logger.info(f"Removing container {container.id}") logger.info(f"Removing container {container.id}")
container.remove() container.remove()
@contextmanager @contextmanager
def init_page(vega: VegaServiceNull, browser: Browser, request: pytest.FixtureRequest): def init_page(vega: VegaServiceNull, browser: Browser, request: pytest.FixtureRequest):
local_server = os.getenv("LOCAL_SERVER", "false").lower() == "true"
server_port = "4200" if local_server else str(vega.console_port)
with browser.new_context( with browser.new_context(
viewport={"width": 1920, "height": 1080}, viewport={"width": 1920, "height": 1080},
base_url=f"http://localhost:{vega.console_port}", base_url=f"http://localhost:{server_port}",
) as context, context.new_page() as page: ) as context, context.new_page() as page:
context.tracing.start(screenshots=True, snapshots=True, sources=True) context.tracing.start(screenshots=True, snapshots=True, sources=True)
try: try:
@@ -114,9 +130,7 @@ def init_page(vega: VegaServiceNull, browser: Browser, request: pytest.FixtureRe
attempts = 0 attempts = 0
while attempts < 100: while attempts < 100:
try: try:
code = requests.get( code = requests.get(f"http://localhost:{server_port}/").status_code
f"http://localhost:{vega.console_port}/"
).status_code
if code == 200: if code == 200:
break break
except requests.exceptions.ConnectionError as e: except requests.exceptions.ConnectionError as e:
+8
View File
@@ -245,3 +245,11 @@ def setup_perps_market(
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
return market_id return market_id
def market_exists(vega: VegaService, market_id: str):
if market_id is None:
return False
all_markets = vega.all_markets()
market_ids = [market.id for market in all_markets]
return market_id in market_ids
+2 -2
View File
@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. # This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
[[package]] [[package]]
name = "certifi" name = "certifi"
@@ -1161,7 +1161,7 @@ profile = ["pytest-profiling", "snakeviz"]
type = "git" type = "git"
url = "https://github.com/vegaprotocol/vega-market-sim.git/" url = "https://github.com/vegaprotocol/vega-market-sim.git/"
reference = "fix/genesis_panic" reference = "fix/genesis_panic"
resolved_reference = "7ab04931924380db8000544b7f3d65fcb39b5467" resolved_reference = "de30d2d4c7a1b81a830527ca76473e23ef59de12"
[[package]] [[package]]
name = "websocket-client" name = "websocket-client"
+14 -8
View File
@@ -56,11 +56,12 @@ label_value_tooltip_pairs = [
def tooltip(page: Page, index: int, test_id: str, tooltip: str): def tooltip(page: Page, index: int, test_id: str, tooltip: str):
page.locator(f"data-testid={index}_{test_id}").hover() page.locator(f"data-testid={index}_{test_id}").hover()
expect(page.locator('[role="tooltip"]').locator("div")).to_have_text(tooltip) expect(page.locator('[role="tooltip"]').locator(
"div")).to_have_text(tooltip)
page.get_by_test_id("dialog-title").click() page.get_by_test_id("dialog-title").click()
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("continuous_market", "auth", "risk_accepted")
def test_asset_details(page: Page): def test_asset_details(page: Page):
page.goto("/#/portfolio") page.goto("/#/portfolio")
page.locator('[data-testid="tab-collateral"] >> text=tDAI').click() page.locator('[data-testid="tab-collateral"] >> text=tDAI').click()
@@ -73,17 +74,22 @@ def test_asset_details(page: Page):
value = pair.get("value", "") value = pair.get("value", "")
label_tooltip = pair.get("labelTooltip", "") label_tooltip = pair.get("labelTooltip", "")
value_tooltip = pair.get("valueToolTip", "") value_tooltip = pair.get("valueToolTip", "")
if label == "ID": if label == "ID":
expect(page.get_by_role("button", name="Copy id to clipboard")).to_be_visible() expect(page.get_by_role(
asset_id_text = page.locator(f"[data-testid='{index}_value']").inner_text() "button", name="Copy id to clipboard")).to_be_visible()
asset_id_text = page.locator(
f"[data-testid='{index}_value']").inner_text()
pattern = r"^[0-9a-f]{6}\u2026[0-9a-f]{4}" pattern = r"^[0-9a-f]{6}\u2026[0-9a-f]{4}"
assert re.match(pattern, asset_id_text), f"Expected ID to match pattern but got {asset_id_text}" assert re.match(
pattern, asset_id_text), f"Expected ID to match pattern but got {asset_id_text}"
else: else:
expect(page.locator(f"[data-testid='{index}_label']")).to_have_text(label) expect(page.locator(
expect(page.locator(f"[data-testid='{index}_value']")).to_have_text(value) f"[data-testid='{index}_label']")).to_have_text(label)
expect(page.locator(
f"[data-testid='{index}_value']")).to_have_text(value)
if label_tooltip: if label_tooltip:
tooltip(page, index, "label", label_tooltip) tooltip(page, index, "label", label_tooltip)
@@ -14,19 +14,16 @@ market_order = "order-type-Market"
tif = "order-tif" tif = "order-tif"
expire = "expire" expire = "expire"
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def vega(request): def vega(request):
with init_vega(request) as vega: with init_vega(request) as vega:
yield vega yield vega
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def continuous_market(vega): def continuous_market(vega):
return setup_continuous_market(vega) return setup_continuous_market(vega)
@pytest.mark.usefixtures("auth", "risk_accepted")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_limit_buy_order_GTT(continuous_market, vega: VegaService, page: Page): def test_limit_buy_order_GTT(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(tif).select_option("Good 'til Time (GTT)") page.get_by_test_id(tif).select_option("Good 'til Time (GTT)")
@@ -54,8 +51,7 @@ def test_limit_buy_order_GTT(continuous_market, vega: VegaService, page: Page):
"BTC:DAI_2023Futr10+10LimitFilled120.00GTT:" "BTC:DAI_2023Futr10+10LimitFilled120.00GTT:"
) )
@pytest.mark.usefixtures("auth", "risk_accepted")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_limit_buy_order(continuous_market, vega: VegaService, page: Page): def test_limit_buy_order(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
@@ -72,8 +68,7 @@ def test_limit_buy_order(continuous_market, vega: VegaService, page: Page):
"BTC:DAI_2023Futr10+10LimitFilled120.00GTC" "BTC:DAI_2023Futr10+10LimitFilled120.00GTC"
) )
@pytest.mark.usefixtures("auth", "risk_accepted")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_limit_sell_order(continuous_market, vega: VegaService, page: Page): def test_limit_sell_order(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(order_size).fill("10") page.get_by_test_id(order_size).fill("10")
@@ -97,8 +92,7 @@ def test_limit_sell_order(continuous_market, vega: VegaService, page: Page):
"BTC:DAI_2023Futr10-10LimitFilled100.00GFN" "BTC:DAI_2023Futr10-10LimitFilled100.00GFN"
) )
@pytest.mark.usefixtures("auth", "risk_accepted")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_market_sell_order(continuous_market, vega: VegaService, page: Page): def test_market_sell_order(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(market_order).click() page.get_by_test_id(market_order).click()
@@ -122,8 +116,7 @@ def test_market_sell_order(continuous_market, vega: VegaService, page: Page):
"BTC:DAI_2023Futr10-10MarketFilled-IOC" "BTC:DAI_2023Futr10-10MarketFilled-IOC"
) )
@pytest.mark.usefixtures("auth", "risk_accepted")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_market_buy_order(continuous_market, vega: VegaService, page: Page): def test_market_buy_order(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(market_order).click() page.get_by_test_id(market_order).click()
@@ -13,7 +13,7 @@ def continuous_market(vega):
return setup_continuous_market(vega) return setup_continuous_market(vega)
@pytest.mark.skip("We currently can't approve wallet connection through Sim") @pytest.mark.skip("We currently can't approve wallet connection through Sim")
@pytest.mark.usefixtures("page", "risk_accepted") @pytest.mark.usefixtures("risk_accepted")
def test_connect_vega_wallet(continuous_market, page: Page): def test_connect_vega_wallet(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("order-price").fill("101") page.get_by_test_id("order-price").fill("101")
@@ -25,7 +25,7 @@ def test_connect_vega_wallet(continuous_market, page: Page):
expect(page.get_by_test_id("order-type-Limit")).to_be_checked() expect(page.get_by_test_id("order-type-Limit")).to_be_checked()
expect(page.get_by_test_id("order-price")).to_have_value("101") expect(page.get_by_test_id("order-price")).to_have_value("101")
@pytest.mark.usefixtures("page", "risk_accepted") @pytest.mark.usefixtures("risk_accepted")
def test_sidebar_should_be_open_after_reload(continuous_market, page: Page): def test_sidebar_should_be_open_after_reload(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
expect(page.get_by_test_id("deal-ticket-form")).to_be_visible() expect(page.get_by_test_id("deal-ticket-form")).to_be_visible()
@@ -12,7 +12,7 @@ market_trading_mode = "market-trading-mode"
@pytest.mark.skip("tbd") @pytest.mark.skip("tbd")
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_margin_and_fees_estimations(continuous_market, vega: VegaService, page: Page): def test_margin_and_fees_estimations(continuous_market, vega: VegaService, page: Page):
# setup continuous trading market with one user buy trade # setup continuous trading market with one user buy trade
market_id = continuous_market market_id = continuous_market
@@ -38,7 +38,6 @@ timeInForce_col = '[col-id="submission.timeInForce"]'
updatedAt_col = '[col-id="updatedAt"]' updatedAt_col = '[col-id="updatedAt"]'
close_toast = "toast-close" close_toast = "toast-close"
def create_position(vega: VegaService, market_id): def create_position(vega: VegaService, market_id):
submit_order(vega, "Key 1", market_id, "SIDE_SELL", 100, 110) submit_order(vega, "Key 1", market_id, "SIDE_SELL", 100, 110)
submit_order(vega, "Key 1", market_id, "SIDE_BUY", 100, 110) submit_order(vega, "Key 1", market_id, "SIDE_BUY", 100, 110)
@@ -46,7 +45,7 @@ def create_position(vega: VegaService, market_id):
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup vega.wait_for_total_catchup
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_stop_order_form_error_validation(continuous_market, page: Page): def test_stop_order_form_error_validation(continuous_market, page: Page):
# 7002-SORD-032 # 7002-SORD-032
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
@@ -69,7 +68,7 @@ def test_stop_order_form_error_validation(continuous_market, page: Page):
) )
@pytest.mark.skip("core issue") @pytest.mark.skip("core issue")
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_order_rejected(continuous_market, vega: VegaService, page: Page): def test_submit_stop_order_rejected(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(stop_orders_tab).click() page.get_by_test_id(stop_orders_tab).click()
@@ -107,7 +106,7 @@ def test_submit_stop_order_rejected(continuous_market, vega: VegaService, page:
).not_to_be_empty() ).not_to_be_empty()
@pytest.mark.skip("core issue") @pytest.mark.skip("core issue")
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_market_order_triggered( def test_submit_stop_market_order_triggered(
continuous_market, vega: VegaService, page: Page continuous_market, vega: VegaService, page: Page
): ):
@@ -165,7 +164,7 @@ def test_submit_stop_market_order_triggered(
).not_to_be_empty() ).not_to_be_empty()
@pytest.mark.skip("core issue") @pytest.mark.skip("core issue")
@pytest.mark.usefixtures("continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_limit_order_pending( def test_submit_stop_limit_order_pending(
continuous_market, vega: VegaService, page: Page continuous_market, vega: VegaService, page: Page
): ):
@@ -226,7 +225,7 @@ def test_submit_stop_limit_order_pending(
).not_to_be_empty() ).not_to_be_empty()
@pytest.mark.skip("core issue") @pytest.mark.skip("core issue")
@pytest.mark.usefixtures("continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_limit_order_cancel( def test_submit_stop_limit_order_cancel(
continuous_market, vega: VegaService, page: Page continuous_market, vega: VegaService, page: Page
): ):
@@ -270,7 +269,7 @@ class TestStopOcoValidation:
def continuous_market(self, vega): def continuous_market(self, vega):
return setup_continuous_market(vega) return setup_continuous_market(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_stop_market_order_form_validation(self, continuous_market, page: Page): def test_stop_market_order_form_validation(self, continuous_market, page: Page):
# 7002-SORD-052 # 7002-SORD-052
# 7002-SORD-055 # 7002-SORD-055
@@ -303,7 +302,7 @@ class TestStopOcoValidation:
expect(page.get_by_test_id(order_size)).to_be_empty expect(page.get_by_test_id(order_size)).to_be_empty
expect(page.get_by_test_id(order_price)).not_to_be_visible() expect(page.get_by_test_id(order_price)).not_to_be_visible()
@pytest.mark.usefixtures("page", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_stop_limit_order_form_validation(self, continuous_market, page: Page): def test_stop_limit_order_form_validation(self, continuous_market, page: Page):
# 7002-SORD-020 # 7002-SORD-020
# 7002-SORD-021 # 7002-SORD-021
@@ -347,7 +346,7 @@ class TestStopOcoValidation:
expect(page.get_by_test_id(order_price)).to_be_empty() expect(page.get_by_test_id(order_price)).to_be_empty()
@pytest.mark.skip("core issue") @pytest.mark.skip("core issue")
@pytest.mark.usefixtures("page", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_maximum_number_of_active_stop_orders( def test_maximum_number_of_active_stop_orders(
self, continuous_market, vega: VegaService, page: Page self, continuous_market, vega: VegaService, page: Page
): ):
@@ -4,7 +4,6 @@ from vega_sim.service import VegaService
from actions.vega import submit_order from actions.vega import submit_order
from actions.utils import wait_for_toast_confirmation from actions.utils import wait_for_toast_confirmation
stop_order_btn = "order-type-Stop" stop_order_btn = "order-type-Stop"
stop_limit_order_btn = "order-type-StopLimit" stop_limit_order_btn = "order-type-StopLimit"
stop_market_order_btn = "order-type-StopMarket" stop_market_order_btn = "order-type-StopMarket"
@@ -50,7 +49,7 @@ def create_position(vega: VegaService, market_id):
vega.wait_for_total_catchup vega.wait_for_total_catchup
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_order_market_oco_rejected( def test_submit_stop_order_market_oco_rejected(
continuous_market, vega: VegaService, page: Page continuous_market, vega: VegaService, page: Page
): ):
@@ -127,7 +126,7 @@ def test_submit_stop_order_market_oco_rejected(
assert trigger_price_list.sort() == trigger_value_list.sort() assert trigger_price_list.sort() == trigger_value_list.sort()
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_oco_market_order_triggered( def test_submit_stop_oco_market_order_triggered(
continuous_market, vega: VegaService, page: Page continuous_market, vega: VegaService, page: Page
): ):
@@ -204,7 +203,7 @@ def test_submit_stop_oco_market_order_triggered(
assert trigger_price_list.sort() == trigger_value_list.sort() assert trigger_price_list.sort() == trigger_value_list.sort()
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_oco_market_order_pending( def test_submit_stop_oco_market_order_pending(
continuous_market, vega: VegaService, page: Page continuous_market, vega: VegaService, page: Page
): ):
@@ -236,7 +235,7 @@ def test_submit_stop_oco_market_order_pending(
"PendingOCO" "PendingOCO"
) )
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
def test_submit_stop_oco_limit_order_pending( def test_submit_stop_oco_limit_order_pending(
continuous_market, vega: VegaService, page: Page continuous_market, vega: VegaService, page: Page
): ):
@@ -287,7 +286,7 @@ def test_submit_stop_oco_limit_order_pending(
assert trigger_price_list.sort() == trigger_value_list.sort() assert trigger_price_list.sort() == trigger_value_list.sort()
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_oco_limit_order_cancel( def test_submit_stop_oco_limit_order_cancel(
continuous_market, vega: VegaService, page: Page continuous_market, vega: VegaService, page: Page
): ):
@@ -325,5 +324,3 @@ def test_submit_stop_oco_limit_order_cancel(
expect( expect(
page.locator(".ag-center-cols-container").locator('[col-id="status"]').last page.locator(".ag-center-cols-container").locator('[col-id="status"]').last
).to_have_text("CancelledOCO") ).to_have_text("CancelledOCO")
@@ -5,8 +5,6 @@ from actions.utils import change_keys
from conftest import init_vega from conftest import init_vega
from fixtures.market import setup_continuous_market from fixtures.market import setup_continuous_market
order_size = "order-size" order_size = "order-size"
order_price = "order-price" order_price = "order-price"
place_order = "place-order" place_order = "place-order"
@@ -18,13 +16,12 @@ def vega(request):
with init_vega(request) as vega: with init_vega(request) as vega:
yield vega yield vega
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def continuous_market(vega): def continuous_market(vega):
return setup_continuous_market(vega) return setup_continuous_market(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_should_display_info_and_button_for_deposit(continuous_market, vega: VegaService, page: Page): def test_should_display_info_and_button_for_deposit(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(order_size).fill("200000") page.get_by_test_id(order_size).fill("200000")
page.get_by_test_id(order_price).fill("20") page.get_by_test_id(order_price).fill("20")
@@ -35,7 +32,7 @@ def test_should_display_info_and_button_for_deposit(continuous_market, vega: Veg
page.get_by_test_id(deal_ticket_deposit_dialog_button).nth(0).click() page.get_by_test_id(deal_ticket_deposit_dialog_button).nth(0).click()
expect(page.get_by_test_id("sidebar-content")).to_contain_text("DepositFrom") expect(page.get_by_test_id("sidebar-content")).to_contain_text("DepositFrom")
@pytest.mark.usefixtures("page", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_should_show_an_error_if_your_balance_is_zero(continuous_market, vega: VegaService, page: Page): def test_should_show_an_error_if_your_balance_is_zero(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
vega.create_key("key_empty") vega.create_key("key_empty")
+682
View File
@@ -0,0 +1,682 @@
import pytest
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from actions.vega import submit_order
from wallet_config import MM_WALLET
from conftest import init_vega, init_page, auth_setup
from actions.utils import next_epoch, change_keys, forward_time
from fixtures.market import market_exists, setup_continuous_market
# region Constants for test IDs
ADJUSTED_FEES = "adjusted-fees"
TOTAL_FEE_BEFORE_DISCOUNT = "total-fee-before-discount"
INFRASTRUCTURE_FEES = "infrastructure-fees"
MAKER_FEES = "maker-fees"
LIQUIDITY_FEES = "liquidity-fees"
TOTAL_DISCOUNT = "total-discount"
VOLUME_DISCOUNT_ROW = "volume-discount-row"
REFERRAL_DISCOUNT_ROW = "referral-discount-row"
PAST_EPOCHS_VOLUME = "past-epochs-volume"
REQUIRED_FOR_NEXT_TIER = "required-for-next-tier"
TIER_VALUE_0 = "tier-value-0"
TIER_VALUE_1 = "tier-value-1"
DISCOUNT_VALUE_0 = "discount-value-0"
DISCOUNT_VALUE_1 = "discount-value-1"
MIN_VOLUME_VALUE_0 = "min-volume-value-0"
MIN_VOLUME_VALUE_1 = "min-volume-value-1"
MY_VOLUME_VALUE_0 = "my-volume-value-0"
MY_VOLUME_VALUE_1 = "my-volume-value-1"
YOUR_TIER_0 = "your-tier-0"
YOUR_TIER_1 = "your-tier-1"
ORDER_SIZE = "order-size"
ORDER_PRICE = "order-price"
DISCOUNT_PILL = "discount-pill"
FEES_TEXT = "fees-text"
TOOLTIP_CONTENT = "tooltip-content"
INFRASTRUCTURE_FEE_FACTOR = "infrastructure-fee-factor"
INFRASTRUCTURE_FEE_VALUE = "infrastructure-fee-value"
LIQUIDITY_FEE_FACTOR = "liquidity-fee-factor"
LIQUIDITY_FEE_VALUE = "liquidity-fee-value"
MAKER_FEE_FACTOR = "maker-fee-factor"
MAKER_FEE_VALUE = "maker-fee-value"
SUBTOTAL_FEE_FACTOR = "subtotal-fee-factor"
SUBTOTAL_FEE_VALUE = "subtotal-fee-value"
DISCOUNT_FEE_FACTOR = "discount-fee-factor"
DISCOUNT_FEE_VALUE = "discount-fee-value"
TOTAL_FEE_VALUE = "total-fee-value"
RUNNING_NOTIONAL_TAKER_VOLUME = "running-notional-taker-volume"
EPOCHS_IN_REFERRAL_SET = "epochs-in-referral-set"
REQUIRED_EPOCHS_VALUE_0 = "required-epochs-value-0"
REQUIRED_EPOCHS_VALUE_1 = "required-epochs-value-1"
FILLS = "Fills"
TAB_FILLS = "tab-fills"
FEE_BREAKDOWN_TOOLTIP = "fee-breakdown-tooltip"
ROW_LOCATOR = ".ag-center-cols-container .ag-row"
# Col-Ids:
COL_INSTRUMENT_CODE = '[col-id="market.tradableInstrument.instrument.code"]'
COL_CODE = '[col-id="code"]'
COL_SIZE = '[col-id="size"]'
COL_PRICE = '[col-id="price"]'
COL_PRICE_1 = '[col-id="price_1"]'
COL_AGGRESSOR = '[col-id="aggressor"]'
COL_FEE = '[col-id="fee"]'
COL_FEE_DISCOUNT = '[col-id="fee-discount"]'
COL_FEE_AFTER_DISCOUNT = '[col-id="feeAfterDiscount"]'
COL_INFRA_FEE = '[col-id="infraFee"]'
COL_MAKER_FEE = '[col-id="makerFee"]'
COL_LIQUIDITY_FEE = '[col-id="liquidityFee"]'
COL_TOTAL_FEE = '[col-id="totalFee"]'
# endregion
@pytest.fixture(scope="module")
def market_ids():
return {
"tier_1_volume": "default_id",
"tier_2_volume": "default_id",
"tier_1_referral": "default_id",
"tier_2_referral": "default_id",
"combo": "default_id",
}
@pytest.fixture(scope="module")
def vega_volume_discount_tier_1(request):
with init_vega(request) as vega_volume_discount_tier_1:
yield vega_volume_discount_tier_1
@pytest.fixture(scope="module")
def vega_volume_discount_tier_2(request):
with init_vega(request) as vega_volume_discount_tier_2:
yield vega_volume_discount_tier_2
@pytest.fixture(scope="module")
def vega_referral_discount_tier_1(request):
with init_vega(request) as vega_referral_discount_tier_1:
yield vega_referral_discount_tier_1
@pytest.fixture(scope="module")
def vega_referral_discount_tier_2(request):
with init_vega(request) as vega_referral_discount_tier_2:
yield vega_referral_discount_tier_2
@pytest.fixture(scope="module")
def vega_referral_and_volume_discount(request):
with init_vega(request) as vega_referral_and_volume_discount:
yield vega_referral_and_volume_discount
@pytest.fixture
def page(vega_instance, browser, request):
with init_page(vega_instance, browser, request) as page_instance:
yield page_instance
@pytest.fixture
def vega_instance(
tier,
discount_program,
vega_volume_discount_tier_1,
vega_volume_discount_tier_2,
vega_referral_discount_tier_1,
vega_referral_discount_tier_2,
vega_referral_and_volume_discount,
):
if discount_program == "volume":
return vega_volume_discount_tier_1 if tier == 1 else vega_volume_discount_tier_2
elif discount_program == "referral":
return (
vega_referral_discount_tier_1
if tier == 1
else vega_referral_discount_tier_2
)
elif discount_program == "combo":
return vega_referral_and_volume_discount
@pytest.fixture
def auth(vega_instance, page):
return auth_setup(vega_instance, page)
def setup_market_with_volume_discount_program(vega: VegaService, tier: int):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega)
order_count = 2 if tier == 1 else 3
for _ in range(order_count):
submit_order(vega, "Key 1", market, "SIDE_BUY", 1, 110)
forward_time(vega, True if _ < order_count - 1 else False)
return market
def setup_market_with_referral_discount_program(vega: VegaService, tier: int):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega=vega)
referral_set_id = list(vega.list_referral_sets().keys())[0]
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega=vega)
order_count = 2
order_size = 1 if tier == 1 else 2
for _ in range(order_count):
submit_order(vega, "Key 1", market, "SIDE_BUY", order_size, 110)
forward_time(vega, True if _ < order_count - 1 else False)
return market
def setup_combined_market(vega: VegaService):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega)
vega.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega=vega)
referral_set_id = list(vega.list_referral_sets().keys())[0]
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega=vega)
order_count = 2
order_size = 2
for _ in range(order_count):
submit_order(vega, "Key 1", market, "SIDE_BUY", order_size, 110)
forward_time(vega, True if _ < order_count - 1 else False)
return market
def set_market_volume_discount(vega, tier, discount_program, market_ids):
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key, "default_id")
print(f"Checking if market exists: {market_id}")
if not market_exists(vega, market_id):
print(
f"Market doesn't exist for {discount_program} tier {tier}. Setting up new market."
)
if discount_program == "volume":
market_id = setup_market_with_volume_discount_program(vega, tier)
elif discount_program == "referral":
market_id = setup_market_with_referral_discount_program(vega, tier)
elif discount_program == "combo":
market_id = setup_combined_market(vega)
market_ids[market_id_key] = market_id
print(f"Using market ID: {market_id}")
return market_ids
@pytest.mark.parametrize(
"tier, discount_program, expected_text",
[
(1, "volume", "9.045%-9.045%"),
(2, "volume", "8.04%-8.04%"),
(1, "referral", "9.045%-9.045%"),
(2, "referral", "8.04%-8.04%"),
(2, "combo", "6.432%-6.432%"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_discount_program_my_trading_fees(
tier, expected_text, discount_program, vega_instance, page: Page, market_ids
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text(expected_text)
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
"Total fee before discount10.05%-10.05%"
)
expect(page.get_by_test_id(INFRASTRUCTURE_FEES)).to_have_text("Infrastructure0.05%")
expect(page.get_by_test_id(MAKER_FEES)).to_have_text("Maker10%")
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
@pytest.mark.parametrize(
"tier, discount_program, volume_discount, total_discount, referral_discount",
[
(1, "volume", "Volume discount10%", "10%", "Referral discount0%"),
(2, "volume", "Volume discount20%", "20%", "Referral discount0%"),
(1, "referral", "Volume discount0%", "10%", "Referral discount10%"),
(2, "referral", "Volume discount0%", "20%", "Referral discount20%"),
(2, "combo", "Volume discount20%", "36%", "Referral discount20%"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_discount_program_total_discount(
tier,
discount_program,
volume_discount,
referral_discount,
total_discount,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text(total_discount)
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text(volume_discount)
expect(page.get_by_test_id(REFERRAL_DISCOUNT_ROW)).to_have_text(referral_discount)
page.get_by_test_id(TOTAL_DISCOUNT).hover()
expect(page.get_by_test_id(TOOLTIP_CONTENT).nth(0)).to_have_text(
"The total discount is calculated according to the following formula: 1 - (1 - dvolume) ⋇ (1 - dreferral)"
)
@pytest.mark.parametrize(
"tier, discount_program, past_epochs_volume, required_for_next_tier",
[(1, "volume", "103", "97"), (2, "volume", "206", "")],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_volume_discount_program_my_current_volume(
tier,
discount_program,
past_epochs_volume,
required_for_next_tier,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(PAST_EPOCHS_VOLUME)).to_have_text(past_epochs_volume)
if tier == 1:
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).to_have_text(
required_for_next_tier
)
else:
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).not_to_be_visible()
@pytest.mark.parametrize(
"tier, discount_program, notional_taker_volume, epochs_in_set",
[(1, "referral", "103", "1"), (2, "referral", "207", "1")],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_referral_discount_program_referral_benefits(
tier,
vega_instance,
discount_program,
notional_taker_volume,
epochs_in_set,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(RUNNING_NOTIONAL_TAKER_VOLUME)).to_have_text(
notional_taker_volume
)
expect(page.get_by_test_id(EPOCHS_IN_REFERRAL_SET)).to_have_text(epochs_in_set)
@pytest.mark.parametrize(
"tier, discount_program, my_volume_test_id, my_volume_value, your_tier",
[
(1, "volume", "my-volume-value-0", "103", "your-tier-0"),
(2, "volume", "my-volume-value-1", "206", "your-tier-1"),
(1, "referral", "my-volume-value-0", "103", "your-tier-0"),
(2, "referral", "my-volume-value-1", "206", "your-tier-1"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_discount_program_discount(
tier,
discount_program,
my_volume_test_id,
my_volume_value,
your_tier,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
expect(page.get_by_test_id(DISCOUNT_VALUE_0)).to_have_text("10%")
expect(page.get_by_test_id(DISCOUNT_VALUE_1)).to_have_text("20%")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_0)).to_have_text("100")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_1)).to_have_text("200")
if discount_program == "volume":
expect(page.get_by_test_id(my_volume_test_id)).to_have_text(my_volume_value)
else:
expect(page.get_by_test_id(REQUIRED_EPOCHS_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(REQUIRED_EPOCHS_VALUE_1)).to_have_text("2")
expect(page.get_by_test_id(your_tier)).to_be_visible()
expect(page.get_by_test_id(your_tier)).to_have_text("Your tier")
@pytest.mark.parametrize(
"tier, discount_program, fees_after_discount",
[
(1, "volume", "9.045%"),
(2, "volume", "8.04%"),
(1, "referral", "9.045%"),
(2, "referral", "8.04%"),
(2, "combo", "6.432%"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_discount_program_fees_by_market(
tier, discount_program, fees_after_discount, vega_instance, page: Page, market_ids
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
row = page.locator(ROW_LOCATOR)
expect(row.locator(COL_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_FEE_AFTER_DISCOUNT)).to_have_text(fees_after_discount)
expect(row.locator(COL_INFRA_FEE)).to_have_text("0.05%")
expect(row.locator(COL_MAKER_FEE)).to_have_text("10%")
expect(row.locator(COL_LIQUIDITY_FEE)).to_have_text("0%")
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.parametrize(
"tier, discount_program, discount, discount_value, total_fee",
[
(1, "volume", "-10%", "-0.01005 tDAI", "0.09045 tDAI"),
(2, "volume", "-20%", "-0.0201 tDAI", "0.0804 tDAI"),
(1, "referral", "-10%", "-0.01005 tDAI", "0.09045 tDAI"),
(2, "referral", "-20%", "-0.0201 tDAI", "0.0804 tDAI"),
(2, "combo", "-36%", "-0.03618 tDAI", "0.06432 tDAI"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_deal_ticket_discount_program(
tier,
discount_program,
discount,
discount_value,
total_fee,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text(discount)
page.get_by_test_id(FEES_TEXT).hover()
tooltip = page.get_by_test_id(TOOLTIP_CONTENT).first
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_FACTOR)).to_have_text("0.05%")
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_VALUE)).to_have_text("0.0005 tDAI")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_FACTOR)).to_have_text("0%")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_VALUE)).to_have_text("0.00 tDAI")
expect(tooltip.get_by_test_id(MAKER_FEE_FACTOR)).to_have_text("10%")
expect(tooltip.get_by_test_id(MAKER_FEE_VALUE)).to_have_text("0.10 tDAI")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_FACTOR)).to_have_text("10.05%")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_VALUE)).to_have_text("0.1005 tDAI")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_FACTOR)).to_have_text(discount)
expect(tooltip.get_by_test_id(DISCOUNT_FEE_VALUE)).to_have_text(discount_value)
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text(total_fee)
@pytest.mark.parametrize(
"tier, discount_program, fee, fee_discount, price_1, size",
[
(1, "volume", "9.36158 tDAI", "1.04017 tDAI", "103.50 tDAI", "+1"),
(2, "volume", "8.3214 tDAI", "2.08035 tDAI", "103.50 tDAI", "+1"),
(
1,
"referral",
"8.42543 tDAI ",
"1.04017 tDAI",
"103.50 tDAI",
"+1",
),
(
2,
"referral",
"13.31424 tDAI",
"4.1607 tDAI",
"207.00 tDAI",
"+2",
),
(2, "combo", "10.6514 tDAI ", "7.48926 tDAI", "207.00 tDAI", "+2"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fills_taker_discount_program(
tier,
discount_program,
fee,
fee_discount,
price_1,
size,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_INSTRUMENT_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_SIZE)).to_have_text(size)
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text(price_1)
expect(row.locator(COL_AGGRESSOR)).to_have_text("Taker")
expect(row.locator(COL_FEE)).to_have_text(fee)
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text(fee_discount)
@pytest.mark.parametrize(
"tier, discount_program, fee, fee_discount, size, price_1",
[
(1, "volume", "-9.315 tDAI", "1.035 tDAI", "-1", "103.50 tDAI"),
(2, "volume", "-8.28 tDAI", "2.07 tDAI", "-1", "103.50 tDAI"),
(1, "referral", "-8.3835 tDAI", "1.035 tDAI", "-1", "103.50 tDAI"),
(2, "referral", "-13.248 tDAI", "4.14 tDAI", "-2", "207.00 tDAI"),
(2, "combo", "-10.5984 tDAI ", "7.452 tDAI", "-2", "207.00 tDAI"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fills_maker_discount_program(
tier,
discount_program,
vega_instance,
fee,
fee_discount,
size,
price_1,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
change_keys(page, vega_instance, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_INSTRUMENT_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_SIZE)).to_have_text(size)
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text(price_1)
expect(row.locator(COL_AGGRESSOR)).to_have_text("Maker")
expect(row.locator(COL_FEE)).to_have_text(fee)
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text(fee_discount)
@pytest.mark.parametrize(
"tier, discount_program, fee",
[
(1, "volume", "9.315"),
(2, "volume", "8.28"),
(1, "referral", "8.3835"),
(2, "referral", "13.248"),
(2, "combo", "10.5984"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fills_maker_fee_tooltip_discount_program(
tier, discount_program, fee, vega_instance, page: Page, market_ids
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
change_keys(page, vega_instance, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
f"If the market was activeFee revenue to be received by the maker, takers' fee discounts already applied.During continuous trading the maker pays no infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-{fee} tDAITotal fees-{fee} tDAI"
)
@pytest.mark.parametrize(
"tier, discount_program, maker_fee, total_fee, infra_fee",
[
(1, "volume", "9.315", "9.36158", "0.04658"),
(2, "volume", "8.28", "8.3214", "0.0414"),
(1, "referral", "8.3835", "8.42543", "0.04193"),
(2, "referral", "13.248", "13.31424", "0.06624"),
(2, "combo", "10.5984", "10.6514", "0.053"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fills_taker_fee_tooltip_discount_program(
tier,
discount_program,
vega_instance,
maker_fee,
total_fee,
infra_fee,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
f"If the market was activeFees to be paid by the taker; discounts are already applied.Infrastructure fee{infra_fee} tDAILiquidity fee0.00 tDAIMaker fee{maker_fee} tDAITotal fees{total_fee} tDAI"
)
@@ -10,20 +10,16 @@ import logging
logger = logging.getLogger() logger = logging.getLogger()
@pytest.fixture(scope="class") @pytest.fixture(scope="class")
def vega(): def vega():
with init_vega() as vega: with init_vega() as vega:
yield vega yield vega
# we can reuse vega market-sim service and market in almost all tests
@pytest.fixture(scope="class") @pytest.fixture(scope="class")
def simple_market(vega: VegaService): def simple_market(vega: VegaService):
return setup_simple_market(vega) return setup_simple_market(vega)
class TestGetStarted: class TestGetStarted:
@pytest.mark.usefixtures("page")
def test_get_started_interactive(self, vega: VegaService, page: Page): def test_get_started_interactive(self, vega: VegaService, page: Page):
page.goto("/") page.goto("/")
# 0007-FUGS-001 # 0007-FUGS-001
@@ -134,8 +130,7 @@ class TestGetStarted:
# Assert dialog isn't visible # Assert dialog isn't visible
expect(page.get_by_test_id("welcome-dialog")).not_to_be_visible() expect(page.get_by_test_id("welcome-dialog")).not_to_be_visible()
@pytest.mark.usefixtures("risk_accepted")
@pytest.mark.usefixtures("page", "risk_accepted")
def test_get_started_seen_already(self, simple_market, page: Page): def test_get_started_seen_already(self, simple_market, page: Page):
page.goto(f"/#/markets/{simple_market}") page.goto(f"/#/markets/{simple_market}")
get_started_locator = page.get_by_test_id("connect-vega-wallet") get_started_locator = page.get_by_test_id("connect-vega-wallet")
@@ -148,8 +143,6 @@ class TestGetStarted:
# 0007-FUGS-007 # 0007-FUGS-007
expect(page.get_by_test_id("dialog-content").nth(1)).to_be_visible() expect(page.get_by_test_id("dialog-content").nth(1)).to_be_visible()
@pytest.mark.usefixtures("page")
def test_browser_wallet_installed(self, simple_market, page: Page): def test_browser_wallet_installed(self, simple_market, page: Page):
page.add_init_script("window.vega = {}") page.add_init_script("window.vega = {}")
page.goto(f"/#/markets/{simple_market}") page.goto(f"/#/markets/{simple_market}")
@@ -159,14 +152,13 @@ class TestGetStarted:
expect(locator).to_be_visible expect(locator).to_be_visible
expect(locator).to_have_text("Connect") expect(locator).to_have_text("Connect")
@pytest.mark.usefixtures("risk_accepted")
@pytest.mark.usefixtures("page", "risk_accepted")
def test_get_started_deal_ticket(self,simple_market, page: Page): def test_get_started_deal_ticket(self,simple_market, page: Page):
page.goto(f"/#/markets/{simple_market}") page.goto(f"/#/markets/{simple_market}")
expect(page.get_by_test_id("order-connect-wallet")).to_have_text("Connect wallet") expect(page.get_by_test_id("order-connect-wallet")).to_have_text("Connect wallet")
@pytest.mark.usefixtures("page", "risk_accepted") @pytest.mark.usefixtures("risk_accepted")
def test_browser_wallet_installed_deal_ticket(simple_market, page: Page): def test_browser_wallet_installed_deal_ticket(simple_market, page: Page):
page.add_init_script("window.vega = {}") page.add_init_script("window.vega = {}")
page.goto(f"/#/markets/{simple_market}") page.goto(f"/#/markets/{simple_market}")
@@ -174,7 +166,6 @@ class TestGetStarted:
page.wait_for_selector('[data-testid="sidebar-content"]', state="visible") page.wait_for_selector('[data-testid="sidebar-content"]', state="visible")
expect(page.get_by_test_id("get-started-banner")).not_to_be_visible() expect(page.get_by_test_id("get-started-banner")).not_to_be_visible()
@pytest.mark.usefixtures("page")
def test_redirect_default_market(self, continuous_market, vega: VegaService, page: Page): def test_redirect_default_market(self, continuous_market, vega: VegaService, page: Page):
page.goto("/") page.goto("/")
# 0007-FUGS-012 # 0007-FUGS-012
@@ -186,7 +177,6 @@ class TestGetStarted:
expect(page.get_by_test_id("welcome-dialog")).not_to_be_visible() expect(page.get_by_test_id("welcome-dialog")).not_to_be_visible()
class TestBrowseAll: class TestBrowseAll:
@pytest.mark.usefixtures("page")
def test_get_started_browse_all(self, simple_market, vega: VegaService, page: Page): def test_get_started_browse_all(self, simple_market, vega: VegaService, page: Page):
page.goto("/") page.goto("/")
print(simple_market) print(simple_market)
@@ -11,7 +11,6 @@ def hover_and_assert_tooltip(page: Page, element_text):
element.hover() element.hover()
expect(page.get_by_role("tooltip")).to_be_visible() expect(page.get_by_role("tooltip")).to_be_visible()
class TestIcebergOrdersValidations: class TestIcebergOrdersValidations:
@pytest.fixture(scope="class") @pytest.fixture(scope="class")
def vega(self, request): def vega(self, request):
@@ -22,7 +21,7 @@ class TestIcebergOrdersValidations:
def continuous_market(self, vega): def continuous_market(self, vega):
return setup_continuous_market(vega) return setup_continuous_market(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_iceberg_submit(self, continuous_market, vega: VegaService, page: Page): def test_iceberg_submit(self, continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("iceberg").click() page.get_by_test_id("iceberg").click()
@@ -47,7 +46,7 @@ class TestIcebergOrdersValidations:
(page.get_by_role("row").locator('[col-id="type"]')).nth(1) (page.get_by_role("row").locator('[col-id="type"]')).nth(1)
).to_have_text("Limit (Iceberg)") ).to_have_text("Limit (Iceberg)")
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_iceberg_open_order(continuous_market, vega: VegaService, page: Page): def test_iceberg_open_order(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
@@ -17,27 +17,34 @@ def continuous_market(vega):
return setup_continuous_market(vega) return setup_continuous_market(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_liquidity_provision_amendment(continuous_market, vega: VegaService, page: Page): def test_liquidity_provision_amendment(continuous_market, vega: VegaService, page: Page):
# TODO Refactor asserting the grid # TODO Refactor asserting the grid
page.goto(f"/#/liquidity/{continuous_market}") page.goto(f"/#/liquidity/{continuous_market}")
change_keys(page, vega, "market_maker") change_keys(page, vega, "market_maker")
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first row = page.get_by_test_id(
"tab-myLP").locator(".ag-center-cols-container .ag-row").first
expect(row).to_contain_text( expect(row).to_contain_text(
"Active" "Active"
) )
# 5002-LIQP-006 # 5002-LIQP-006
expect(page.get_by_test_id("target-stake")).to_have_text("Target stake5.82757 tDAI") expect(page.get_by_test_id("target-stake")
).to_have_text("Target stake5.82757 tDAI")
# 5002-LIQP-007 # 5002-LIQP-007
expect(page.get_by_test_id("supplied-stake")).to_have_text("Supplied stake10,000.00 tDAI") expect(page.get_by_test_id("supplied-stake")
).to_have_text("Supplied stake10,000.00 tDAI")
# 5002-LIQP-008 # 5002-LIQP-008
expect(page.get_by_test_id("liquidity-supplied")).to_have_text("Liquidity supplied 171,598.11%") expect(page.get_by_test_id("liquidity-supplied")
).to_have_text("Liquidity supplied 171,598.11%")
expect(page.get_by_test_id("fees-paid")).to_have_text("Fees paid-") expect(page.get_by_test_id("fees-paid")).to_have_text("Fees paid-")
# 5002-LIQP-009 # 5002-LIQP-009
expect(page.get_by_test_id("liquidity-market-id")).to_have_text("Market ID" + truncate_middle(continuous_market)) expect(page.get_by_test_id("liquidity-market-id")
expect(page.get_by_test_id("liquidity-learn-more")).to_have_text("Learn moreProviding liquidity") ).to_have_text("Market ID" + truncate_middle(continuous_market))
expect(page.get_by_test_id("liquidity-learn-more")
).to_have_text("Learn moreProviding liquidity")
# 002-LIQP-010 # 002-LIQP-010
expect(page.get_by_test_id("liquidity-learn-more").get_by_test_id("external-link")).to_have_attribute("href", "https://docs.vega.xyz/testnet/concepts/liquidity/provision") expect(page.get_by_test_id("liquidity-learn-more").get_by_test_id("external-link")
).to_have_attribute("href", "https://docs.vega.xyz/testnet/concepts/liquidity/provision")
vega.submit_simple_liquidity( vega.submit_simple_liquidity(
key_name="market_maker", key_name="market_maker",
@@ -50,26 +57,32 @@ def test_liquidity_provision_amendment(continuous_market, vega: VegaService, pag
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
page.reload() page.reload()
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first row = page.get_by_test_id(
"tab-myLP").locator(".ag-center-cols-container .ag-row").first
expect(row).to_contain_text( expect(row).to_contain_text(
"Updating next epoch" "Updating next epoch"
) )
next_epoch(vega=vega) next_epoch(vega=vega)
page.reload() page.reload()
expect(page.get_by_test_id("supplied-stake")).to_have_text("Supplied stake1.00001 tDAI") expect(page.get_by_test_id("supplied-stake")
expect(page.get_by_test_id("liquidity-supplied")).to_have_text("Liquidity supplied 17.16%") ).to_have_text("Supplied stake1.00001 tDAI")
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first expect(page.get_by_test_id("liquidity-supplied")
).to_have_text("Liquidity supplied 17.16%")
row = page.get_by_test_id(
"tab-myLP").locator(".ag-center-cols-container .ag-row").first
expect(row).to_contain_text( expect(row).to_contain_text(
"Active" "Active"
) )
@pytest.mark.skip("Waiting for the ability to cancel LP") @pytest.mark.skip("Waiting for the ability to cancel LP")
@pytest.mark.usefixtures("page", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_liquidity_provision_inactive(continuous_market, vega: VegaService, page: Page): def test_liquidity_provision_inactive(continuous_market, vega: VegaService, page: Page):
# TODO Refactor asserting the grid # TODO Refactor asserting the grid
page.goto(f"/#/liquidity/{continuous_market}") page.goto(f"/#/liquidity/{continuous_market}")
change_keys(page,vega, "market_maker") change_keys(page, vega, "market_maker")
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first row = page.get_by_test_id(
"tab-myLP").locator(".ag-center-cols-container .ag-row").first
expect(row).to_contain_text( expect(row).to_contain_text(
"Active" "Active"
) )
@@ -82,4 +95,3 @@ def test_liquidity_provision_inactive(continuous_market, vega: VegaService, page
) )
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
@@ -12,6 +12,7 @@ def vega():
with init_vega() as vega: with init_vega() as vega:
yield vega yield vega
@pytest.fixture(scope="class") @pytest.fixture(scope="class")
def create_settled_market(vega: VegaService): def create_settled_market(vega: VegaService):
market_id = setup_continuous_market(vega) market_id = setup_continuous_market(vega)
@@ -73,8 +74,9 @@ class TestSettledMarket:
# 6001-MARK-010 # 6001-MARK-010
pattern = r"(\d+)\s+(months|hours|days)\s+ago" pattern = r"(\d+)\s+(months|hours|days)\s+ago"
date_text = row_selector.locator('[col-id="settlementDate"]').inner_text() date_text = row_selector.locator('[col-id="settlementDate"]').inner_text()
assert re.match(pattern, date_text), f"Expected text to match pattern but got {date_text}" assert re.match(
pattern, date_text
), f"Expected text to match pattern but got {date_text}"
expected_pattern = re.compile(r"https://.*?/oracles/[a-f0-9]{64}") expected_pattern = re.compile(r"https://.*?/oracles/[a-f0-9]{64}")
actual_href = row_selector.locator( actual_href = row_selector.locator(
@@ -87,12 +89,12 @@ class TestSettledMarket:
expect(row_selector.locator('[col-id="bestBidPrice"]')).to_have_text("0.00") expect(row_selector.locator('[col-id="bestBidPrice"]')).to_have_text("0.00")
# 6001-MARK-012 # 6001-MARK-012
expect(row_selector.locator('[col-id="bestOfferPrice"]')).to_have_text("0.00") expect(row_selector.locator('[col-id="bestOfferPrice"]')).to_have_text("0.00")
# 6001-MARK-013 # 6001-MARK-013
expect(row_selector.locator('[col-id="markPrice"]')).to_have_text("110.00") expect(row_selector.locator('[col-id="markPrice"]')).to_have_text("110.00")
# 6001-MARK-014 # 6001-MARK-014
# 6001-MARK-015 # 6001-MARK-015
# 6001-MARK-016 # 6001-MARK-016
#tbd currently we have value unknown # tbd currently we have value unknown
# expect(row_selector.locator('[col-id="settlementDataOracleId"]')).to_have_text( # expect(row_selector.locator('[col-id="settlementDataOracleId"]')).to_have_text(
# "110.00" # "110.00"
# ) # )
@@ -107,7 +109,9 @@ class TestSettledMarket:
# 6001-MARK-018 # 6001-MARK-018
expect(row_selector.locator('[col-id="settlementAsset"]')).to_have_text("tDAI") expect(row_selector.locator('[col-id="settlementAsset"]')).to_have_text("tDAI")
# 6001-MARK-020 # 6001-MARK-020
assert re.match(pattern, date_text), f"Expected text to match pattern but got {date_text}" assert re.match(
pattern, date_text
), f"Expected text to match pattern but got {date_text}"
@pytest.mark.usefixtures("risk_accepted", "auth") @pytest.mark.usefixtures("risk_accepted", "auth")
+15 -9
View File
@@ -31,7 +31,7 @@ initial_spread: float = 0.1
market_name = "BTC:DAI_2023" market_name = "BTC:DAI_2023"
@pytest.mark.usefixtures("vega", "page", "simple_market", "risk_accepted", "auth") @pytest.mark.usefixtures("risk_accepted", "auth")
def test_price_monitoring(simple_market, vega: VegaService, page: Page): def test_price_monitoring(simple_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/all") page.goto(f"/#/markets/all")
expect(page.locator(table_row_selector).locator(trading_mode_col)).to_have_text( expect(page.locator(table_row_selector).locator(trading_mode_col)).to_have_text(
@@ -75,7 +75,7 @@ def test_price_monitoring(simple_market, vega: VegaService, page: Page):
time_in_force="TIME_IN_FORCE_GTC", time_in_force="TIME_IN_FORCE_GTC",
volume=99, volume=99,
) )
#6002-MDET-009 # 6002-MDET-009
expect( expect(
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value) page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
).to_have_text("0.00 (0.00%)") ).to_have_text("0.00 (0.00%)")
@@ -154,7 +154,7 @@ def test_price_monitoring(simple_market, vega: VegaService, page: Page):
vega.forward("10s") vega.forward("10s")
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
expect( expect(
page.get_by_test_id(price_monitoring_bounds_row).first.get_by_text( page.get_by_test_id(price_monitoring_bounds_row).first.get_by_text(
"135.44204 BTC" "135.44204 BTC"
@@ -191,22 +191,28 @@ def test_price_monitoring(simple_market, vega: VegaService, page: Page):
) )
# commented out because we have an issue #4233 # commented out because we have an issue #4233
# expect(page.get_by_text("Opening auction")).to_be_hidden() # expect(page.get_by_text("Opening auction")).to_be_hidden()
#6002-MDET-009 # 6002-MDET-009
expect( expect(
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value) page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
).to_have_text("50.00 (>100%)") ).to_have_text("50.00 (>100%)")
COL_ID_FEE = ".ag-center-cols-container [col-id='fee'] .ag-cell-value" COL_ID_FEE = ".ag-center-cols-container [col-id='fee'] .ag-cell-value"
@pytest.mark.usefixtures("vega", "page", "continuous_market", "risk_accepted", "auth")
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_auction_uncross_fees(continuous_market, vega: VegaService, page: Page): def test_auction_uncross_fees(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("Fills").click() page.get_by_test_id("Fills").click()
expect(page.locator(COL_ID_FEE)).to_have_text("0.00 tDAI") expect(page.locator(COL_ID_FEE)).to_have_text("0.00 tDAI")
page.locator(COL_ID_FEE).hover() page.locator(COL_ID_FEE).hover()
expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text("If the market was suspendedIf the market is in monitoring auction, half of the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI") expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text(
change_keys(page,vega, "market_maker") "If the market was suspendedDuring auction, half the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI"
)
change_keys(page, vega, "market_maker")
expect(page.locator(COL_ID_FEE)).to_have_text("0.00 tDAI") expect(page.locator(COL_ID_FEE)).to_have_text("0.00 tDAI")
page.locator(COL_ID_FEE).hover() page.locator(COL_ID_FEE).hover()
expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text("If the market was suspendedIf the market is in monitoring auction, half of the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI") expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text(
"If the market was suspendedDuring auction, half the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI"
)
@@ -3,7 +3,6 @@ import pytest
from playwright.sync_api import Page, expect from playwright.sync_api import Page, expect
from vega_sim.service import VegaService from vega_sim.service import VegaService
from fixtures.market import setup_continuous_market from fixtures.market import setup_continuous_market
from conftest import init_page, init_vega, risk_accepted_setup from conftest import init_page, init_vega, risk_accepted_setup
market_title_test_id = "accordion-title" market_title_test_id = "accordion-title"
@@ -15,7 +14,6 @@ def vega():
yield vega yield vega
# setting up everything in this single fixture, as all of the tests need the same setup, so no point in creating separate ones
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def page(vega, browser, request): def page(vega, browser, request):
with init_page(vega, browser, request) as page: with init_page(vega, browser, request) as page:
@@ -122,7 +120,9 @@ def test_market_info_instrument(page: Page):
# @pytest.mark.skip("oracle test to be fixed") # @pytest.mark.skip("oracle test to be fixed")
def test_market_info_oracle(page: Page, vega: VegaService):
def test_market_info_oracle(page: Page):
# 6002-MDET-203 # 6002-MDET-203
page.get_by_test_id(market_title_test_id).get_by_text("Oracle").click() page.get_by_test_id(market_title_test_id).get_by_text("Oracle").click()
expect( expect(
@@ -280,7 +280,7 @@ def test_market_info_proposal(page: Page, vega: VegaService):
"href", re.compile(r"(\/proposals\/propose\/update-market)") "href", re.compile(r"(\/proposals\/propose\/update-market)")
) )
@pytest.mark.skip("tbd-market-sim")
def test_market_info_succession_line(page: Page, vega: VegaService): def test_market_info_succession_line(page: Page, vega: VegaService):
page.get_by_test_id(market_title_test_id).get_by_text("Succession line").click() page.get_by_test_id(market_title_test_id).get_by_text("Succession line").click()
market_id = vega.find_market_id("BTC:DAI_2023") market_id = vega.find_market_id("BTC:DAI_2023")
@@ -2,7 +2,7 @@ import pytest
from playwright.sync_api import expect, Page from playwright.sync_api import expect, Page
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_market_selector(continuous_market, page: Page): def test_market_selector(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
expect(page.get_by_test_id("market-selector")).not_to_be_visible() expect(page.get_by_test_id("market-selector")).not_to_be_visible()
@@ -27,7 +27,7 @@ def test_market_selector(continuous_market, page: Page):
expect(btc_market.locator('[data-testid="sparkline-svg"]')).not_to_be_visible expect(btc_market.locator('[data-testid="sparkline-svg"]')).not_to_be_visible
@pytest.mark.usefixtures("page", "continuous_market", "simple_market", "auth", "risk_accepted") @pytest.mark.usefixtures("simple_market", "auth", "risk_accepted")
@pytest.mark.parametrize( @pytest.mark.parametrize(
"simple_market", "simple_market",
[ [
@@ -1,6 +1,5 @@
import pytest import pytest
from playwright.sync_api import Page, expect from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from conftest import init_page, init_vega, risk_accepted_setup from conftest import init_page, init_vega, risk_accepted_setup
@@ -5,7 +5,7 @@ from playwright.sync_api import Page, expect
from vega_sim.service import VegaService from vega_sim.service import VegaService
from conftest import init_vega from conftest import init_vega
from fixtures.market import setup_simple_market from fixtures.market import setup_simple_market
from wallet_config import MM_WALLET, MM_WALLET2, TERMINATE_WALLET, wallets from wallet_config import MM_WALLET
row_selector = '[data-testid="tab-proposed-markets"] .ag-center-cols-container .ag-row' row_selector = '[data-testid="tab-proposed-markets"] .ag-center-cols-container .ag-row'
col_market_id = '[col-id="market"] [data-testid="stack-cell-primary"]' col_market_id = '[col-id="market"] [data-testid="stack-cell-primary"]'
@@ -16,6 +16,7 @@ def vega(request):
with init_vega(request) as vega: with init_vega(request) as vega:
yield vega yield vega
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def proposed_market(vega: VegaService): def proposed_market(vega: VegaService):
# setup market without liquidity provided # setup market without liquidity provided
@@ -7,6 +7,7 @@ from conftest import init_vega
from actions.utils import wait_for_toast_confirmation from actions.utils import wait_for_toast_confirmation
from wallet_config import MM_WALLET, MM_WALLET2 from wallet_config import MM_WALLET, MM_WALLET2
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def vega(request): def vega(request):
with init_vega(request) as vega: with init_vega(request) as vega:
@@ -17,6 +18,7 @@ def vega(request):
def simple_market(vega): def simple_market(vega):
return setup_simple_market(vega) return setup_simple_market(vega)
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def setup_market_monitoring_auction(vega: VegaService, simple_market): def setup_market_monitoring_auction(vega: VegaService, simple_market):
vega.submit_liquidity( vega.submit_liquidity(
@@ -48,12 +50,18 @@ def setup_market_monitoring_auction(vega: VegaService, simple_market):
volume=99, volume=99,
) )
# add orders to provide liquidity # add orders to provide liquidity
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_BUY", 1, 1) submit_order(vega, MM_WALLET.name, simple_market, "SIDE_BUY", 1, 1)
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 1, 1) submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 1, 1)
submit_order(vega,MM_WALLET.name,simple_market, "SIDE_BUY",1,1 + 0.1 / 2,) submit_order(
submit_order(vega,MM_WALLET.name,simple_market,"SIDE_SELL",1,1 + 0.1 / 2) vega,
MM_WALLET.name,
simple_market,
"SIDE_BUY",
1,
1 + 0.1 / 2,
)
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 1, 1 + 0.1 / 2)
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_SELL", 1, 1) submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_SELL", 1, 1)
vega.forward("10s") vega.forward("10s")
@@ -71,9 +79,11 @@ def setup_market_monitoring_auction(vega: VegaService, simple_market):
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
@pytest.mark.usefixtures("page", "risk_accepted", "simple_market", "auth", "setup_market_monitoring_auction")
def test_market_monitoring_auction_price_volatility_limit_order(page: Page, simple_market, vega: VegaService): @pytest.mark.usefixtures("risk_accepted", "auth", "setup_market_monitoring_auction")
def test_market_monitoring_auction_price_volatility_limit_order(
page: Page, simple_market, vega: VegaService
):
page.goto(f"/#/markets/{simple_market}") page.goto(f"/#/markets/{simple_market}")
page.get_by_test_id("order-size").clear() page.get_by_test_id("order-size").clear()
page.get_by_test_id("order-size").type("1") page.get_by_test_id("order-size").type("1")
@@ -82,10 +92,14 @@ def test_market_monitoring_auction_price_volatility_limit_order(page: Page, simp
page.get_by_test_id("order-tif").select_option("Fill or Kill (FOK)") page.get_by_test_id("order-tif").select_option("Fill or Kill (FOK)")
page.get_by_test_id("place-order").click() page.get_by_test_id("place-order").click()
expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_have_text("This market is in auction due to high price volatility. Until the auction ends, you can only place GFA, GTT, or GTC limit orders.") expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_have_text(
"This market is in auction due to high price volatility. Until the auction ends, you can only place GFA, GTT, or GTC limit orders."
)
expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_be_visible() expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_be_visible()
expect(page.get_by_test_id("deal-ticket-warning-auction")).to_have_text("Any orders placed now will not trade until the auction ends") expect(page.get_by_test_id("deal-ticket-warning-auction")).to_have_text(
"Any orders placed now will not trade until the auction ends"
)
expect(page.get_by_test_id("deal-ticket-warning-auction")).to_be_visible() expect(page.get_by_test_id("deal-ticket-warning-auction")).to_be_visible()
page.get_by_test_id("order-tif").select_option("Good 'til Cancelled (GTC)") page.get_by_test_id("order-tif").select_option("Good 'til Cancelled (GTC)")
@@ -103,8 +117,11 @@ def test_market_monitoring_auction_price_volatility_limit_order(page: Page, simp
"BTC:DAI_2023Futr0+1LimitActive110.00GTC" "BTC:DAI_2023Futr0+1LimitActive110.00GTC"
) )
@pytest.mark.usefixtures("page", "risk_accepted", "simple_market", "auth", "setup_market_monitoring_auction")
def test_market_monitoring_auction_price_volatility_market_order(page: Page, simple_market): @pytest.mark.usefixtures("risk_accepted", "auth", "setup_market_monitoring_auction")
def test_market_monitoring_auction_price_volatility_market_order(
page: Page, simple_market
):
page.goto(f"/#/markets/{simple_market}") page.goto(f"/#/markets/{simple_market}")
page.get_by_test_id("order-type-Market").click() page.get_by_test_id("order-type-Market").click()
page.get_by_test_id("order-size").clear() page.get_by_test_id("order-size").clear()
@@ -112,8 +129,12 @@ def test_market_monitoring_auction_price_volatility_market_order(page: Page, sim
# 7002-SORD-060 # 7002-SORD-060
page.get_by_test_id("place-order").click() page.get_by_test_id("place-order").click()
expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_have_text("This market is in auction due to high price volatility. Until the auction ends, you can only place GFA, GTT, or GTC limit orders.") expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_have_text(
"This market is in auction due to high price volatility. Until the auction ends, you can only place GFA, GTT, or GTC limit orders."
)
expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_be_visible() expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_be_visible()
expect(page.get_by_test_id("deal-ticket-error-message-type")).to_have_text("This market is in auction due to high price volatility. Only limit orders are permitted when market is in auction.") expect(page.get_by_test_id("deal-ticket-error-message-type")).to_have_text(
"This market is in auction due to high price volatility. Only limit orders are permitted when market is in auction."
)
expect(page.get_by_test_id("deal-ticket-error-message-type")).to_be_visible() expect(page.get_by_test_id("deal-ticket-error-message-type")).to_be_visible()
@@ -9,8 +9,7 @@ from actions.utils import next_epoch
from wallet_config import MM_WALLET, MM_WALLET2, GOVERNANCE_WALLET from wallet_config import MM_WALLET, MM_WALLET2, GOVERNANCE_WALLET
@pytest.mark.usefixtures("risk_accepted")
@pytest.mark.usefixtures("vega", "page", "proposed_market", "risk_accepted")
def test_market_lifecycle(proposed_market, vega: VegaService, page: Page): def test_market_lifecycle(proposed_market, vega: VegaService, page: Page):
# 7002-SORD-001 # 7002-SORD-001
# 7002-SORD-002 # 7002-SORD-002
@@ -27,8 +26,12 @@ def test_market_lifecycle(proposed_market, vega: VegaService, page: Page):
# 6002-MDET-002 # 6002-MDET-002
expect(page.get_by_test_id("market-expiry")).to_have_text("ExpiryNot time-based") expect(page.get_by_test_id("market-expiry")).to_have_text("ExpiryNot time-based")
page.get_by_test_id("market-expiry").hover() page.get_by_test_id("market-expiry").hover()
expect(page.get_by_test_id("expiry-tooltip").first).to_have_text("This market expires when triggered by its oracle, not on a set date.View oracle specification") expect(page.get_by_test_id("expiry-tooltip").first).to_have_text(
expect(page.get_by_test_id("expiry-tooltip").first.get_by_test_id("link")).to_have_attribute("href", re.compile('.*')) "This market expires when triggered by its oracle, not on a set date.View oracle specification"
)
expect(
page.get_by_test_id("expiry-tooltip").first.get_by_test_id("link")
).to_have_attribute("href", re.compile(".*"))
# 6002-MDET-003 # 6002-MDET-003
expect(page.get_by_test_id("market-price")).to_have_text("Mark Price0.00") expect(page.get_by_test_id("market-price")).to_have_text("Mark Price0.00")
# 6002-MDET-004 # 6002-MDET-004
@@ -36,18 +39,30 @@ def test_market_lifecycle(proposed_market, vega: VegaService, page: Page):
# 6002-MDET-005 # 6002-MDET-005
expect(page.get_by_test_id("market-volume")).to_have_text("Volume (24h)-") expect(page.get_by_test_id("market-volume")).to_have_text("Volume (24h)-")
# 6002-MDET-008 # 6002-MDET-008
expect(page.get_by_test_id("market-settlement-asset")).to_have_text("Settlement assettDAI") expect(page.get_by_test_id("market-settlement-asset")).to_have_text(
expect(page.get_by_test_id("liquidity-supplied")).to_have_text("Liquidity supplied 0.00 (0.00%)") "Settlement assettDAI"
)
expect(page.get_by_test_id("liquidity-supplied")).to_have_text(
"Liquidity supplied 0.00 (0.00%)"
)
page.get_by_test_id("liquidity-supplied").hover() page.get_by_test_id("liquidity-supplied").hover()
expect(page.get_by_test_id("liquidity-supplied-tooltip").first).to_have_text("Supplied stake0.00Target stake0.00View liquidity provision tableLearn about providing liquidity") expect(page.get_by_test_id("liquidity-supplied-tooltip").first).to_have_text(
expect(page.get_by_test_id("liquidity-supplied-tooltip").first.get_by_test_id("link").first).to_have_text("View liquidity provision table") "Supplied stake0.00Target stake0.00View liquidity provision tableLearn about providing liquidity"
)
expect(
page.get_by_test_id("liquidity-supplied-tooltip")
.first.get_by_test_id("link")
.first
).to_have_text("View liquidity provision table")
# check that market is in proposed state # check that market is in proposed state
# 6002-MDET-006 # 6002-MDET-006
# 6002-MDET-007 # 6002-MDET-007
# 7002-SORD-061 # 7002-SORD-061
expect(trading_mode).to_have_text("No trading") expect(trading_mode).to_have_text("No trading")
trading_mode.hover() trading_mode.hover()
expect(page.get_by_test_id("trading-mode-tooltip").first).to_have_text("No trading enabled for this market.") expect(page.get_by_test_id("trading-mode-tooltip").first).to_have_text(
"No trading enabled for this market."
)
expect(market_state).to_have_text("Proposed") expect(market_state).to_have_text("Proposed")
# approve market # approve market
@@ -182,4 +197,4 @@ def test_market_closing_banners(page: Page, continuous_market, vega: VegaService
will_close_pattern = r"TRADING ON MARKET BTC:DAI_2023 WILL STOP ON \d+ \w+\nYou will no longer be able to hold a position on this market when it closes in \d+ days \d+ hours\. The final price will be 107\.00 BTC\." will_close_pattern = r"TRADING ON MARKET BTC:DAI_2023 WILL STOP ON \d+ \w+\nYou will no longer be able to hold a position on this market when it closes in \d+ days \d+ hours\. The final price will be 107\.00 BTC\."
match_result = re.fullmatch(will_close_pattern, page.locator(".grow").inner_text()) match_result = re.fullmatch(will_close_pattern, page.locator(".grow").inner_text())
assert match_result is not None assert match_result is not None
""" """
@@ -48,8 +48,9 @@ def verify_order_value(
else: else:
expect(element).to_have_text(expected_text) expect(element).to_have_text(expected_text)
@pytest.mark.skip("tbd") @pytest.mark.skip("tbd")
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_order_details_are_correctly_displayed( def test_order_details_are_correctly_displayed(
continuous_market, vega: VegaService, page: Page continuous_market, vega: VegaService, page: Page
): ):
@@ -8,6 +8,7 @@ from actions.vega import submit_order
logger = logging.getLogger() logger = logging.getLogger()
# Could be turned into a helper function in the future. # Could be turned into a helper function in the future.
def verify_data_grid(page: Page, data_test_id, expected_pattern): def verify_data_grid(page: Page, data_test_id, expected_pattern):
page.get_by_test_id(data_test_id).click() page.get_by_test_id(data_test_id).click()
@@ -49,9 +50,7 @@ def submit_order(vega: VegaService, wallet_name, market_id, side, volume, price)
) )
@pytest.mark.usefixtures( @pytest.mark.usefixtures("auth", "risk_accepted")
"vega", "page", "opening_auction_market", "auth", "risk_accepted"
)
def test_limit_order_trade_open_order( def test_limit_order_trade_open_order(
opening_auction_market, vega: VegaService, page: Page opening_auction_market, vega: VegaService, page: Page
): ):
@@ -80,7 +79,7 @@ def test_limit_order_trade_open_order(
verify_data_grid(page, "Open", expected_open_order) verify_data_grid(page, "Open", expected_open_order)
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_limit_order_trade_open_position(continuous_market, page: Page): def test_limit_order_trade_open_position(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
@@ -148,7 +147,7 @@ def test_limit_order_trade_open_position(continuous_market, page: Page):
expect(unrealisedPNL).to_have_text(position["unrealised_pnl"]) expect(unrealisedPNL).to_have_text(position["unrealised_pnl"])
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_limit_order_trade_order_trade_away(continuous_market, page: Page): def test_limit_order_trade_order_trade_away(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
# Assert that the order is no longer on the orderbook # Assert that the order is no longer on the orderbook
@@ -6,6 +6,7 @@ from conftest import init_vega
from fixtures.market import setup_simple_market from fixtures.market import setup_simple_market
from wallet_config import MM_WALLET, MM_WALLET2 from wallet_config import MM_WALLET, MM_WALLET2
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def vega(): def vega():
with init_vega() as vega: with init_vega() as vega:
@@ -78,8 +79,9 @@ def verify_prices_descending(page: Page):
prices = [float(price.text_content()) for price in prices_locator.all()] prices = [float(price.text_content()) for price in prices_locator.all()]
assert prices == sorted(prices, reverse=True) assert prices == sorted(prices, reverse=True)
@pytest.mark.skip("tbd") @pytest.mark.skip("tbd")
@pytest.mark.usefixtures("page", "risk_accepted") @pytest.mark.usefixtures("risk_accepted")
def test_orderbook_grid_content(setup_market, page: Page): def test_orderbook_grid_content(setup_market, page: Page):
vega = setup_market[0] vega = setup_market[0]
market_id = setup_market[1] market_id = setup_market[1]
@@ -138,7 +140,7 @@ def test_orderbook_grid_content(setup_market, page: Page):
verify_prices_descending(page) verify_prices_descending(page)
@pytest.mark.usefixtures("page", "risk_accepted") @pytest.mark.usefixtures("risk_accepted")
def test_orderbook_resolution_change(setup_market, page: Page): def test_orderbook_resolution_change(setup_market, page: Page):
market_id = setup_market[1] market_id = setup_market[1]
# 6003-ORDB-008 # 6003-ORDB-008
@@ -188,7 +190,7 @@ def test_orderbook_resolution_change(setup_market, page: Page):
# verify_orderbook_grid(page, resolution[1]) # verify_orderbook_grid(page, resolution[1])
@pytest.mark.usefixtures("page", "risk_accepted") @pytest.mark.usefixtures("risk_accepted")
def test_orderbook_price_size_copy(setup_market, page: Page): def test_orderbook_price_size_copy(setup_market, page: Page):
market_id = setup_market[1] market_id = setup_market[1]
# 6003-ORDB-009 # 6003-ORDB-009
@@ -206,8 +208,9 @@ def test_orderbook_price_size_copy(setup_market, page: Page):
volume.click() volume.click()
expect(page.get_by_test_id("order-size")).to_have_value(volume.text_content()) expect(page.get_by_test_id("order-size")).to_have_value(volume.text_content())
@pytest.mark.skip("tbd") @pytest.mark.skip("tbd")
@pytest.mark.usefixtures("page", "risk_accepted") @pytest.mark.usefixtures("risk_accepted")
def test_orderbook_price_movement(setup_market, page: Page): def test_orderbook_price_movement(setup_market, page: Page):
vega = setup_market[0] vega = setup_market[0]
market_id = setup_market[1] market_id = setup_market[1]
@@ -13,8 +13,8 @@ from wallet_config import MM_WALLET, MM_WALLET2, TERMINATE_WALLET
row_selector = '[data-testid="tab-funding-payments"] .ag-center-cols-container .ag-row' row_selector = '[data-testid="tab-funding-payments"] .ag-center-cols-container .ag-row'
col_amount = '[col-id="amount"]' col_amount = '[col-id="amount"]'
class TestPerpetuals:
class TestPerpetuals:
@pytest.fixture(scope="class") @pytest.fixture(scope="class")
def vega(self, request): def vega(self, request):
with init_vega(request) as vega: with init_vega(request) as vega:
@@ -53,31 +53,33 @@ class TestPerpetuals:
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
return perps_market return perps_market
@pytest.mark.usefixtures("page","risk_accepted", "auth") @pytest.mark.usefixtures("risk_accepted", "auth")
def test_funding_payment_profit(self, perps_market, page: Page): def test_funding_payment_profit(self, perps_market, page: Page):
page.goto(f"/#/markets/{perps_market}") page.goto(f"/#/markets/{perps_market}")
page.get_by_test_id("Funding payments").click() page.get_by_test_id("Funding payments").click()
row = page.locator(row_selector) row = page.locator(row_selector)
expect(row.locator(col_amount)).to_have_text("9.00 tDAI") expect(row.locator(col_amount)).to_have_text("9.00 tDAI")
@pytest.mark.usefixtures("page","risk_accepted", "auth") @pytest.mark.usefixtures("risk_accepted", "auth")
def test_funding_payment_loss(self, perps_market, page: Page, vega): def test_funding_payment_loss(self, perps_market, page: Page, vega):
page.goto(f"/#/markets/{perps_market}") page.goto(f"/#/markets/{perps_market}")
change_keys(page, vega, "market_maker") change_keys(page, vega, "market_maker")
page.get_by_test_id("Funding payments").click() page.get_by_test_id("Funding payments").click()
row = page.locator(row_selector) row = page.locator(row_selector)
expect(row.locator(col_amount)).to_have_text("-27.00 tDAI") expect(row.locator(col_amount)).to_have_text("-27.00 tDAI")
@pytest.mark.usefixtures("page","risk_accepted", "auth") @pytest.mark.usefixtures("risk_accepted", "auth")
def test_funding_header(self, perps_market, page: Page): def test_funding_header(self, perps_market, page: Page):
page.goto(f"/#/markets/{perps_market}") page.goto(f"/#/markets/{perps_market}")
expect(page.get_by_test_id("market-funding")).to_contain_text("Funding Rate / Countdown-8.1818%") expect(page.get_by_test_id("market-funding")).to_contain_text(
"Funding Rate / Countdown-8.1818%"
)
expect(page.get_by_test_id("index-price")).to_have_text("Index Price110.00") expect(page.get_by_test_id("index-price")).to_have_text("Index Price110.00")
@pytest.mark.skip("Skipped due to issue #5421") @pytest.mark.skip("Skipped due to issue #5421")
@pytest.mark.usefixtures("page","risk_accepted", "auth") @pytest.mark.usefixtures("risk_accepted", "auth")
def test_funding_payment_history(perps_market, page: Page, vega): def test_funding_payment_history(perps_market, page: Page, vega):
page.goto(f"/#/markets/{perps_market}") page.goto(f"/#/markets/{perps_market}")
change_keys(page, vega, "market_maker") change_keys(page, vega, "market_maker")
page.get_by_test_id("Funding history").click() page.get_by_test_id("Funding history").click()
element = page.get_by_test_id("tab-funding-history") element = page.get_by_test_id("tab-funding-history")
@@ -92,30 +94,36 @@ class TestPerpetuals:
else: else:
print("Bounding box not found for the element") print("Bounding box not found for the element")
@pytest.mark.usefixtures("page","risk_accepted", "auth")
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_perps_market_termination_proposed(page: Page, vega: VegaService): def test_perps_market_termination_proposed(page: Page, vega: VegaService):
perpetual_market = setup_perps_market(vega) perpetual_market = setup_perps_market(vega)
page.goto(f"/#/markets/{perpetual_market}") page.goto(f"/#/markets/{perpetual_market}")
vega.update_market_state( vega.update_market_state(
proposal_key=MM_WALLET.name, proposal_key=MM_WALLET.name,
market_id=perpetual_market, market_id=perpetual_market,
market_state=MarketStateUpdateType.Terminate, market_state=MarketStateUpdateType.Terminate,
price=100, price=100,
vote_closing_time = datetime.now() + timedelta(seconds=15), vote_closing_time=datetime.now() + timedelta(seconds=15),
vote_enactment_time = datetime.now() + timedelta(seconds=60), vote_enactment_time=datetime.now() + timedelta(seconds=60),
approve_proposal = True, approve_proposal=True,
forward_time_to_enactment = False, forward_time_to_enactment=False,
) )
vega.forward("10s") vega.forward("10s")
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
banner_text = page.get_by_test_id(f"termination-warning-banner-{perpetual_market}").text_content() banner_text = page.get_by_test_id(
f"termination-warning-banner-{perpetual_market}"
).text_content()
pattern = re.compile( pattern = re.compile(
r"Trading on Market BTC:DAI_Perpetual may stop on \d{2} [A-Za-z]+\. There is open proposal to close this market\.Proposed final price is 100\.00 BTC\.View proposal" r"Trading on Market BTC:DAI_Perpetual may stop on \d{2} [A-Za-z]+\. There is open proposal to close this market\.Proposed final price is 100\.00 BTC\.View proposal"
) )
assert pattern.search(banner_text), f"Text did not match pattern. Text was: {banner_text}" assert pattern.search(
banner_text
), f"Text did not match pattern. Text was: {banner_text}"
@pytest.mark.usefixtures("page","risk_accepted", "auth" )
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_perps_market_terminated(page: Page, vega: VegaService): def test_perps_market_terminated(page: Page, vega: VegaService):
perpetual_market = setup_perps_market(vega) perpetual_market = setup_perps_market(vega)
vega.update_market_state( vega.update_market_state(
@@ -123,20 +131,29 @@ def test_perps_market_terminated(page: Page, vega: VegaService):
market_id=perpetual_market, market_id=perpetual_market,
market_state=MarketStateUpdateType.Terminate, market_state=MarketStateUpdateType.Terminate,
price=100, price=100,
approve_proposal = True, approve_proposal=True,
forward_time_to_enactment = True, forward_time_to_enactment=True,
) )
vega.forward("10s") vega.forward("10s")
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
page.goto(f"/#/markets/{perpetual_market}") page.goto(f"/#/markets/{perpetual_market}")
# TODO change back to have text once bug #5465 is fixed
expect(page.get_by_test_id("market-price")).to_have_text("Mark Price100.00") expect(page.get_by_test_id("market-price")).to_have_text("Mark Price100.00")
expect(page.get_by_test_id("market-change")).to_have_text("Change (24h)-") expect(page.get_by_test_id("market-change")).to_contain_text("Change (24h)")
expect(page.get_by_test_id("market-volume")).to_have_text("Volume (24h)-") expect(page.get_by_test_id("market-volume")).to_contain_text("Volume (24h)")
expect(page.get_by_test_id("market-trading-mode")).to_have_text("Trading modeNo trading") expect(page.get_by_test_id("market-trading-mode")).to_have_text(
"Trading modeNo trading"
)
expect(page.get_by_test_id("market-state")).to_have_text("StatusClosed") expect(page.get_by_test_id("market-state")).to_have_text("StatusClosed")
expect(page.get_by_test_id("liquidity-supplied")).to_have_text("Liquidity supplied 0.00 (0.00%)") expect(page.get_by_test_id("liquidity-supplied")).to_have_text(
expect(page.get_by_test_id("market-funding")).to_contain_text("Funding Rate / Countdown") "Liquidity supplied 0.00 (0.00%)"
)
expect(page.get_by_test_id("market-funding")).to_contain_text(
"Funding Rate / Countdown"
)
expect(page.get_by_test_id("index-price")).to_contain_text("Index Price") expect(page.get_by_test_id("index-price")).to_contain_text("Index Price")
expect(page.get_by_test_id("deal-ticket-error-message-summary")).to_have_text("This market is closed and not accepting orders") expect(page.get_by_test_id("deal-ticket-error-message-summary")).to_have_text(
"This market is closed and not accepting orders"
)
+9 -3
View File
@@ -4,13 +4,15 @@ from vega_sim.service import VegaService
from actions.vega import submit_order from actions.vega import submit_order
from actions.utils import change_keys from actions.utils import change_keys
def check_pnl_color_value(element, expected_color, expected_value): def check_pnl_color_value(element, expected_color, expected_value):
color = element.evaluate("element => getComputedStyle(element).color") color = element.evaluate("element => getComputedStyle(element).color")
value = element.inner_text() value = element.inner_text()
assert color == expected_color, f"Unexpected color: {color}" assert color == expected_color, f"Unexpected color: {color}"
assert value == expected_value, f"Unexpected value: {value}" assert value == expected_value, f"Unexpected value: {value}"
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_pnl(continuous_market, vega: VegaService, page: Page): def test_pnl(continuous_market, vega: VegaService, page: Page):
page.set_viewport_size({"width": 1748, "height": 977}) page.set_viewport_size({"width": 1748, "height": 977})
submit_order(vega, "Key 1", continuous_market, "SIDE_BUY", 1, 104.50000) submit_order(vega, "Key 1", continuous_market, "SIDE_BUY", 1, 104.50000)
@@ -59,9 +61,13 @@ def test_pnl(continuous_market, vega: VegaService, page: Page):
key_1_unrealised_pnl = key_1.query_selector('xpath=./div[@col-id="unrealisedPNL"]') key_1_unrealised_pnl = key_1.query_selector('xpath=./div[@col-id="unrealisedPNL"]')
key_1_realised_pnl = key_1.query_selector('xpath=./div[@col-id="realisedPNL"]') key_1_realised_pnl = key_1.query_selector('xpath=./div[@col-id="realisedPNL"]')
key_mm_unrealised_pnl = key_mm.query_selector('xpath=./div[@col-id="unrealisedPNL"]') key_mm_unrealised_pnl = key_mm.query_selector(
'xpath=./div[@col-id="unrealisedPNL"]'
)
key_mm_realised_pnl = key_mm.query_selector('xpath=./div[@col-id="realisedPNL"]') key_mm_realised_pnl = key_mm.query_selector('xpath=./div[@col-id="realisedPNL"]')
key_mm2_unrealised_pnl = key_mm2.query_selector('xpath=./div[@col-id="unrealisedPNL"]') key_mm2_unrealised_pnl = key_mm2.query_selector(
'xpath=./div[@col-id="unrealisedPNL"]'
)
key_mm2_realised_pnl = key_mm2.query_selector('xpath=./div[@col-id="realisedPNL"]') key_mm2_realised_pnl = key_mm2.query_selector('xpath=./div[@col-id="realisedPNL"]')
check_pnl_color_value(key_1_realised_pnl, "rgb(0, 0, 0)", "0.00") check_pnl_color_value(key_1_realised_pnl, "rgb(0, 0, 0)", "0.00")
check_pnl_color_value(key_1_unrealised_pnl, "rgb(236, 0, 60)", "-4.00") check_pnl_color_value(key_1_unrealised_pnl, "rgb(236, 0, 60)", "-4.00")
@@ -2,30 +2,31 @@ import os
import pytest import pytest
from playwright.sync_api import Page, expect from playwright.sync_api import Page, expect
from actions.utils import wait_for_toast_confirmation #TODO migrate to jest
@pytest.mark.usefixtures("auth", "risk_accepted", "continuous_market")
@pytest.mark.usefixtures("page", "auth", "risk_accepted", "continuous_market")
def test_ledger_entries_downloads(page: Page): def test_ledger_entries_downloads(page: Page):
page.goto("/#/portfolio") page.goto("/#/portfolio")
page.get_by_test_id("Ledger entries").click() page.get_by_test_id("Ledger entries").click()
expect(page.get_by_test_id("ledger-download-button")).to_be_enabled() expect(page.get_by_test_id("ledger-download-button")).to_be_enabled()
# 7007-LEEN-001 # 7007-LEEN-001
page.get_by_test_id("ledger-download-button").click() page.get_by_test_id("ledger-download-button").click()
#7007-LEEN-009 # 7007-LEEN-009
expect(page.get_by_test_id("toast-content")).to_contain_text(("Your file is ready")) expect(page.get_by_test_id("toast-content")).to_contain_text(("Your file is ready"))
# Get the user's Downloads directory # Get the user's Downloads directory
downloads_directory = os.path.expanduser("~") + "/Downloads/" downloads_directory = os.path.expanduser("~") + "/Downloads/"
# Start waiting for the download # Start waiting for the download
with page.expect_download() as download_info: with page.expect_download() as download_info:
# Perform the action that initiates download # Perform the action that initiates download
page.get_by_role("link", name="Get file here").click() page.get_by_role("link", name="Get file here").click()
download = download_info.value download = download_info.value
# Wait for the download process to complete and save the downloaded file in the Downloads directory # Wait for the download process to complete and save the downloaded file in the Downloads directory
download.save_as(os.path.join(downloads_directory, download.suggested_filename)) download.save_as(os.path.join(downloads_directory, download.suggested_filename))
# Verify the download by asserting that the file exists # Verify the download by asserting that the file exists
downloaded_file_path = os.path.join(downloads_directory, download.suggested_filename) downloaded_file_path = os.path.join(
assert os.path.exists(downloaded_file_path), f"Download failed! File not found at: {downloaded_file_path}" downloads_directory, download.suggested_filename
)
assert os.path.exists(
downloaded_file_path
), f"Download failed! File not found at: {downloaded_file_path}"
@@ -8,44 +8,60 @@ TOOLTIP_LABEL = "margin-health-tooltip-label"
TOOLTIP_VALUE = "margin-health-tooltip-value" TOOLTIP_VALUE = "margin-health-tooltip-value"
COL_ID_USED = ".ag-center-cols-container [col-id='used'] .ag-cell-value" COL_ID_USED = ".ag-center-cols-container [col-id='used'] .ag-cell-value"
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def vega(request): def vega(request):
with init_vega(request) as vega: with init_vega(request) as vega:
yield vega yield vega
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def continuous_market(vega: VegaService): def continuous_market(vega: VegaService):
return setup_continuous_market(vega) return setup_continuous_market(vega)
@pytest.mark.usefixtures("auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_usage_breakdown(continuous_market, page: Page): def test_usage_breakdown(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("Collateral").click() page.get_by_test_id("Collateral").click()
page.locator(".ag-floating-top-container .ag-row [col-id='used']").click() page.locator(".ag-floating-top-container .ag-row [col-id='used']").click()
usage_breakdown = page.get_by_test_id('usage-breakdown') usage_breakdown = page.get_by_test_id("usage-breakdown")
# Verify headers # Verify headers
headers = ['Market', 'Account type', 'Balance', 'Margin health'] headers = ["Market", "Account type", "Balance", "Margin health"]
ag_headers = usage_breakdown.locator('.ag-header-cell-text').element_handles() ag_headers = usage_breakdown.locator(".ag-header-cell-text").element_handles()
for i, header_element in enumerate(ag_headers): for i, header_element in enumerate(ag_headers):
header_text = header_element.text_content() header_text = header_element.text_content()
assert header_text == headers[i] assert header_text == headers[i]
# Other expectations # Other expectations
expect(usage_breakdown.locator('[class="mb-2 text-sm"]')).to_have_text("You have 1,000,000.00 tDAI in total.") expect(usage_breakdown.locator('[class="mb-2 text-sm"]')).to_have_text(
"You have 1,000,000.00 tDAI in total."
)
expect(usage_breakdown.locator(COL_ID_USED).first).to_have_text("8.50269 (0%)") expect(usage_breakdown.locator(COL_ID_USED).first).to_have_text("8.50269 (0%)")
expect(usage_breakdown.locator(COL_ID_USED).nth(1)).to_have_text("999,991.49731 (99%)") expect(usage_breakdown.locator(COL_ID_USED).nth(1)).to_have_text(
"999,991.49731 (99%)"
)
# Maintenance Level # Maintenance Level
expect(usage_breakdown.locator(".ag-center-cols-container [col-id='market.id'] .ag-cell-value").first).to_have_text("2.85556 above maintenance level") expect(
usage_breakdown.locator(
".ag-center-cols-container [col-id='market.id'] .ag-cell-value"
).first
).to_have_text("2.85556 above maintenance level")
# Margin health tooltip # Margin health tooltip
usage_breakdown.get_by_test_id("margin-health-chart-track").hover() usage_breakdown.get_by_test_id("margin-health-chart-track").hover()
tooltip_data = [("maintenance level", "5.64713"), ("search level", "6.21184"), ("initial level", "8.47069"), ("balance", "8.50269"), ("release level", "9.60012")] tooltip_data = [
("maintenance level", "5.64713"),
("search level", "6.21184"),
("initial level", "8.47069"),
("balance", "8.50269"),
("release level", "9.60012"),
]
for index, (label, value) in enumerate(tooltip_data): for index, (label, value) in enumerate(tooltip_data):
expect(page.get_by_test_id(TOOLTIP_LABEL).nth(index)).to_have_text(label) expect(page.get_by_test_id(TOOLTIP_LABEL).nth(index)).to_have_text(label)
expect(page.get_by_test_id(TOOLTIP_VALUE).nth(index)).to_have_text(value) expect(page.get_by_test_id(TOOLTIP_VALUE).nth(index)).to_have_text(value)
page.get_by_test_id("dialog-close").click()
page.get_by_test_id('dialog-close').click()
@@ -5,6 +5,7 @@ from fixtures.market import (
setup_continuous_market, setup_continuous_market,
) )
@pytest.mark.usefixtures("auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_closed_market_position(vega: VegaService, page: Page): def test_closed_market_position(vega: VegaService, page: Page):
market_id = setup_continuous_market(vega) market_id = setup_continuous_market(vega)
@@ -26,4 +27,3 @@ def test_closed_market_position(vega: VegaService, page: Page):
expect(market.get_by_test_id("stack-cell-primary")).to_have_text("BTC:DAI_2023") expect(market.get_by_test_id("stack-cell-primary")).to_have_text("BTC:DAI_2023")
page.get_by_test_id("open-transfer").click() page.get_by_test_id("open-transfer").click()
expect(page.locator(".ag-overlay-panel")).to_have_text("No positions") expect(page.locator(".ag-overlay-panel")).to_have_text("No positions")
@@ -9,10 +9,9 @@ def vega():
yield vega yield vega
@pytest.mark.usefixtures("page", "risk_accepted") @pytest.mark.usefixtures("risk_accepted")
def test_share_usage_data(page: Page): def test_share_usage_data(page: Page):
page.goto("/") page.goto("/")
# page.get_by_test_id("icon-cross").click()
page.get_by_test_id("Settings").click() page.get_by_test_id("Settings").click()
telemetry_switch = page.locator("#switch-settings-telemetry-switch") telemetry_switch = page.locator("#switch-settings-telemetry-switch")
expect(telemetry_switch).to_have_attribute("data-state", "unchecked") expect(telemetry_switch).to_have_attribute("data-state", "unchecked")
@@ -41,7 +40,7 @@ ICON_TO_TOAST = {
} }
@pytest.mark.usefixtures("page", "risk_accepted") @pytest.mark.usefixtures("risk_accepted")
def test_toast_positions(page: Page): def test_toast_positions(page: Page):
page.goto("/") page.goto("/")
page.get_by_test_id("Settings").click() page.get_by_test_id("Settings").click()
@@ -52,7 +51,7 @@ def test_toast_positions(page: Page):
expect(page.locator(f"[{toast_selector}]")).to_be_visible() expect(page.locator(f"[{toast_selector}]")).to_be_visible()
@pytest.mark.usefixtures("page", "risk_accepted") @pytest.mark.usefixtures("risk_accepted")
def test_dark_mode(page: Page): def test_dark_mode(page: Page):
page.goto("/") page.goto("/")
page.get_by_test_id("Settings").click() page.get_by_test_id("Settings").click()
@@ -5,7 +5,7 @@ from fixtures.market import setup_continuous_market, setup_simple_successor_mark
@pytest.fixture @pytest.fixture
@pytest.mark.usefixtures("vega") @pytest.mark.usefixtures()
def successor_market(vega: VegaService): def successor_market(vega: VegaService):
parent_market_id = setup_continuous_market(vega) parent_market_id = setup_continuous_market(vega)
tdai_id = vega.find_asset_id(symbol="tDAI") tdai_id = vega.find_asset_id(symbol="tDAI")
@@ -23,8 +23,7 @@ def successor_market(vega: VegaService):
return successor_market_id return successor_market_id
@pytest.mark.usefixtures("risk_accepted")
@pytest.mark.usefixtures("page", "risk_accepted")
def test_succession_line(page: Page, successor_market): def test_succession_line(page: Page, successor_market):
page.goto(f"/#/markets/{successor_market}") page.goto(f"/#/markets/{successor_market}")
page.get_by_test_id("Info").click() page.get_by_test_id("Info").click()
@@ -45,8 +45,10 @@ def verify_data_grid(page: Page, data_test_id, expected_pattern):
raise AssertionError(f"Pattern does not match: {expected} != {actual}") raise AssertionError(f"Pattern does not match: {expected} != {actual}")
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_limit_order_new_trade_top_of_list(continuous_market, vega: VegaService, page: Page): def test_limit_order_new_trade_top_of_list(
continuous_market, vega: VegaService, page: Page
):
submit_order(vega, "Key 1", continuous_market, "SIDE_BUY", 1, 110) submit_order(vega, "Key 1", continuous_market, "SIDE_BUY", 1, 110)
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
@@ -67,7 +69,7 @@ def test_limit_order_new_trade_top_of_list(continuous_market, vega: VegaService,
verify_data_grid(page, "Trades", expected_trade) verify_data_grid(page, "Trades", expected_trade)
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_price_copied_to_deal_ticket(continuous_market, page: Page): def test_price_copied_to_deal_ticket(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("Trades").click() page.get_by_test_id("Trades").click()
@@ -4,10 +4,9 @@ from vega_sim.service import VegaService
from actions.vega import submit_multiple_orders from actions.vega import submit_multiple_orders
@pytest.mark.skip("tbd") @pytest.mark.skip("tbd")
@pytest.mark.usefixtures( @pytest.mark.usefixtures("auth", "risk_accepted")
"page", "vega", "opening_auction_market", "auth", "risk_accepted"
)
def test_trade_match_table(opening_auction_market: str, vega: VegaService, page: Page): def test_trade_match_table(opening_auction_market: str, vega: VegaService, page: Page):
row_locator = ".ag-center-cols-container .ag-row" row_locator = ".ag-center-cols-container .ag-row"
page.goto(f"/#/markets/{opening_auction_market}") page.goto(f"/#/markets/{opening_auction_market}")
@@ -12,7 +12,7 @@
# InfoItem = namedtuple('InfoItem', ['name', 'infoText']) # InfoItem = namedtuple('InfoItem', ['name', 'infoText'])
# @pytest.mark.skip("temporary skip") # @pytest.mark.skip("temporary skip")
# @pytest.mark.parametrize("vega", [120], indirect=True) # @pytest.mark.parametrize(, [120], indirect=True)
# @pytest.mark.usefixtures("continuous_market","risk_accepted", "auth") # @pytest.mark.usefixtures("continuous_market","risk_accepted", "auth")
# def test_trading_chart(continuous_market, vega: VegaService, page: Page): # def test_trading_chart(continuous_market, vega: VegaService, page: Page):
# page.goto(f"/#/markets/{continuous_market}") # page.goto(f"/#/markets/{continuous_market}")
@@ -2,7 +2,13 @@ import pytest
import re import re
from playwright.sync_api import Page, expect from playwright.sync_api import Page, expect
from vega_sim.service import VegaService from vega_sim.service import VegaService
from actions.utils import wait_for_toast_confirmation, create_and_faucet_wallet, WalletConfig, next_epoch, change_keys from actions.utils import (
wait_for_toast_confirmation,
create_and_faucet_wallet,
WalletConfig,
next_epoch,
change_keys,
)
import vega_sim.proto.vega as vega_protos import vega_sim.proto.vega as vega_protos
LIQ = WalletConfig("liq", "liq") LIQ = WalletConfig("liq", "liq")
@@ -10,7 +16,8 @@ PARTY_A = WalletConfig("party_a", "party_a")
PARTY_B = WalletConfig("party_b", "party_b") PARTY_B = WalletConfig("party_b", "party_b")
PARTY_C = WalletConfig("party_c", "party_c") PARTY_C = WalletConfig("party_c", "party_c")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_transfer_submit(continuous_market, vega: VegaService, page: Page): def test_transfer_submit(continuous_market, vega: VegaService, page: Page):
# 1003-TRAN-001 # 1003-TRAN-001
# 1003-TRAN-006 # 1003-TRAN-006
@@ -19,38 +26,50 @@ def test_transfer_submit(continuous_market, vega: VegaService, page: Page):
# 1003-TRAN-009 # 1003-TRAN-009
# 1003-TRAN-010 # 1003-TRAN-010
# 1003-TRAN-023 # 1003-TRAN-023
page.goto('/#/portfolio') page.goto("/#/portfolio")
expect(page.get_by_test_id('transfer-form')).to_be_visible expect(page.get_by_test_id("transfer-form")).to_be_visible
page.get_by_test_id('select-asset').click() page.get_by_test_id("select-asset").click()
expect(page.get_by_test_id('rich-select-option')).to_have_count(1) expect(page.get_by_test_id("rich-select-option")).to_have_count(1)
page.get_by_test_id('rich-select-option').click() page.get_by_test_id("rich-select-option").click()
page.select_option('[data-testid=transfer-form] [name="toVegaKey"]', index=2) page.select_option('[data-testid=transfer-form] [name="toVegaKey"]', index=2)
page.select_option('[data-testid=transfer-form] [name="fromAccount"]', index=1) page.select_option('[data-testid=transfer-form] [name="fromAccount"]', index=1)
expected_asset_text = re.compile(r"tDAI tDAI999991.49731 tDAI.{6}….{4}") expected_asset_text = re.compile(r"tDAI tDAI999991.49731 tDAI.{6}….{4}")
actual_asset_text = page.get_by_test_id('select-asset').text_content().strip() actual_asset_text = page.get_by_test_id("select-asset").text_content().strip()
assert expected_asset_text.search(actual_asset_text), f"Expected pattern not found in {actual_asset_text}" assert expected_asset_text.search(
actual_asset_text
), f"Expected pattern not found in {actual_asset_text}"
page.locator('[data-testid=transfer-form] input[name="amount"]').fill('1') page.locator('[data-testid=transfer-form] input[name="amount"]').fill("1")
expect(page.locator('[data-testid=transfer-form] input[name="amount"]')).not_to_be_empty() expect(
page.locator('[data-testid=transfer-form] input[name="amount"]')
).not_to_be_empty()
page.locator('[data-testid=transfer-form] [type="submit"]').click() page.locator('[data-testid=transfer-form] [type="submit"]').click()
wait_for_toast_confirmation(page) wait_for_toast_confirmation(page)
vega.forward("10s") vega.forward("10s")
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
expected_confirmation_text = re.compile(r"Transfer completeYour transaction has been confirmedView in block explorerTransferTo .{6}….{6}1\.00 tDAI") expected_confirmation_text = re.compile(
actual_confirmation_text = page.get_by_test_id('toast-content').text_content() r"Transfer completeYour transaction has been confirmedView in block explorerTransferTo .{6}….{6}1\.00 tDAI"
assert expected_confirmation_text.search(actual_confirmation_text), f"Expected pattern not found in {actual_confirmation_text}" )
actual_confirmation_text = page.get_by_test_id("toast-content").text_content()
assert expected_confirmation_text.search(
actual_confirmation_text
), f"Expected pattern not found in {actual_confirmation_text}"
@pytest.mark.usefixtures("page", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, page: Page): def test_transfer_vesting_below_minimum(
continuous_market, vega: VegaService, page: Page
):
vega.update_network_parameter( vega.update_network_parameter(
"market_maker", parameter="transfer.minTransferQuantumMultiple", new_value="100000" "market_maker",
parameter="transfer.minTransferQuantumMultiple",
new_value="100000",
) )
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
@@ -94,28 +113,34 @@ def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, pa
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
next_epoch(vega=vega) next_epoch(vega=vega)
next_epoch(vega=vega) next_epoch(vega=vega)
page.goto('/#/portfolio') page.goto("/#/portfolio")
expect(page.get_by_test_id('transfer-form')).to_be_visible expect(page.get_by_test_id("transfer-form")).to_be_visible
change_keys(page, vega, "party_b") change_keys(page, vega, "party_b")
page.get_by_test_id('select-asset').click() page.get_by_test_id("select-asset").click()
page.get_by_test_id('rich-select-option').click() page.get_by_test_id("rich-select-option").click()
option_value = page.locator('[data-testid="transfer-form"] [name="fromAccount"] option[value^="ACCOUNT_TYPE_VESTED_REWARDS"]').first.get_attribute("value") option_value = page.locator(
'[data-testid="transfer-form"] [name="fromAccount"] option[value^="ACCOUNT_TYPE_VESTED_REWARDS"]'
).first.get_attribute("value")
page.select_option('[data-testid="transfer-form"] [name="fromAccount"]', option_value) page.select_option(
'[data-testid="transfer-form"] [name="fromAccount"]', option_value
)
page.locator('[data-testid=transfer-form] input[name="amount"]').fill('0.000001') page.locator('[data-testid=transfer-form] input[name="amount"]').fill("0.000001")
page.locator('[data-testid=transfer-form] [type="submit"]').click() page.locator('[data-testid=transfer-form] [type="submit"]').click()
expect(page.get_by_test_id('input-error-text')).to_be_visible expect(page.get_by_test_id("input-error-text")).to_be_visible
expect(page.get_by_test_id('input-error-text')).to_have_text("Amount below minimum requirements for partial transfer. Use max to bypass") expect(page.get_by_test_id("input-error-text")).to_have_text(
"Amount below minimum requirements for partial transfer. Use max to bypass"
)
vega.one_off_transfer( vega.one_off_transfer(
from_key_name=PARTY_B.name, from_key_name=PARTY_B.name,
to_key_name=PARTY_B.name, to_key_name=PARTY_B.name,
from_account_type= vega_protos.vega.AccountType.ACCOUNT_TYPE_VESTED_REWARDS, from_account_type=vega_protos.vega.AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
to_account_type= vega_protos.vega.AccountType.ACCOUNT_TYPE_GENERAL, to_account_type=vega_protos.vega.AccountType.ACCOUNT_TYPE_GENERAL,
asset= asset_id, asset=asset_id,
amount= 24.999999, amount=24.999999,
) )
vega.forward("10s") vega.forward("10s")
vega.wait_fn(10) vega.wait_fn(10)
@@ -127,6 +152,10 @@ def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, pa
vega.forward("10s") vega.forward("10s")
vega.wait_fn(1) vega.wait_fn(1)
vega.wait_for_total_catchup() vega.wait_for_total_catchup()
expected_confirmation_text = re.compile(r"Transfer completeYour transaction has been confirmedView in block explorerTransferTo .{6}….{6}0\.00001 tDAI") expected_confirmation_text = re.compile(
actual_confirmation_text = page.get_by_test_id('toast-content').text_content() r"Transfer completeYour transaction has been confirmedView in block explorerTransferTo .{6}….{6}0\.00001 tDAI"
assert expected_confirmation_text.search(actual_confirmation_text), f"Expected pattern not found in {actual_confirmation_text}" )
actual_confirmation_text = page.get_by_test_id("toast-content").text_content()
assert expected_confirmation_text.search(
actual_confirmation_text
), f"Expected pattern not found in {actual_confirmation_text}"
+63 -45
View File
@@ -15,6 +15,7 @@ tif = "order-tif"
expire = "expire" expire = "expire"
api_request_match = r"http://localhost:\d+/api/v2/requests" api_request_match = r"http://localhost:\d+/api/v2/requests"
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def vega(request): def vega(request):
with init_vega(request) as vega: with init_vega(request) as vega:
@@ -25,50 +26,59 @@ def vega(request):
def continuous_market(vega): def continuous_market(vega):
return setup_continuous_market(vega) return setup_continuous_market(vega)
def handle_route_connection_lost(route: Route, request): def handle_route_connection_lost(route: Route, request):
if request.method == "POST" and re.match(api_request_match, request.url): if request.method == "POST" and re.match(api_request_match, request.url):
route.fulfill( route.fulfill(
status=200, status=200,
headers={"Content-Type": "application/json"}, headers={"Content-Type": "application/json"},
body='{"jsonrpc": "2.0", "id": "1"}' body='{"jsonrpc": "2.0", "id": "1"}',
) )
else: else:
route.continue_() route.continue_()
def handle_route_connection_rejected(route: Route, request): def handle_route_connection_rejected(route: Route, request):
if request.method == "POST" and re.match(api_request_match, request.url): if request.method == "POST" and re.match(api_request_match, request.url):
custom_response = { custom_response = {
"jsonrpc": "2.0", "jsonrpc": "2.0",
"error": { "error": {
"code": 3001, "code": 3001,
"data": "the user rejected the wallet connection", "data": "the user rejected the wallet connection",
"message": "User error" "message": "User error",
}, },
"id": "0" "id": "0",
} }
route.fulfill( route.fulfill(
status=400, status=400,
headers={"Content-Type": "application/json"}, headers={"Content-Type": "application/json"},
body=json.dumps(custom_response) body=json.dumps(custom_response),
) )
else: else:
route.continue_() route.continue_()
def assert_connection_approve(route: Route, request, page:Page):
if request.method == "POST" and re.match(api_request_match, request.url):
expect(page.get_by_test_id("toast-content")).to_have_text("Please go to your Vega wallet application and approve or reject the transaction.")
else:
route.continue_()
@pytest.mark.usefixtures("page", "auth", "risk_accepted") def assert_connection_approve(route: Route, request, page: Page):
if request.method == "POST" and re.match(api_request_match, request.url):
expect(page.get_by_test_id("toast-content")).to_have_text(
"Please go to your Vega wallet application and approve or reject the transaction."
)
else:
route.continue_()
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_wallet_connection_error(continuous_market, page: Page): def test_wallet_connection_error(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.route("**/*", handle_route_connection_lost) page.route("**/*", handle_route_connection_lost)
page.get_by_test_id("connect-vega-wallet").click() page.get_by_test_id("connect-vega-wallet").click()
page.get_by_test_id("connector-jsonRpc").click() page.get_by_test_id("connector-jsonRpc").click()
expect(page.get_by_test_id("wallet-dialog-title")).to_have_text("Something went wrong") expect(page.get_by_test_id("wallet-dialog-title")).to_have_text(
"Something went wrong"
)
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_wallet_connection_rejected(continuous_market, page: Page): def test_wallet_connection_rejected(continuous_market, page: Page):
# 0002-WCON-002 # 0002-WCON-002
# 0002-WCON-005 # 0002-WCON-005
@@ -78,11 +88,13 @@ def test_wallet_connection_rejected(continuous_market, page: Page):
page.route("**/*", handle_route_connection_rejected) page.route("**/*", handle_route_connection_rejected)
page.get_by_test_id("connect-vega-wallet").click() page.get_by_test_id("connect-vega-wallet").click()
page.get_by_test_id("connector-jsonRpc").click() page.get_by_test_id("connector-jsonRpc").click()
expect(page.get_by_test_id("dialog-content").nth(1)).to_have_text("User errorthe user rejected the wallet connectionTry againAbout the Vega wallet | Supported browsers ") expect(page.get_by_test_id("dialog-content").nth(1)).to_have_text(
"User errorthe user rejected the wallet connectionTry againAbout the Vega wallet | Supported browsers "
)
@pytest.mark.usefixtures("page", "auth", "risk_accepted") @pytest.mark.usefixtures("auth", "risk_accepted")
def test_wallet_connection_error_transaction(continuous_market, vega: VegaService, page: Page): def test_wallet_connection_error_transaction(continuous_market, page: Page):
# 0003-WTXN-009 # 0003-WTXN-009
# 0003-WTXN-011 # 0003-WTXN-011
# 0002-WCON-016 # 0002-WCON-016
@@ -92,20 +104,26 @@ def test_wallet_connection_error_transaction(continuous_market, vega: VegaServic
page.get_by_test_id(order_price).fill("120") page.get_by_test_id(order_price).fill("120")
page.route("**/*", handle_route_connection_lost) page.route("**/*", handle_route_connection_lost)
page.get_by_test_id(place_order).click() page.get_by_test_id(place_order).click()
expect(page.get_by_test_id("toast-content")).to_have_text("Wallet disconnectedThe connection to your Vega Wallet has been lost.Connect vega wallet") expect(page.get_by_test_id("toast-content")).to_have_text(
"Wallet disconnectedThe connection to your Vega Wallet has been lost.Connect vega wallet"
@pytest.mark.usefixtures("page", "auth", "risk_accepted") )
def test_wallet_transaction_rejected(continuous_market, vega: VegaService, page: Page):
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_wallet_transaction_rejected(continuous_market, page: Page):
# 0003-WTXN-007 # 0003-WTXN-007
page.goto(f"/#/markets/{continuous_market}") page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(order_size).fill("10") page.get_by_test_id(order_size).fill("10")
page.get_by_test_id(order_price).fill("120") page.get_by_test_id(order_price).fill("120")
page.route("**/*", handle_route_connection_rejected) page.route("**/*", handle_route_connection_rejected)
page.get_by_test_id(place_order).click() page.get_by_test_id(place_order).click()
expect(page.get_by_test_id("toast-content")).to_have_text("Error occurredthe user rejected the wallet connection") expect(page.get_by_test_id("toast-content")).to_have_text(
"Error occurredthe user rejected the wallet connection"
@pytest.mark.usefixtures("page", "auth", "risk_accepted") )
def test_wallet_connection_approve(continuous_market, vega: VegaService, page: Page):
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_wallet_connection_approve(continuous_market, page: Page):
# 0002-WCON-005 # 0002-WCON-005
# 0002-WCON-007 # 0002-WCON-007
# 0002-WCON-009 # 0002-WCON-009
@@ -113,4 +131,4 @@ def test_wallet_connection_approve(continuous_market, vega: VegaService, page: P
page.get_by_test_id(order_size).fill("10") page.get_by_test_id(order_size).fill("10")
page.get_by_test_id(order_price).fill("120") page.get_by_test_id(order_price).fill("120")
page.route("**/*", assert_connection_approve) page.route("**/*", assert_connection_approve)
page.get_by_test_id(place_order).click() page.get_by_test_id(place_order).click()
+10 -1
View File
@@ -4,9 +4,18 @@ export default {
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
transform: { transform: {
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/next/babel'] }], '^.+\\.[tj]sx?$': [
'babel-jest',
{
presets: ['@nx/next/babel'],
// required for pennant to work in jest, due to having untranspiled exports
plugins: [['@babel/plugin-proposal-private-methods']],
},
],
}, },
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/apps/trading', coverageDirectory: '../../coverage/apps/trading',
setupFilesAfterEnv: ['./setup-tests.ts'], setupFilesAfterEnv: ['./setup-tests.ts'],
// dont ignore pennant from transpilation
transformIgnorePatterns: ['<rootDir>/node_modules/pennant'],
}; };
@@ -1,9 +1,9 @@
import { routerConfig } from '../../pages/client-router'; import { useRouterConfig } from '../../pages/client-router';
import { matchRoutes, useLocation } from 'react-router-dom'; import { matchRoutes, useLocation } from 'react-router-dom';
export const useGetCurrentRouteId = () => { export const useGetCurrentRouteId = () => {
const location = useLocation(); const location = useLocation();
const matches = matchRoutes(routerConfig, location); const matches = matchRoutes(useRouterConfig(), location);
const lastRoute = matches ? matches[matches.length - 1] : undefined; const lastRoute = matches ? matches[matches.length - 1] : undefined;
if (lastRoute) { if (lastRoute) {
const id = lastRoute.route.id; const id = lastRoute.route.id;
@@ -0,0 +1,62 @@
import {
Intent,
useToasts,
ToastHeading,
CLOSE_AFTER,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useEffect, useMemo } from 'react';
import { useT } from '../use-t';
import { VegaWalletConnectButton } from '../../components/vega-wallet-connect-button';
const WALLET_DISCONNECTED_TOAST_ID = 'WALLET_DISCONNECTED_TOAST_ID';
export const useWalletDisconnectedToasts = () => {
const t = useT();
const [hasToast, setToast, updateToast] = useToasts((state) => [
state.hasToast,
state.setToast,
state.update,
]);
const { isAlive } = useVegaWallet();
const toast = useMemo(
() => ({
id: WALLET_DISCONNECTED_TOAST_ID,
intent: Intent.Danger,
content: (
<>
<ToastHeading>{t('Wallet connection lost')}</ToastHeading>
<p>{t('The connection to the Vega wallet has been lost.')}</p>
<p className="mt-2">
<VegaWalletConnectButton
intent={Intent.Danger}
onClick={() => {
updateToast(WALLET_DISCONNECTED_TOAST_ID, {
hidden: true,
});
}}
/>
</p>
</>
),
onClose: () => {
updateToast(WALLET_DISCONNECTED_TOAST_ID, {
hidden: true,
});
},
closeAfter: CLOSE_AFTER,
}),
[t, updateToast]
);
useEffect(() => {
if (isAlive === false) {
if (hasToast(WALLET_DISCONNECTED_TOAST_ID)) {
updateToast(WALLET_DISCONNECTED_TOAST_ID, { hidden: false });
} else {
setToast(toast);
}
}
}, [hasToast, isAlive, setToast, t, toast, updateToast]);
};

Some files were not shown because too many files have changed in this diff Show More