Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf519fbfaa | ||
|
|
c7bc64abfb | ||
|
|
7f60485c59 |
@@ -4,8 +4,8 @@ const marketName = 'ACTIVE MARKET';
|
||||
describe('market selector', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockConsole();
|
||||
cy.setVegaWallet();
|
||||
cy.visit(`/trading/${marketId}`);
|
||||
cy.connectVegaWallet();
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
@@ -67,7 +67,6 @@ describe('market selector', { tags: '@smoke' }, () => {
|
||||
it('mobile view', () => {
|
||||
cy.viewport('iphone-xr');
|
||||
cy.visit(`/trading/${marketId}`);
|
||||
cy.connectVegaWallet();
|
||||
cy.get('[role="dialog"]').should('not.exist');
|
||||
cy.getByTestId('arrow-button').click();
|
||||
cy.get('[role="dialog"]').should('be.visible');
|
||||
|
||||
@@ -51,8 +51,8 @@ describe('Market trade', { tags: '@regression' }, () => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Market', marketQuery(marketOverride));
|
||||
});
|
||||
cy.setVegaWallet();
|
||||
cy.visit(`/trading/${marketId}`);
|
||||
cy.connectVegaWallet();
|
||||
cy.wait('@Market');
|
||||
});
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
|
||||
describe('Portfolio page - wallet', { tags: '@smoke' }, () => {
|
||||
it('button for wallet connect should work', () => {
|
||||
cy.mockConsole();
|
||||
cy.visit('/');
|
||||
cy.get('[href="/portfolio"]').eq(0).click();
|
||||
cy.getByTestId('trading-connect-wallet').should('be.visible');
|
||||
@@ -35,11 +34,11 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
|
||||
aliasGQLQuery(req, 'Accounts', accountsQuery());
|
||||
aliasGQLQuery(req, 'Assets', assetsQuery());
|
||||
});
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('certain tabs should exist', () => {
|
||||
cy.visit('/portfolio');
|
||||
cy.connectVegaWallet();
|
||||
|
||||
cy.getByTestId('assets').click();
|
||||
cy.location('pathname').should('eq', '/portfolio/assets');
|
||||
@@ -58,15 +57,28 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
describe('Assets view', () => {
|
||||
beforeEach(() => {
|
||||
cy.mockConsole();
|
||||
cy.setVegaWallet();
|
||||
before(() => {
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'ChainId', chainIdQuery());
|
||||
aliasGQLQuery(req, 'Statistics', statisticsQuery());
|
||||
aliasGQLQuery(req, 'Positions', positionsQuery());
|
||||
aliasGQLQuery(req, 'Margins', marginsQuery());
|
||||
aliasGQLQuery(req, 'Markets', marketsQuery());
|
||||
aliasGQLQuery(req, 'MarketsData', marketsDataQuery());
|
||||
aliasGQLQuery(req, 'Accounts', accountsQuery());
|
||||
aliasGQLQuery(req, 'Assets', assetsQuery());
|
||||
});
|
||||
cy.visit('/portfolio/assets');
|
||||
cy.connectVegaWallet();
|
||||
});
|
||||
|
||||
it('data should be properly rendered', () => {
|
||||
cy.get('.ag-center-cols-container .ag-row').should('have.length', 5);
|
||||
cy.get('[title="tEURO"] button').click();
|
||||
cy.get(
|
||||
'.ag-center-cols-container [row-id="ACCOUNT_TYPE_GENERAL-asset-id-null"]'
|
||||
)
|
||||
.find('button')
|
||||
.click();
|
||||
cy.getByTestId('dialog-title').should(
|
||||
'have.text',
|
||||
'Asset details - tEURO'
|
||||
@@ -87,8 +99,8 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
|
||||
aliasGQLQuery(req, 'Accounts', accountsQuery());
|
||||
aliasGQLQuery(req, 'Assets', assetsQuery());
|
||||
});
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/portfolio/positions');
|
||||
cy.connectVegaWallet();
|
||||
});
|
||||
|
||||
it('data should be properly rendered', () => {
|
||||
@@ -104,8 +116,8 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
|
||||
aliasGQLQuery(req, 'Orders', ordersQuery());
|
||||
aliasGQLQuery(req, 'Markets', marketsQuery());
|
||||
});
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/portfolio/orders');
|
||||
cy.connectVegaWallet();
|
||||
});
|
||||
|
||||
it('data should be properly rendered', () => {
|
||||
@@ -122,8 +134,8 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
|
||||
aliasGQLQuery(req, 'Markets', marketsQuery());
|
||||
aliasGQLQuery(req, 'Fills', fillsQuery());
|
||||
});
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/portfolio/fills');
|
||||
cy.connectVegaWallet();
|
||||
});
|
||||
|
||||
it('data should be properly rendered', () => {
|
||||
@@ -149,8 +161,8 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
|
||||
aliasGQLQuery(req, 'Margins', marginsQuery());
|
||||
aliasGQLQuery(req, 'MarketsData', marketsDataQuery());
|
||||
});
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/portfolio');
|
||||
cy.connectVegaWallet();
|
||||
});
|
||||
|
||||
it('"No data to display" should be always displayed', () => {
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
marketsCandlesQuery,
|
||||
marketsDataQuery,
|
||||
marketsQuery,
|
||||
networkParamsQuery,
|
||||
ordersQuery,
|
||||
positionsQuery,
|
||||
statisticsQuery,
|
||||
@@ -48,7 +47,6 @@ const mockPage = (req: CyHttpMessages.IncomingHttpRequest) => {
|
||||
aliasGQLQuery(req, 'SimpleMarkets', marketsQuery());
|
||||
aliasGQLQuery(req, 'Orders', ordersQuery());
|
||||
aliasGQLQuery(req, 'Fills', fillsQuery());
|
||||
aliasGQLQuery(req, 'NetworkParams', networkParamsQuery());
|
||||
};
|
||||
|
||||
export const addMockConsole = () => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
useOrderMargin,
|
||||
useMaximumPositionSize,
|
||||
useCalculateSlippage,
|
||||
validateAmount,
|
||||
} from '@vegaprotocol/deal-ticket';
|
||||
import { InputError } from '@vegaprotocol/ui-toolkit';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
@@ -22,7 +23,6 @@ import {
|
||||
addDecimalsFormatNumber,
|
||||
addDecimal,
|
||||
formatNumber,
|
||||
validateAmount,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
useOrderSubmit,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import type { FieldErrors } from 'react-hook-form';
|
||||
import { useMemo } from 'react';
|
||||
import { DataGrid, t, toDecimal } from '@vegaprotocol/react-helpers';
|
||||
import { t, toDecimal } from '@vegaprotocol/react-helpers';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
MarketDataGrid,
|
||||
compileGridData,
|
||||
MarginWarning,
|
||||
isMarketInAuction,
|
||||
@@ -215,7 +216,9 @@ export const useOrderValidation = ({
|
||||
<span>
|
||||
{t('This market is in auction until it reaches')}{' '}
|
||||
<Tooltip
|
||||
description={<DataGrid grid={compileGridData(market)} />}
|
||||
description={
|
||||
<MarketDataGrid grid={compileGridData(market)} />
|
||||
}
|
||||
>
|
||||
<span>{t('sufficient liquidity')}</span>
|
||||
</Tooltip>
|
||||
@@ -237,7 +240,9 @@ export const useOrderValidation = ({
|
||||
<span>
|
||||
{t('This market is in auction due to')}{' '}
|
||||
<Tooltip
|
||||
description={<DataGrid grid={compileGridData(market)} />}
|
||||
description={
|
||||
<MarketDataGrid grid={compileGridData(market)} />
|
||||
}
|
||||
>
|
||||
<span>{t('high price volatility')}</span>
|
||||
</Tooltip>
|
||||
@@ -276,7 +281,9 @@ export const useOrderValidation = ({
|
||||
<span>
|
||||
{t('This market is in auction until it reaches')}{' '}
|
||||
<Tooltip
|
||||
description={<DataGrid grid={compileGridData(market)} />}
|
||||
description={
|
||||
<MarketDataGrid grid={compileGridData(market)} />
|
||||
}
|
||||
>
|
||||
<span>{t('sufficient liquidity')}</span>
|
||||
</Tooltip>
|
||||
@@ -300,7 +307,9 @@ export const useOrderValidation = ({
|
||||
<span>
|
||||
{t('This market is in auction due to')}{' '}
|
||||
<Tooltip
|
||||
description={<DataGrid grid={compileGridData(market)} />}
|
||||
description={
|
||||
<MarketDataGrid grid={compileGridData(market)} />
|
||||
}
|
||||
>
|
||||
<span>{t('high price volatility')}</span>
|
||||
</Tooltip>
|
||||
|
||||
@@ -4,7 +4,6 @@ NX_TENDERMINT_URL=https://n04.d.vega.xyz/tm
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://n04.d.vega.xyz/tm/websocket
|
||||
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
|
||||
NX_VEGA_ENV=DEVNET
|
||||
NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
|
||||
@@ -4,7 +4,6 @@ NX_TENDERMINT_URL=https://mainnet-observer-proxy01.ops.vega.xyz/
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocket
|
||||
NX_VEGA_URL=https://api.vega.xyz/query
|
||||
NX_VEGA_ENV=MAINNET
|
||||
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
|
||||
@@ -4,7 +4,6 @@ NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n00.stagnet3.vega.xyz/websocket
|
||||
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
|
||||
NX_VEGA_ENV=STAGNET3
|
||||
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
|
||||
@@ -4,7 +4,6 @@ NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz/tm
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket
|
||||
NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
|
||||
NX_VEGA_ENV=TESTNET
|
||||
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
|
||||
@@ -21,12 +21,7 @@ The e2e tests run against a locally running instance of the Vega network, manage
|
||||
- Install the required Vega smart contracts
|
||||
- Set up DataNodes with a running GraphQL and REST APIs.
|
||||
|
||||
1. Refer to the [Vega Capsule readme](https://github.com/vegaprotocol/vegacapsule#readme) for setting up and running Capsule - follow by Pre-start and Quick Start (points 1-2)
|
||||
2. Bootstrap with auto-installed dependencies including wallet
|
||||
|
||||
```bash
|
||||
vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl --force
|
||||
```
|
||||
Refer to the [Vega Capsule readme](https://github.com/vegaprotocol/vegacapsule#readme) for setting up and running Capsule. You will need [Go 1.19 or later](https://go.dev/doc/install) and [Docker](https://docs.docker.com/get-docker/) installed.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
@@ -34,6 +29,6 @@ vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/con
|
||||
|
||||
## Vega Wallet Setup
|
||||
|
||||
You can then refer to (or run) `frontend-monorepo/vegacapsule/setup-vegawallet.sh`. This will initialise and configure your wallet to have the correct public keys and network config to run against capsule.
|
||||
Start by [downloading the Vega wallet software here](https://github.com/vegaprotocol/vega/releases).
|
||||
|
||||
Go to the .env file in `apps/explorer-e2e` and set the `CYPRESS_VEGA_WALLET_API_TOKEN` environment variable by pasting in your wallets long lived api token
|
||||
You can then refer to (or run) `vegacapsule/setup-vegawallet.sh`. This will initialise and configure your wallet to have the correct public keys and network config to run against capsule.
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"market.liquidity.maximumLiquidityFeeFactorLevel",
|
||||
"market.liquidity.minimum.probabilityOfTrading.lpOrders",
|
||||
"market.liquidity.probabilityOfTrading.tau.scaling",
|
||||
"market.liquidity.stakeToCcyVolume",
|
||||
"market.liquidity.stakeToCcySiskas",
|
||||
"market.liquidity.targetstake.triggering.ratio",
|
||||
"market.liquidityProvision.minLpStakeQuantumMultiple",
|
||||
"market.liquidityProvision.shapes.maxSize",
|
||||
|
||||
@@ -52,8 +52,7 @@ context('Blocks page', { tags: '@regression' }, function () {
|
||||
});
|
||||
});
|
||||
|
||||
// Skipping - see https://github.com/vegaprotocol/frontend-monorepo/issues/2494
|
||||
it.skip('Previous button disabled on first block', function () {
|
||||
it('Previous button disabled on first block', function () {
|
||||
cy.get('[data-testid="block-input"]').type('1');
|
||||
cy.get('[data-testid="go-submit"]').click();
|
||||
cy.get(previousBlockBtn).find('button').should('be.disabled');
|
||||
@@ -116,7 +115,7 @@ context('Blocks page', { tags: '@regression' }, function () {
|
||||
});
|
||||
|
||||
function waitForBlocksResponse() {
|
||||
cy.get('[data-testid="loader"]').should('not.exist', { timeout: 18000 });
|
||||
cy.contains('Loading...').should('not.exist', { timeout: 18000 });
|
||||
}
|
||||
|
||||
function validateBlocksDisplayed() {
|
||||
|
||||
@@ -20,18 +20,19 @@ context('Home Page', function () {
|
||||
1: 'Height',
|
||||
2: 'Uptime',
|
||||
3: 'Total nodes',
|
||||
4: 'Total staked',
|
||||
5: 'Backlog',
|
||||
6: 'Trades / second',
|
||||
7: 'Orders / block',
|
||||
8: 'Orders / second',
|
||||
9: 'Transactions / block',
|
||||
10: 'Block time',
|
||||
11: 'Time',
|
||||
12: 'App',
|
||||
13: 'Tendermint',
|
||||
14: 'Up since',
|
||||
15: 'Chain ID',
|
||||
4: 'Inactive nodes',
|
||||
5: 'Total staked',
|
||||
6: 'Backlog',
|
||||
7: 'Trades / second',
|
||||
8: 'Orders / block',
|
||||
9: 'Orders / second',
|
||||
10: 'Transactions / block',
|
||||
11: 'Block time',
|
||||
12: 'Time',
|
||||
13: 'App',
|
||||
14: 'Tendermint',
|
||||
15: 'Up since',
|
||||
16: 'Chain ID',
|
||||
};
|
||||
|
||||
cy.get('[data-testid="stats-title"]')
|
||||
@@ -39,7 +40,7 @@ context('Home Page', function () {
|
||||
cy.wrap($list).should('have.text', statTitles[index]);
|
||||
})
|
||||
.then(($list) => {
|
||||
cy.wrap($list).should('have.length', 16);
|
||||
cy.wrap($list).should('have.length', 17);
|
||||
});
|
||||
|
||||
cy.get(statsValue).eq(0).should('have.text', 'CONNECTED');
|
||||
@@ -49,29 +50,30 @@ context('Home Page', function () {
|
||||
.invoke('text')
|
||||
.should('match', /\d+d \d+h \d+m \d+s/i);
|
||||
cy.get(statsValue).eq(3).should('have.text', '2');
|
||||
cy.get(statsValue).eq(4).should('have.text', '2');
|
||||
cy.get(statsValue)
|
||||
.eq(4)
|
||||
.eq(5)
|
||||
.invoke('text')
|
||||
.should('match', /\d+\.\d\d(?!\d)/i);
|
||||
cy.get(statsValue).eq(5).should('have.text', '0');
|
||||
cy.get(statsValue).eq(6).should('have.text', '0');
|
||||
cy.get(statsValue).eq(7).should('have.text', '0');
|
||||
cy.get(statsValue).eq(8).should('have.text', '0');
|
||||
cy.get(statsValue).eq(9).should('not.be.empty');
|
||||
cy.get(statsValue).eq(9).should('have.text', '0');
|
||||
cy.get(statsValue).eq(10).should('not.be.empty');
|
||||
cy.get(statsValue).eq(11).should('not.be.empty');
|
||||
cy.get(statsValue).eq(12).should('not.be.empty');
|
||||
if (Cypress.env('NIGHTLY_RUN') != true) {
|
||||
cy.get(statsValue)
|
||||
.eq(12)
|
||||
.eq(13)
|
||||
.invoke('text')
|
||||
.should('match', /v\d+\.\d+\.\d+/i);
|
||||
}
|
||||
cy.get(statsValue)
|
||||
.eq(13)
|
||||
.eq(14)
|
||||
.invoke('text')
|
||||
.should('match', /\d+\.\d+\.\d+/i);
|
||||
cy.get(statsValue).eq(14).should('not.be.empty');
|
||||
cy.get(statsValue).eq(15).should('not.be.empty');
|
||||
cy.get(statsValue).eq(16).should('not.be.empty');
|
||||
});
|
||||
|
||||
it('Block height should be updating', function () {
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.65.1/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
||||
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.62.1/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -59,8 +59,7 @@ describe('Blocks infinite list', () => {
|
||||
error={undefined}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByTestId('emptylist')).toBeInTheDocument();
|
||||
expect(screen.getByText('This chain has 0 blocks')).toBeInTheDocument();
|
||||
expect(screen.getByText('No items')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('error is displayed at item level', () => {
|
||||
|
||||
@@ -4,8 +4,6 @@ import InfiniteLoader from 'react-window-infinite-loader';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import type { BlockMeta } from '../../routes/blocks/tendermint-blockchain-response';
|
||||
import { BlockData } from './block-data';
|
||||
import EmptyList from '../empty-list/empty-list';
|
||||
import { Loader } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
interface BlocksInfiniteListProps {
|
||||
hasMoreBlocks: boolean;
|
||||
@@ -33,16 +31,7 @@ export const BlocksInfiniteList = ({
|
||||
className,
|
||||
}: BlocksInfiniteListProps) => {
|
||||
if (!blocks) {
|
||||
if (!areBlocksLoading) {
|
||||
return (
|
||||
<EmptyList
|
||||
heading={t('This chain has 0 blocks')}
|
||||
label={t('Check back soon')}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return <Loader />;
|
||||
}
|
||||
return <div>No items</div>;
|
||||
}
|
||||
|
||||
// If there are more items to be loaded then add an extra row to hold a loading indicator.
|
||||
@@ -61,7 +50,7 @@ export const BlocksInfiniteList = ({
|
||||
if (error) {
|
||||
content = t(`${error}`);
|
||||
} else if (!isItemLoaded(index)) {
|
||||
content = <Loader />;
|
||||
content = t('Loading...');
|
||||
} else {
|
||||
content = <BlockData block={blocks[index]} />;
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
export type EmptyListProps = {
|
||||
heading?: string;
|
||||
label?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the empty state from github ticket #1463
|
||||
*/
|
||||
const EmptyList = ({ heading, label }: EmptyListProps) => {
|
||||
return (
|
||||
<div
|
||||
className="empty-list w-full items-center h-full align-center"
|
||||
data-testid="emptylist"
|
||||
>
|
||||
<div className="skeleton-list border-dashed border-neutral-800 rounded p-5 w-full border-[1px] grid gap-4 grid-cols-9 grid-rows-1 place-content-around mb-4">
|
||||
<div className="bg-neutral-900 mr-5 h-3 col-span-5"></div>
|
||||
<div className="bg-neutral-900 h-3 col-span-1"></div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
{heading ? (
|
||||
<h1 className="font-alpha text-xl uppercase text-center leading-relaxed">
|
||||
{heading}
|
||||
</h1>
|
||||
) : null}
|
||||
{label ? (
|
||||
<p className="font-alpha text-gray-500 text-center">{label}</p>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmptyList;
|
||||
@@ -14,6 +14,8 @@ export const methodText: Record<
|
||||
METHOD_NOW: 'Immediate',
|
||||
METHOD_UNSPECIFIED: 'Unspecified',
|
||||
METHOD_AT_END_OF_EPOCH: 'End of epoch',
|
||||
// This will be removed in a future release
|
||||
METHOD_IN_ANGER: 'Immediate',
|
||||
};
|
||||
|
||||
interface TxDetailsUndelegateProps {
|
||||
|
||||
@@ -2,3 +2,4 @@ export { TxList } from './tx-list';
|
||||
export { TxOrderType } from './tx-order-type';
|
||||
export { TxsInfiniteList } from './txs-infinite-list';
|
||||
export { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||
export { TxsStatsInfo } from './txs-stats-info';
|
||||
|
||||
@@ -46,10 +46,7 @@ describe('Txs infinite list', () => {
|
||||
error={undefined}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByTestId('emptylist')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('This chain has 0 transactions')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText('No items')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('error is displayed at item level', () => {
|
||||
|
||||
@@ -4,8 +4,6 @@ import InfiniteLoader from 'react-window-infinite-loader';
|
||||
import { t, useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
|
||||
import EmptyList from '../empty-list/empty-list';
|
||||
import { Loader } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
interface TxsInfiniteListProps {
|
||||
hasMoreTxs: boolean;
|
||||
@@ -31,7 +29,7 @@ const Item = ({ index, style, isLoading, error }: ItemProps) => {
|
||||
if (error) {
|
||||
content = t(`Cannot fetch transaction: ${error}`);
|
||||
} else if (isLoading) {
|
||||
content = <Loader />;
|
||||
content = t('Loading...');
|
||||
} else {
|
||||
const {
|
||||
hash,
|
||||
@@ -70,16 +68,7 @@ export const TxsInfiniteList = ({
|
||||
const isStacked = ['xs', 'sm', 'md', 'lg'].includes(screenSize);
|
||||
|
||||
if (!txs) {
|
||||
if (!areTxsLoading) {
|
||||
return (
|
||||
<EmptyList
|
||||
heading={t('This chain has 0 transactions')}
|
||||
label={t('Check back soon')}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return <Loader />;
|
||||
}
|
||||
return <div>No items</div>;
|
||||
}
|
||||
|
||||
// If there are more items to be loaded then add an extra row to hold a loading indicator.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Routes } from '../../routes/route-names';
|
||||
import { DATA_SOURCES } from '../../config';
|
||||
import { RenderFetched } from '../render-fetched';
|
||||
import { TruncatedLink } from '../truncate/truncated-link';
|
||||
import { TxOrderType } from './tx-order-type';
|
||||
@@ -7,9 +8,6 @@ import { t, useFetch } from '@vegaprotocol/react-helpers';
|
||||
import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
|
||||
import isNumber from 'lodash/isNumber';
|
||||
import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code';
|
||||
import { getTxsDataUrl } from '../../hooks/use-txs-data';
|
||||
import { Loader } from '@vegaprotocol/ui-toolkit';
|
||||
import EmptyList from '../empty-list/empty-list';
|
||||
|
||||
interface TxsPerBlockProps {
|
||||
blockHeight: string;
|
||||
@@ -19,11 +17,15 @@ interface TxsPerBlockProps {
|
||||
const truncateLength = 5;
|
||||
|
||||
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
||||
const filters = `filters[block.height]=${blockHeight}`;
|
||||
const url = getTxsDataUrl({ limit: txCount.toString(), filters });
|
||||
// TODO after https://github.com/vegaprotocol/vega/pull/6958/files is merged and deployed, use filter
|
||||
// by block height instead
|
||||
const {
|
||||
state: { data, loading, error },
|
||||
} = useFetch<BlockExplorerTransactions>(url);
|
||||
} = useFetch<BlockExplorerTransactions>(
|
||||
`${
|
||||
DATA_SOURCES.blockExplorerUrl
|
||||
}/transactions?before=${blockHeight.toString()}.0&limit=${txCount}`
|
||||
);
|
||||
|
||||
return (
|
||||
<RenderFetched error={error} loading={loading} className="text-body-large">
|
||||
@@ -86,13 +88,10 @@ export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
|
||||
</tbody>
|
||||
</Table>
|
||||
</div>
|
||||
) : loading ? (
|
||||
<Loader />
|
||||
) : (
|
||||
<EmptyList
|
||||
heading={t('No transactions in this block')}
|
||||
label={t('0 transactions')}
|
||||
/>
|
||||
<div className="sr-only">
|
||||
{t(`No transactions in block ${blockHeight}`)}
|
||||
</div>
|
||||
)}
|
||||
</RenderFetched>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { useEffect } from 'react';
|
||||
import { InfoBlock } from '../../components/info-block';
|
||||
import { Panel } from '../../components/panel';
|
||||
import { useExplorerStatsQuery } from './__generated__/Explorer-stats';
|
||||
import type { ExplorerStatsFieldsFragment } from './__generated__/Explorer-stats';
|
||||
|
||||
interface StatsMap {
|
||||
field: keyof ExplorerStatsFieldsFragment;
|
||||
label: string;
|
||||
info: string;
|
||||
}
|
||||
|
||||
export const TXS_STATS_MAP: StatsMap[] = [
|
||||
{
|
||||
field: 'averageOrdersPerBlock',
|
||||
label: t('Orders per block'),
|
||||
info: t(
|
||||
'Number of new orders processed in the last block. All orders derived from pegged orders and liquidity commitments count as a single order'
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'txPerBlock',
|
||||
label: t('Transactions per block'),
|
||||
info: t('Number of transactions processed in the last block'),
|
||||
},
|
||||
{
|
||||
field: 'tradesPerSecond',
|
||||
label: t('Trades per second'),
|
||||
info: t('Number of trades processed in the last second'),
|
||||
},
|
||||
{
|
||||
field: 'ordersPerSecond',
|
||||
label: t('Order per second'),
|
||||
info: t(
|
||||
'Number of orders processed in the last second. All orders derived from pegged orders and liquidity commitments count as a single order'
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
interface TxsStatsInfoProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const TxsStatsInfo = ({ className }: TxsStatsInfoProps) => {
|
||||
const { data, startPolling, stopPolling } = useExplorerStatsQuery();
|
||||
|
||||
useEffect(() => {
|
||||
startPolling(1000);
|
||||
return () => stopPolling();
|
||||
});
|
||||
|
||||
const gridStyles =
|
||||
'grid grid-rows-2 gap-4 grid-cols-2 xl:gap-8 xl:grid-rows-1 xl:grid-cols-4';
|
||||
|
||||
return (
|
||||
<Panel className={className}>
|
||||
<section className={gridStyles}>
|
||||
{TXS_STATS_MAP.map((field) => {
|
||||
if (!data?.statistics) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Workaround for awkward typing
|
||||
const title = data.statistics[field.field] || '';
|
||||
return (
|
||||
<InfoBlock
|
||||
subtitle={field.label}
|
||||
tooltipInfo={field.info}
|
||||
title={title}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</section>
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
@@ -1,44 +0,0 @@
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { render } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import Assets from './index';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { ExplorerAssetDocument } from '../../components/links/asset-link/__generated__/Asset';
|
||||
|
||||
function renderComponent(mock: MockedResponse[]) {
|
||||
return (
|
||||
<MemoryRouter>
|
||||
<MockedProvider mocks={mock}>
|
||||
<Assets />
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
}
|
||||
|
||||
describe('Assets index', () => {
|
||||
it('Renders loader when loading', async () => {
|
||||
const mock = {
|
||||
request: {
|
||||
query: ExplorerAssetDocument,
|
||||
},
|
||||
result: {
|
||||
data: {},
|
||||
},
|
||||
};
|
||||
const res = render(renderComponent([mock]));
|
||||
expect(await res.findByTestId('loader')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders EmptyList when loading completes and there are no results', async () => {
|
||||
const mock = {
|
||||
request: {
|
||||
query: ExplorerAssetDocument,
|
||||
},
|
||||
result: {
|
||||
data: {},
|
||||
},
|
||||
};
|
||||
const res = render(renderComponent([mock]));
|
||||
expect(await res.findByTestId('emptylist')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -2,15 +2,14 @@ import { getNodes, t } from '@vegaprotocol/react-helpers';
|
||||
import React from 'react';
|
||||
import { RouteTitle } from '../../components/route-title';
|
||||
import { SubHeading } from '../../components/sub-heading';
|
||||
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { useExplorerAssetsQuery } from './__generated__/Assets';
|
||||
import type { AssetsFieldsFragment } from './__generated__/Assets';
|
||||
import { useScrollToLocation } from '../../hooks/scroll-to-location';
|
||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||
import EmptyList from '../../components/empty-list/empty-list';
|
||||
|
||||
const Assets = () => {
|
||||
const { data, loading } = useExplorerAssetsQuery();
|
||||
const { data } = useExplorerAssetsQuery();
|
||||
useDocumentTitle(['Assets']);
|
||||
|
||||
useScrollToLocation();
|
||||
@@ -18,25 +17,17 @@ const Assets = () => {
|
||||
const assets = getNodes<AssetsFieldsFragment>(data?.assetsConnection);
|
||||
|
||||
if (!assets || assets.length === 0) {
|
||||
if (!loading) {
|
||||
return (
|
||||
<section>
|
||||
<RouteTitle data-testid="assets-header">{t('Assets')}</RouteTitle>
|
||||
<EmptyList
|
||||
heading={t('This chain has no assets')}
|
||||
label={t('0 assets')}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
} else {
|
||||
return <Loader />;
|
||||
}
|
||||
return <section></section>;
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<RouteTitle data-testid="assets-header">{t('Assets')}</RouteTitle>
|
||||
{assets.map((a) => {
|
||||
if (!a) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment key={a.id}>
|
||||
<SubHeading data-testid="asset-header" id={a.id}>
|
||||
|
||||
@@ -18,7 +18,6 @@ import { RenderFetched } from '../../../components/render-fetched';
|
||||
import { t, useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { NodeLink } from '../../../components/links';
|
||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||
import EmptyList from '../../../components/empty-list/empty-list';
|
||||
|
||||
const Block = () => {
|
||||
const { block } = useParams<{ block: string }>();
|
||||
@@ -113,12 +112,7 @@ const Block = () => {
|
||||
blockHeight={blockData.result.block.header.height}
|
||||
txCount={blockData.result.block.data.txs.length}
|
||||
/>
|
||||
) : (
|
||||
<EmptyList
|
||||
heading={t('This block is empty')}
|
||||
label={t('0 transactions')}
|
||||
/>
|
||||
)}
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { t, useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { RouteTitle } from '../../components/route-title';
|
||||
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { DATA_SOURCES } from '../../config';
|
||||
import type { TendermintGenesisResponse } from './tendermint-genesis-response';
|
||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||
@@ -9,16 +9,11 @@ const Genesis = () => {
|
||||
useDocumentTitle(['Genesis']);
|
||||
|
||||
const {
|
||||
state: { data: genesis, loading },
|
||||
state: { data: genesis },
|
||||
} = useFetch<TendermintGenesisResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/genesis`
|
||||
);
|
||||
if (!genesis?.result.genesis) {
|
||||
if (loading) {
|
||||
return <Loader />;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (!genesis?.result.genesis) return null;
|
||||
return (
|
||||
<section>
|
||||
<RouteTitle data-testid="genesis-header">{t('Genesis')}</RouteTitle>
|
||||
|
||||
@@ -2,35 +2,19 @@ import { t } from '@vegaprotocol/react-helpers';
|
||||
import React from 'react';
|
||||
import { RouteTitle } from '../../components/route-title';
|
||||
import { SubHeading } from '../../components/sub-heading';
|
||||
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { useExplorerProposalsQuery } from './__generated__/Proposals';
|
||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||
import EmptyList from '../../components/empty-list/empty-list';
|
||||
|
||||
const Governance = () => {
|
||||
const { data, loading } = useExplorerProposalsQuery({
|
||||
const { data } = useExplorerProposalsQuery({
|
||||
errorPolicy: 'ignore',
|
||||
});
|
||||
|
||||
useDocumentTitle();
|
||||
|
||||
if (!data || !data.proposalsConnection || !data.proposalsConnection.edges) {
|
||||
if (!loading) {
|
||||
return (
|
||||
<section>
|
||||
<RouteTitle data-testid="governance-header">
|
||||
{t('Governance Proposals')}
|
||||
</RouteTitle>
|
||||
|
||||
<EmptyList
|
||||
heading={t('This chain has no proposals')}
|
||||
label={t('0 proposals')}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
} else {
|
||||
return <Loader />;
|
||||
}
|
||||
return <section></section>;
|
||||
}
|
||||
|
||||
const proposals = data?.proposalsConnection?.edges.map((e) => {
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { render } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import Markets from './index';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { ExplorerMarketsDocument } from './__generated__/Markets';
|
||||
|
||||
function renderComponent(mock: MockedResponse[]) {
|
||||
return (
|
||||
<MemoryRouter>
|
||||
<MockedProvider mocks={mock}>
|
||||
<Markets />
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
}
|
||||
|
||||
describe('Markets index', () => {
|
||||
it('Renders loader when loading', async () => {
|
||||
const mock = {
|
||||
request: {
|
||||
query: ExplorerMarketsDocument,
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
marketsConnection: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
const res = render(renderComponent([mock]));
|
||||
expect(await res.findByTestId('loader')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders EmptyList when loading completes and there are no results', async () => {
|
||||
const mock = {
|
||||
request: {
|
||||
query: ExplorerMarketsDocument,
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
marketsConnection: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
const res = render(renderComponent([mock]));
|
||||
expect(await res.findByTestId('emptylist')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,15 +1,14 @@
|
||||
import React from 'react';
|
||||
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { RouteTitle } from '../../components/route-title';
|
||||
import { SubHeading } from '../../components/sub-heading';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { useExplorerMarketsQuery } from './__generated__/Markets';
|
||||
import { useScrollToLocation } from '../../hooks/scroll-to-location';
|
||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||
import EmptyList from '../../components/empty-list/empty-list';
|
||||
|
||||
const Markets = () => {
|
||||
const { data, loading } = useExplorerMarketsQuery();
|
||||
const { data } = useExplorerMarketsQuery();
|
||||
|
||||
useScrollToLocation();
|
||||
useDocumentTitle(['Markets']);
|
||||
@@ -20,23 +19,16 @@ const Markets = () => {
|
||||
<section key="markets">
|
||||
<RouteTitle data-testid="markets-heading">{t('Markets')}</RouteTitle>
|
||||
|
||||
{m ? (
|
||||
m.map((e) => (
|
||||
<React.Fragment key={e.node.id}>
|
||||
<SubHeading data-testid="markets-header" id={e.node.id}>
|
||||
{e.node.tradableInstrument.instrument.name}
|
||||
</SubHeading>
|
||||
<SyntaxHighlighter data={e.node} />
|
||||
</React.Fragment>
|
||||
))
|
||||
) : loading ? (
|
||||
<Loader />
|
||||
) : (
|
||||
<EmptyList
|
||||
heading={t('This chain has no markets')}
|
||||
label={t('0 markets')}
|
||||
/>
|
||||
)}
|
||||
{m
|
||||
? m.map((e) => (
|
||||
<React.Fragment key={e.node.id}>
|
||||
<SubHeading data-testid="markets-header" id={e.node.id}>
|
||||
{e.node.tradableInstrument.instrument.name}
|
||||
</SubHeading>
|
||||
<SyntaxHighlighter data={e.node} />
|
||||
</React.Fragment>
|
||||
))
|
||||
: null}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { RouteTitle } from '../../../components/route-title';
|
||||
import { BlocksRefetch } from '../../../components/blocks';
|
||||
import { TxsInfiniteList } from '../../../components/txs';
|
||||
import { TxsInfiniteList, TxsStatsInfo } from '../../../components/txs';
|
||||
import { useTxsData } from '../../../hooks/use-txs-data';
|
||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||
|
||||
@@ -16,6 +16,7 @@ export const TxsList = () => {
|
||||
<section className="md:p-2 lg:p-4 xl:p-6">
|
||||
<RouteTitle>{t('Transactions')}</RouteTitle>
|
||||
<BlocksRefetch refetch={refreshTxs} />
|
||||
<TxsStatsInfo className="!my-12 py-8" />
|
||||
<TxsInfiniteList
|
||||
hasMoreTxs={hasMoreTxs}
|
||||
areTxsLoading={loading}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import React from 'react';
|
||||
import { RouteTitle } from '../../components/route-title';
|
||||
import { SubHeading } from '../../components/sub-heading';
|
||||
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { DATA_SOURCES } from '../../config';
|
||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
import type { TendermintValidatorsResponse } from './tendermint-validator-response';
|
||||
@@ -27,9 +28,7 @@ const Validators = () => {
|
||||
<SubHeading data-testid="vega-header">{t('Vega data')}</SubHeading>
|
||||
<SyntaxHighlighter data-testid="vega-data" data={data} />
|
||||
</>
|
||||
) : (
|
||||
<Loader />
|
||||
)}
|
||||
) : null}
|
||||
{validators ? (
|
||||
<>
|
||||
<SubHeading data-testid="tendermint-header">
|
||||
@@ -37,9 +36,7 @@ const Validators = () => {
|
||||
</SubHeading>
|
||||
<SyntaxHighlighter data-testid="tendermint-data" data={validators} />
|
||||
</>
|
||||
) : (
|
||||
<Loader />
|
||||
)}
|
||||
) : null}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
+26
-73
@@ -14,17 +14,9 @@ type OneOf<T extends any[]> = T extends [infer Only]
|
||||
: T extends [infer A, infer B, ...infer Rest]
|
||||
? OneOf<[XOR<A, B>, ...Rest]>
|
||||
: never;
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
/* typescript-eslint:enable no-explicit-any */
|
||||
|
||||
export interface paths {
|
||||
'/info': {
|
||||
/**
|
||||
* Info
|
||||
* @description Retrieves information about the block explorer.
|
||||
* Response contains a semver formatted version of the data node and the commit hash, from which the block explorer was built,
|
||||
*/
|
||||
get: operations['BlockExplorer_Info'];
|
||||
};
|
||||
'/transactions': {
|
||||
/**
|
||||
* List transactions
|
||||
@@ -108,7 +100,8 @@ export interface components {
|
||||
readonly UndelegateSubmissionMethod:
|
||||
| 'METHOD_UNSPECIFIED'
|
||||
| 'METHOD_NOW'
|
||||
| 'METHOD_AT_END_OF_EPOCH';
|
||||
| 'METHOD_AT_END_OF_EPOCH'
|
||||
| 'METHOD_IN_ANGER';
|
||||
readonly blockexplorerapiv1Transaction: {
|
||||
/**
|
||||
* The height of the block the transaction was found in
|
||||
@@ -124,11 +117,6 @@ export interface components {
|
||||
readonly command?: components['schemas']['v1InputData'];
|
||||
/** The cursor for this transaction (in the page, used for paginated results) */
|
||||
readonly cursor?: string;
|
||||
/**
|
||||
* An optional error happening when processing / checking the transaction
|
||||
* Should be set if error code is not 0
|
||||
*/
|
||||
readonly error?: string;
|
||||
/** The hash of the transaction */
|
||||
readonly hash?: string;
|
||||
/**
|
||||
@@ -136,8 +124,6 @@ export interface components {
|
||||
* Format: int64
|
||||
*/
|
||||
readonly index?: number;
|
||||
/** Submitter's signature of transaction */
|
||||
readonly signature?: components['schemas']['v1Signature'];
|
||||
/** The submitter of the transaction (Vega public key) */
|
||||
readonly submitter?: string;
|
||||
/** The type of transaction */
|
||||
@@ -173,7 +159,7 @@ export interface components {
|
||||
readonly '@type'?: string;
|
||||
[key: string]: unknown | undefined;
|
||||
};
|
||||
/** Used announce a node as a new pending validator */
|
||||
/** Used announce a node as a new potential validator */
|
||||
readonly v1AnnounceNode: {
|
||||
/** AvatarURL of the validator */
|
||||
readonly avatarUrl?: string;
|
||||
@@ -206,7 +192,7 @@ export interface components {
|
||||
* Format: int64
|
||||
*/
|
||||
readonly vegaPubKeyIndex?: number;
|
||||
/** Signature from the validator made using the Vega wallet */
|
||||
/** Signature from the validator made using the vega wallet */
|
||||
readonly vegaSignature?: components['schemas']['v1Signature'];
|
||||
};
|
||||
/**
|
||||
@@ -301,12 +287,6 @@ export interface components {
|
||||
/** The transaction corresponding to the hash */
|
||||
readonly transaction?: components['schemas']['blockexplorerapiv1Transaction'];
|
||||
};
|
||||
readonly v1InfoResponse: {
|
||||
/** The commit hash from which the data-node was built */
|
||||
readonly commitHash?: string;
|
||||
/** A semver formatted version of the data node */
|
||||
readonly version?: string;
|
||||
};
|
||||
readonly v1InputData: {
|
||||
readonly announceNode?: components['schemas']['v1AnnounceNode'];
|
||||
readonly batchMarketInstructions?: components['schemas']['v1BatchMarketInstructions'];
|
||||
@@ -371,7 +351,7 @@ export interface components {
|
||||
/** The ID of the node that will be signed in or out of the smartcontract */
|
||||
readonly validatorNodeId?: string;
|
||||
};
|
||||
/** A transaction to allow validator to rotate their Vega keys */
|
||||
/** A transaction to allow validator to rotate their vega keys */
|
||||
readonly v1KeyRotateSubmission: {
|
||||
/** Hash of currently used public key */
|
||||
readonly currentPubKeyHash?: string;
|
||||
@@ -434,7 +414,7 @@ export interface components {
|
||||
readonly sig?: string;
|
||||
};
|
||||
/**
|
||||
* The kind of signature created by a node, for example, allow-listing a new asset, withdrawal etc
|
||||
* The kind of the signature created by a node, for example, allow-listing a new asset, withdrawal etc
|
||||
* @description - NODE_SIGNATURE_KIND_UNSPECIFIED: Represents an unspecified or missing value from the input
|
||||
* - NODE_SIGNATURE_KIND_ASSET_NEW: Represents a signature for a new asset allow-listing
|
||||
* - NODE_SIGNATURE_KIND_ASSET_WITHDRAWAL: Represents a signature for an asset withdrawal
|
||||
@@ -452,7 +432,7 @@ export interface components {
|
||||
| 'NODE_SIGNATURE_KIND_ERC20_MULTISIG_SIGNER_REMOVED'
|
||||
| 'NODE_SIGNATURE_KIND_ASSET_UPDATE';
|
||||
/**
|
||||
* Used when a node votes for validating that a given resource exists or is valid,
|
||||
* Used when a node votes for validating a given resource exists or is valid,
|
||||
* for example, an ERC20 deposit is valid and exists on ethereum
|
||||
*/
|
||||
readonly v1NodeVote: {
|
||||
@@ -573,12 +553,6 @@ export interface components {
|
||||
readonly v1PropertyKey: {
|
||||
/** @description name is the name of the property. */
|
||||
readonly name?: string;
|
||||
/**
|
||||
* An optional decimal place to be be applied on the provided value
|
||||
* valid only for PropertyType of type DECIMAL and INTEGER
|
||||
* Format: uint64
|
||||
*/
|
||||
readonly numberDecimalPlaces?: string;
|
||||
/** @description type is the type of the property. */
|
||||
readonly type?: components['schemas']['v1PropertyKeyType'];
|
||||
};
|
||||
@@ -622,7 +596,7 @@ export interface components {
|
||||
* Format: uint64
|
||||
*/
|
||||
readonly upgradeBlockHeight?: string;
|
||||
/** the release tag for the Vega binary */
|
||||
/** the release tag for the vega binary */
|
||||
readonly vegaReleaseTag?: string;
|
||||
};
|
||||
/**
|
||||
@@ -685,8 +659,8 @@ export interface components {
|
||||
readonly nodeId?: string;
|
||||
};
|
||||
/**
|
||||
* A message from a validator signalling they are still online and validating blocks
|
||||
* or ready to validate blocks when they are still a pending validator
|
||||
* A message from a validator signaling they are still online and validating blocks
|
||||
* or ready to validate block when they are till a potential validator
|
||||
*/
|
||||
readonly v1ValidatorHeartbeat: {
|
||||
/** Signature from the validator made using the ethereum wallet */
|
||||
@@ -1087,6 +1061,11 @@ export interface components {
|
||||
readonly quoteName?: string;
|
||||
/** Asset ID for the product's settlement asset */
|
||||
readonly settlementAsset?: string;
|
||||
/**
|
||||
* The number of decimal places implied by the settlement data (such as price) emitted by the settlement data source
|
||||
* Format: int64
|
||||
*/
|
||||
readonly settlementDataDecimals?: number;
|
||||
};
|
||||
/** Instrument configuration */
|
||||
readonly vegaInstrumentConfiguration: {
|
||||
@@ -1132,17 +1111,17 @@ export interface components {
|
||||
/** Risk model parameters for log normal */
|
||||
readonly vegaLogNormalModelParams: {
|
||||
/**
|
||||
* Mu parameter, annualised growth rate of the underlying asset
|
||||
* Mu param
|
||||
* Format: double
|
||||
*/
|
||||
readonly mu?: number;
|
||||
/**
|
||||
* R parameter, annualised growth rate of the risk-free asset, used for discounting of future cash flows, can be any real number
|
||||
* R param
|
||||
* Format: double
|
||||
*/
|
||||
readonly r?: number;
|
||||
/**
|
||||
* Sigma parameter, annualised volatility of the underlying asset, must be a strictly non-negative real number
|
||||
* Sigma param
|
||||
* Format: double
|
||||
*/
|
||||
readonly sigma?: number;
|
||||
@@ -1157,7 +1136,7 @@ export interface components {
|
||||
*/
|
||||
readonly riskAversionParameter?: number;
|
||||
/**
|
||||
* Tau parameter of the risk model, projection horizon measured as a year fraction used in the expected shortfall calculation to obtain the maintenance margin, must be a strictly non-negative real number
|
||||
* Tau
|
||||
* Format: double
|
||||
*/
|
||||
readonly tau?: number;
|
||||
@@ -1201,11 +1180,6 @@ export interface components {
|
||||
readonly liquidityMonitoringParameters?: components['schemas']['vegaLiquidityMonitoringParameters'];
|
||||
/** Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected */
|
||||
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
|
||||
/**
|
||||
* Percentage move up and down from the mid price which specifies the range of
|
||||
* price levels over which automated liquidity provision orders will be deployed
|
||||
*/
|
||||
readonly lpPriceRange?: string;
|
||||
/** Optional new market meta data, tags */
|
||||
readonly metadata?: readonly string[];
|
||||
/**
|
||||
@@ -1265,7 +1239,7 @@ export interface components {
|
||||
readonly vegaPriceMonitoringTrigger: {
|
||||
/**
|
||||
* Price monitoring auction extension duration in seconds should the price
|
||||
* breach its theoretical level over the specified horizon at the specified
|
||||
* breach it's theoretical level over the specified horizon at the specified
|
||||
* probability level
|
||||
* Format: int64
|
||||
*/
|
||||
@@ -1462,6 +1436,11 @@ export interface components {
|
||||
readonly dataSourceSpecForTradingTermination?: components['schemas']['vegaDataSourceDefinition'];
|
||||
/** Human-readable name/abbreviation of the quote name */
|
||||
readonly quoteName?: string;
|
||||
/**
|
||||
* The number of decimal places implied by the settlement data (such as price) emitted by the settlement external data source
|
||||
* Format: int64
|
||||
*/
|
||||
readonly settlementDataDecimals?: number;
|
||||
};
|
||||
/** Instrument configuration */
|
||||
readonly vegaUpdateInstrumentConfiguration: {
|
||||
@@ -1485,11 +1464,6 @@ export interface components {
|
||||
readonly liquidityMonitoringParameters?: components['schemas']['vegaLiquidityMonitoringParameters'];
|
||||
/** Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected */
|
||||
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
|
||||
/**
|
||||
* Percentage move up and down from the mid price which specifies the range of
|
||||
* price levels over which automated liquidity provision orders will be deployed
|
||||
*/
|
||||
readonly lpPriceRange?: string;
|
||||
/** Optional market metadata, tags */
|
||||
readonly metadata?: readonly string[];
|
||||
/** Price monitoring parameters */
|
||||
@@ -1530,27 +1504,6 @@ export interface components {
|
||||
export type external = Record<string, never>;
|
||||
|
||||
export interface operations {
|
||||
BlockExplorer_Info: {
|
||||
/**
|
||||
* Info
|
||||
* @description Retrieves information about the block explorer.
|
||||
* Response contains a semver formatted version of the data node and the commit hash, from which the block explorer was built,
|
||||
*/
|
||||
responses: {
|
||||
/** @description A successful response. */
|
||||
200: {
|
||||
content: {
|
||||
readonly 'application/json': components['schemas']['v1InfoResponse'];
|
||||
};
|
||||
};
|
||||
/** @description An unexpected error response. */
|
||||
default: {
|
||||
content: {
|
||||
readonly 'application/json': components['schemas']['googlerpcStatus'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
BlockExplorer_ListTransactions: {
|
||||
/**
|
||||
* List transactions
|
||||
|
||||
-16
@@ -10,7 +10,6 @@ import {
|
||||
formatNumberPercentage,
|
||||
t,
|
||||
toBigNum,
|
||||
getDateTimeFormat,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type { VegaValueFormatterParams } from '@vegaprotocol/ui-toolkit';
|
||||
import type * as Schema from '@vegaprotocol/types';
|
||||
@@ -297,21 +296,6 @@ export const MarketList = () => {
|
||||
return value ? formatDistanceToNow(new Date(value)) : '-';
|
||||
}}
|
||||
/>
|
||||
<AgGridColumn
|
||||
headerName={t('Closing Time')}
|
||||
field="proposal.terms.closingDatetime"
|
||||
headerTooltip={t('Closing time of the market')}
|
||||
valueFormatter={({
|
||||
value,
|
||||
}: VegaValueFormatterParams<
|
||||
Market,
|
||||
'proposal.terms.closingDatetime'
|
||||
>) => {
|
||||
return value
|
||||
? getDateTimeFormat().format(new Date(value).getTime())
|
||||
: '-';
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<HealthDialog
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { getChainName, useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import { Button, Splash, AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { Web3ConnectDialog } from '@vegaprotocol/web3';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
@@ -82,7 +82,7 @@ export const Web3Content = ({
|
||||
<Splash>
|
||||
<div className="flex flex-col items-center gap-12">
|
||||
<p className="text-white">
|
||||
This app only works on {getChainName(appChainId)}
|
||||
This app only works on chain ID: {appChainId}
|
||||
</p>
|
||||
<Button onClick={() => connector.deactivate()}>Disconnect</Button>
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"hosts": ["https://api.n00.mainnet-mirror.vega.xyz/query"]
|
||||
"hosts": ["https://api.n00.mainnet-mirror.vega.xyz/graphql"]
|
||||
}
|
||||
|
||||
@@ -21,12 +21,7 @@ The e2e tests run against a locally running instance of the Vega network, manage
|
||||
- Install the required Vega smart contracts
|
||||
- Set up DataNodes with a running GraphQL and REST APIs.
|
||||
|
||||
1. Refer to the [Vega Capsule readme](https://github.com/vegaprotocol/vegacapsule#readme) for setting up and running Capsule - follow by Pre-start and Quick Start (points 1-2)
|
||||
2. Bootstrap with auto-installed dependencies including wallet
|
||||
|
||||
```bash
|
||||
vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl --force
|
||||
```
|
||||
Refer to the [Vega Capsule readme](https://github.com/vegaprotocol/vegacapsule#readme) for setting up and running Capsule. You will need [Go 1.19 or later](https://go.dev/doc/install) and [Docker](https://docs.docker.com/get-docker/) installed.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
@@ -34,6 +29,6 @@ vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/con
|
||||
|
||||
## Vega Wallet Setup
|
||||
|
||||
You can then refer to (or run) `frontend-monorepo/vegacapsule/setup-vegawallet.sh`. This will initialise and configure your wallet to have the correct public keys and network config to run against capsule.
|
||||
Start by [downloading the Vega wallet software here](https://github.com/vegaprotocol/vega/releases).
|
||||
|
||||
Go to the .env file in `apps/token-e2e` and set the `CYPRESS_VEGA_WALLET_API_TOKEN` environment variable by pasting in your wallets long lived api token
|
||||
You can then refer to (or run) `vegacapsule/setup-vegawallet.sh`. This will initialise and configure your wallet to have the correct public keys and network config to run against capsule.
|
||||
|
||||
@@ -728,7 +728,7 @@ context(
|
||||
});
|
||||
|
||||
// 1005-PROP-009
|
||||
it.skip(
|
||||
it(
|
||||
'Unable to vote on a freeform proposal - when some but not enough vega associated',
|
||||
{ tags: '@smoke' },
|
||||
function () {
|
||||
|
||||
@@ -8,4 +8,3 @@ NX_ETHERSCAN_URL=https://etherscan.io
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4a9141bd@o286262.ingest.sentry.io/5882996
|
||||
@@ -6,4 +6,3 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json
|
||||
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4a9141bd@o286262.ingest.sentry.io/5882996
|
||||
|
||||
@@ -9,4 +9,3 @@ NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4a9141bd@o286262.ingest.sentry.io/5882996
|
||||
|
||||
@@ -39,12 +39,12 @@ There are a few different configuration options offered for this app:
|
||||
|
||||
| **Flag** | **Purpose** |
|
||||
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `NX_SENTRY_DSN` | The sentry endpoint to report to. Should be off in dev but set in live. |
|
||||
| `NX_VEGA_URL` | The GraphQL query endpoint of a [Vega data node](https://github.com/vegaprotocol/networks#data-node) |
|
||||
| `NX_DEX_STAKING_DISABLED` | Disable the dex liquidity page an show a coming soon message |
|
||||
| `NX_FAIRGROUND` | Change styling to be themed as the fairground version of the website |
|
||||
| `NX_INFURA_ID` | Infura fallback for if the user does not have a web3 compatible browser |
|
||||
| `NX_ENV` | Change network to connect to. |
|
||||
| `NX_APP_SENTRY_DSN` | The sentry endpoint to report to. Should be off in dev but set in live. |
|
||||
| `NX_APP_VEGA_URL` | The GraphQL query endpoint of a [Vega data node](https://github.com/vegaprotocol/networks#data-node) |
|
||||
| `NX_APP_DEX_STAKING_DISABLED` | Disable the dex liquidity page an show a coming soon message |
|
||||
| `NX_APP_FAIRGROUND` | Change styling to be themed as the fairground version of the website |
|
||||
| `NX_APP_INFURA_ID` | Infura fallback for if the user does not have a web3 compatible browser |
|
||||
| `NX_APP_ENV` | Change network to connect to. When set to CUSTOM use CUSTOM\_\* vars for network parameters |
|
||||
| `NX_ETH_URL_CONNECT` (optional) | If set to true the below two must also be set. This allows siging transactions in brower to allow to connect to a local ganache node through cypress |
|
||||
| `NX_ETH_WALLET_MNEMONIC` (optional) | The mnemonic to be used to sign transactions with in browser |
|
||||
| `NX_LOCAL_PROVIDER_URL` (optional) | The local node to use to send transaction to when signing in browser |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Button, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { getChainName, Web3ConnectDialog } from '@vegaprotocol/web3';
|
||||
import { Web3ConnectDialog } from '@vegaprotocol/web3';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import type { ReactElement } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
@@ -78,7 +78,7 @@ export const Web3Content = ({ children, appChainId }: Web3ContentProps) => {
|
||||
<Splash>
|
||||
<div className="flex flex-col items-center gap-12">
|
||||
<p className="text-white">
|
||||
This app only works on {getChainName(appChainId)}
|
||||
This app only works on chain ID: {appChainId}
|
||||
</p>
|
||||
<Button onClick={() => connector.deactivate()}>Disconnect</Button>
|
||||
</div>
|
||||
|
||||
@@ -6,41 +6,43 @@ const amountField = 'input[name="amount"]';
|
||||
const formFieldError = 'input-error-text';
|
||||
|
||||
describe('deposit form validation', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
beforeEach(() => {
|
||||
cy.mockWeb3Provider();
|
||||
cy.mockSubscription();
|
||||
cy.mockTradingPage();
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
cy.getByTestId('Deposits').click();
|
||||
cy.getByTestId('tab-deposits').contains('Connect your Vega wallet');
|
||||
cy.connectVegaWallet();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
cy.wait('@Assets');
|
||||
connectEthereumWallet();
|
||||
cy.getByTestId('deposit-submit').click();
|
||||
});
|
||||
|
||||
it('handles empty fields', () => {
|
||||
cy.getByTestId(formFieldError).should('contain.text', 'Required');
|
||||
cy.getByTestId(formFieldError).should('have.length', 2);
|
||||
});
|
||||
|
||||
it('unable to select assets not enabled', () => {
|
||||
connectEthereumWallet();
|
||||
cy.getByTestId('deposit-submit').click();
|
||||
// Assets not enabled in mocks
|
||||
cy.get(assetSelectField + ' option:contains(Asset 2)').should('not.exist');
|
||||
cy.get(assetSelectField + ' option:contains(Asset 3)').should('not.exist');
|
||||
cy.get(assetSelectField + ' option:contains(Asset 4)').should('not.exist');
|
||||
});
|
||||
|
||||
it('invalid public key', () => {
|
||||
it('handles empty fields', () => {
|
||||
connectEthereumWallet();
|
||||
// Submit form to trigger any empty validation messages
|
||||
cy.getByTestId('deposit-submit').click();
|
||||
|
||||
cy.getByTestId(formFieldError).should('contain.text', 'Required');
|
||||
cy.getByTestId(formFieldError).should('have.length', 2);
|
||||
|
||||
// Invalid public key
|
||||
cy.get(toAddressField)
|
||||
.clear()
|
||||
.type('INVALID_DEPOSIT_TO_ADDRESS')
|
||||
.next(`[data-testid="${formFieldError}"]`)
|
||||
.should('have.text', 'Invalid Vega key');
|
||||
});
|
||||
|
||||
it('invalid amount', () => {
|
||||
// Deposit amount smaller than minimum viable for selected asset
|
||||
// Select an amount so that we have a known decimal places value to work with
|
||||
cy.get(assetSelectField).select('Euro');
|
||||
@@ -49,9 +51,7 @@ describe('deposit form validation', { tags: '@smoke' }, () => {
|
||||
.type('0.00000000000000000000000000000000001')
|
||||
.next(`[data-testid="${formFieldError}"]`)
|
||||
.should('have.text', 'Value is below minimum');
|
||||
});
|
||||
|
||||
it('insufficient funds', () => {
|
||||
// Deposit amount is valid, but less than approved. This will always be the case because our
|
||||
// CI wallet wont have approved any assets
|
||||
cy.get(amountField)
|
||||
|
||||
@@ -133,7 +133,6 @@ describe('Navbar', { tags: '@smoke' }, () => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/');
|
||||
cy.wait('@Market');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
});
|
||||
|
||||
|
||||
@@ -224,34 +224,4 @@ describe('home', { tags: '@regression' }, () => {
|
||||
.should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('redirect should take last visited market into consideration', () => {
|
||||
beforeEach(() => {
|
||||
cy.window().then((window) => {
|
||||
window.localStorage.removeItem('marketId');
|
||||
});
|
||||
});
|
||||
it('marketId comes from existing market', () => {
|
||||
cy.window().then((window) => {
|
||||
window.localStorage.setItem('marketId', 'market-1');
|
||||
cy.visit('/');
|
||||
cy.wait('@Market');
|
||||
cy.location('hash').should('equal', '#/markets/market-1');
|
||||
cy.get('[role="dialog"]').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('marketId comes from not-existing market', () => {
|
||||
cy.window().then((window) => {
|
||||
window.localStorage.setItem('marketId', 'market-not-existing');
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Market', null);
|
||||
});
|
||||
cy.visit('/');
|
||||
cy.wait('@Market');
|
||||
cy.location('hash').should('equal', '#/markets/market-not-existing');
|
||||
cy.get('[role="dialog"]').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -235,9 +235,9 @@ describe('market states not accepting orders', { tags: '@smoke' }, function () {
|
||||
beforeEach(function () {
|
||||
cy.mockTradingPage(marketState);
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.connectVegaWallet();
|
||||
});
|
||||
it('must display that market is not accepting orders', function () {
|
||||
cy.getByTestId('place-order').click();
|
||||
|
||||
@@ -2,7 +2,6 @@ beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockWeb3Provider();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/#/markets/market-0');
|
||||
});
|
||||
|
||||
@@ -11,6 +10,8 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
const tradingAccountRowId = '[row-id="asset-0"]';
|
||||
cy.getByTestId('Collateral').click();
|
||||
|
||||
cy.connectVegaWallet();
|
||||
|
||||
cy.getByTestId('tab-accounts').should('be.visible');
|
||||
|
||||
cy.getByTestId('tab-accounts')
|
||||
|
||||
@@ -30,11 +30,11 @@ const displayTomorrow = () => {
|
||||
|
||||
describe('time in force default values', () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.connectVegaWallet();
|
||||
});
|
||||
|
||||
it('must have market order set up to IOC by default', function () {
|
||||
@@ -59,15 +59,20 @@ describe('time in force default values', () => {
|
||||
describe('must submit order', { tags: '@smoke' }, () => {
|
||||
// 7002-SORD-039
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.connectVegaWallet();
|
||||
cy.window().then(function (window) {
|
||||
cy.wrap(window.localStorage.getItem('vega_wallet_config')).as('cfg');
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.window().then(function (window) {
|
||||
window.localStorage.setItem('vega_wallet_config', this.cfg);
|
||||
});
|
||||
});
|
||||
|
||||
it('successfully places market buy order', () => {
|
||||
@@ -153,7 +158,6 @@ describe(
|
||||
{ tags: '@regression' },
|
||||
() => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage(
|
||||
Schema.MarketState.STATE_SUSPENDED,
|
||||
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
|
||||
@@ -162,10 +166,16 @@ describe(
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.connectVegaWallet();
|
||||
cy.window().then(function (window) {
|
||||
cy.wrap(window.localStorage.getItem('vega_wallet_config')).as('cfg');
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.window().then(function (window) {
|
||||
window.localStorage.setItem('vega_wallet_config', this.cfg);
|
||||
});
|
||||
});
|
||||
|
||||
it('successfully places limit buy order', () => {
|
||||
@@ -222,7 +232,6 @@ describe(
|
||||
{ tags: '@regression' },
|
||||
() => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage(
|
||||
Schema.MarketState.STATE_SUSPENDED,
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
||||
@@ -231,10 +240,16 @@ describe(
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.connectVegaWallet();
|
||||
cy.window().then(function (window) {
|
||||
cy.wrap(window.localStorage.getItem('vega_wallet_config')).as('cfg');
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.window().then(function (window) {
|
||||
window.localStorage.setItem('vega_wallet_config', this.cfg);
|
||||
});
|
||||
});
|
||||
|
||||
it('successfully places limit buy order', () => {
|
||||
@@ -291,7 +306,6 @@ describe(
|
||||
{ tags: '@regression' },
|
||||
() => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage(
|
||||
Schema.MarketState.STATE_SUSPENDED,
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
@@ -300,10 +314,16 @@ describe(
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.connectVegaWallet();
|
||||
cy.window().then(function (window) {
|
||||
cy.wrap(window.localStorage.getItem('vega_wallet_config')).as('cfg');
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.window().then(function (window) {
|
||||
window.localStorage.setItem('vega_wallet_config', this.cfg);
|
||||
});
|
||||
});
|
||||
|
||||
it('successfully places limit buy order', () => {
|
||||
@@ -401,10 +421,10 @@ describe('deal ticket validation', { tags: '@smoke' }, () => {
|
||||
|
||||
describe('deal ticket size validation', { tags: '@smoke' }, function () {
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.connectVegaWallet();
|
||||
});
|
||||
|
||||
it('must warn if order size input has too many digits after the decimal place', function () {
|
||||
@@ -435,18 +455,14 @@ describe('deal ticket size validation', { tags: '@smoke' }, function () {
|
||||
|
||||
describe('limit order validations', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.connectVegaWallet();
|
||||
cy.wait('@Market');
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('must see the price unit', function () {
|
||||
//7002-SORD-018
|
||||
cy.getByTestId(orderPriceField)
|
||||
@@ -528,17 +544,11 @@ describe('limit order validations', { tags: '@smoke' }, () => {
|
||||
|
||||
describe('market order validations', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.getByTestId(toggleMarket).click();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('must not see the price unit', function () {
|
||||
//7002-SORD-019
|
||||
cy.getByTestId(orderPriceField).should('not.exist');
|
||||
@@ -577,7 +587,6 @@ describe('market order validations', { tags: '@smoke' }, () => {
|
||||
|
||||
describe('suspended market validation', { tags: '@regression' }, () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage(
|
||||
Schema.MarketState.STATE_SUSPENDED,
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
@@ -586,10 +595,7 @@ describe('suspended market validation', { tags: '@regression' }, () => {
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.connectVegaWallet();
|
||||
});
|
||||
|
||||
it('should show warning for market order', function () {
|
||||
@@ -602,7 +608,6 @@ describe('suspended market validation', { tags: '@regression' }, () => {
|
||||
'This market is in auction until it reaches sufficient liquidity. Only limit orders are permitted when market is in auction'
|
||||
);
|
||||
});
|
||||
|
||||
it('should show info for allowed TIF', function () {
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
cy.getByTestId(orderPriceField).clear().type('0.1');
|
||||
@@ -630,7 +635,6 @@ describe('suspended market validation', { tags: '@regression' }, () => {
|
||||
describe('account validation', { tags: '@regression' }, () => {
|
||||
describe('zero balance error', () => {
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(
|
||||
@@ -659,6 +663,7 @@ describe('account validation', { tags: '@regression' }, () => {
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.connectVegaWallet();
|
||||
cy.wait('@Market');
|
||||
});
|
||||
|
||||
@@ -677,7 +682,6 @@ describe('account validation', { tags: '@regression' }, () => {
|
||||
|
||||
describe('not enough balance warning', () => {
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(
|
||||
@@ -695,9 +699,9 @@ describe('account validation', { tags: '@regression' }, () => {
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.connectVegaWallet();
|
||||
cy.wait('@Market');
|
||||
});
|
||||
|
||||
it('should display info and button for deposit', () => {
|
||||
//7002-SORD-003
|
||||
// warning should show immediately
|
||||
|
||||
@@ -12,7 +12,6 @@ describe('fills', { tags: '@regression' }, () => {
|
||||
)
|
||||
);
|
||||
});
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(
|
||||
@@ -28,12 +27,20 @@ describe('fills', { tags: '@regression' }, () => {
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
cy.getByTestId('Fills').click();
|
||||
cy.getByTestId('tab-fills').contains('Connect your Vega wallet');
|
||||
cy.connectVegaWallet();
|
||||
validateFillsDisplayed();
|
||||
});
|
||||
|
||||
it('renders fills on trading tab', () => {
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId('Fills').click();
|
||||
cy.getByTestId('tab-fills').should(
|
||||
'contain.text',
|
||||
'Connect your Vega wallet'
|
||||
);
|
||||
cy.connectVegaWallet();
|
||||
validateFillsDisplayed();
|
||||
});
|
||||
|
||||
|
||||
@@ -27,11 +27,11 @@ describe('orders list', { tags: '@smoke' }, () => {
|
||||
cy.spy(subscriptionMocks, 'OrdersUpdate');
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription(subscriptionMocks);
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId('Orders').click();
|
||||
cy.connectVegaWallet();
|
||||
cy.wait('@Orders').then(() => {
|
||||
expect(subscriptionMocks.OrdersUpdate).to.be.calledTwice;
|
||||
expect(subscriptionMocks.OrdersUpdate).to.be.calledOnce;
|
||||
});
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
@@ -125,11 +125,11 @@ describe('subscribe orders', { tags: '@smoke' }, () => {
|
||||
cy.spy(subscriptionMocks, 'OrdersUpdate');
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription(subscriptionMocks);
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId('Orders').click();
|
||||
cy.connectVegaWallet();
|
||||
cy.wait('@Orders').then(() => {
|
||||
expect(subscriptionMocks.OrdersUpdate).to.be.calledTwice;
|
||||
expect(subscriptionMocks.OrdersUpdate).to.be.calledOnce;
|
||||
});
|
||||
});
|
||||
const orderId = '1234567890';
|
||||
@@ -341,11 +341,11 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
cy.spy(subscriptionMocks, 'OrdersUpdate');
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription(subscriptionMocks);
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId('Orders').click();
|
||||
cy.connectVegaWallet();
|
||||
cy.wait('@Orders').then(() => {
|
||||
expect(subscriptionMocks.OrdersUpdate).to.be.calledTwice;
|
||||
expect(subscriptionMocks.OrdersUpdate).to.be.calledOnce;
|
||||
});
|
||||
cy.mockVegaWalletTransaction();
|
||||
});
|
||||
@@ -423,30 +423,4 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
testOrderCancellation(order);
|
||||
});
|
||||
});
|
||||
it('must be warned (pre-submit) if the input price has too many digits after the decimal place for the market', () => {
|
||||
// 7003-MORD-016
|
||||
updateOrder({
|
||||
id: orderId,
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
peggedOrder: null,
|
||||
liquidityProvisionId: null,
|
||||
});
|
||||
cy.get(`[row-id=${orderId}]`)
|
||||
.find('[data-testid="edit"]')
|
||||
.should('have.text', 'Edit')
|
||||
.then(($btn) => {
|
||||
cy.wrap($btn).click();
|
||||
cy.getByTestId('dialog-title').should('have.text', 'Edit order');
|
||||
cy.get('#limitPrice').focus().clear().type('0.111111');
|
||||
cy.getByTestId('edit-order').find('[type="submit"]').click();
|
||||
cy.getByTestId('input-error-text').should(
|
||||
'have.text',
|
||||
'Price accepts up to 5 decimal places'
|
||||
);
|
||||
});
|
||||
});
|
||||
it.skip('tbd for 7003-MORD', () => {
|
||||
// NOT COVERED: must see the reference, offset and direction for each part pegged order - waiting for clarification
|
||||
// NOT COVERED: must see the reference, offset and direction for each part liquidity order order - waiting for clarification
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { ledgerEntriesQuery } from '@vegaprotocol/mock';
|
||||
import {
|
||||
assetsQuery,
|
||||
ledgerEntriesQuery,
|
||||
marketsQuery,
|
||||
} from '@vegaprotocol/mock';
|
||||
|
||||
describe('Portfolio page', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'LedgerEntries', ledgerEntriesQuery());
|
||||
aliasGQLQuery(req, 'Assets', assetsQuery());
|
||||
aliasGQLQuery(req, 'Markets', marketsQuery());
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
describe('Ledger entries', () => {
|
||||
it('List should be properly rendered', () => {
|
||||
cy.visit('/#/portfolio');
|
||||
cy.connectVegaWallet();
|
||||
cy.getByTestId('"Ledger entries"').click();
|
||||
const headers = [
|
||||
'Sender',
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
describe('positions', { tags: '@smoke' }, () => {
|
||||
it('renders positions on trading page', () => {
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId('Positions').click();
|
||||
cy.getByTestId('tab-positions').should(
|
||||
'contain.text',
|
||||
'Connect your Vega wallet'
|
||||
);
|
||||
|
||||
cy.connectVegaWallet();
|
||||
validatePositionsDisplayed();
|
||||
});
|
||||
|
||||
it('renders positions on portfolio page', () => {
|
||||
cy.visit('/#/portfolio');
|
||||
cy.getByTestId('Positions').click();
|
||||
cy.connectVegaWallet();
|
||||
validatePositionsDisplayed();
|
||||
});
|
||||
|
||||
|
||||
@@ -15,11 +15,13 @@ describe('withdraw form validation', { tags: '@smoke' }, () => {
|
||||
cy.mockWeb3Provider();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
|
||||
// Withdraw page requires vega wallet connection
|
||||
cy.connectVegaWallet();
|
||||
|
||||
cy.getByTestId('withdraw-dialog-button').click();
|
||||
|
||||
// It also requires connection Ethereum wallet
|
||||
@@ -70,10 +72,13 @@ describe('withdraw actions', { tags: '@regression' }, () => {
|
||||
cy.mockWeb3Provider();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
|
||||
// Withdraw page requires vega wallet connection
|
||||
cy.connectVegaWallet();
|
||||
|
||||
cy.getByTestId('withdraw-dialog-button').click();
|
||||
|
||||
connectEthereumWallet();
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ethers } from 'ethers';
|
||||
import type { Transaction } from '@vegaprotocol/wallet';
|
||||
|
||||
/**
|
||||
* Base64 encode a transaction object
|
||||
*/
|
||||
export const encodeTransaction = (tx: Transaction): string => {
|
||||
return ethers.utils.base64.encode(
|
||||
ethers.utils.toUtf8Bytes(JSON.stringify(tx))
|
||||
);
|
||||
};
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
OrderSubmissionBody,
|
||||
Transaction,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import { encodeTransaction } from './encode-transaction';
|
||||
|
||||
export const testOrderSubmission = (
|
||||
order: OrderSubmission,
|
||||
@@ -17,6 +18,9 @@ export const testOrderSubmission = (
|
||||
...expected,
|
||||
};
|
||||
|
||||
expectedOrder.expiresAt = expectedOrder.expiresAt || undefined;
|
||||
expectedOrder.price = expectedOrder.price || undefined;
|
||||
|
||||
const transaction: OrderSubmissionBody = {
|
||||
orderSubmission: expectedOrder,
|
||||
};
|
||||
@@ -32,6 +36,9 @@ export const testOrderAmendment = (
|
||||
...expected,
|
||||
};
|
||||
|
||||
expectedOrder.expiresAt = expectedOrder.expiresAt || undefined;
|
||||
expectedOrder.price = expectedOrder.price || undefined;
|
||||
|
||||
const transaction: OrderAmendmentBody = {
|
||||
orderAmendment: expectedOrder,
|
||||
};
|
||||
@@ -63,7 +70,7 @@ const vegaWalletTransaction = (transaction: Transaction) => {
|
||||
?.token,
|
||||
publicKey: Cypress.env('VEGA_PUBLIC_KEY2'),
|
||||
sendingMode: 'TYPE_SYNC',
|
||||
transaction,
|
||||
encodedTransaction: encodeTransaction(transaction),
|
||||
});
|
||||
cy.getByTestId(dialogTitle).should(
|
||||
'have.text',
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 32 KiB |
@@ -1,10 +1,14 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { marketsWithDataProvider } from '@vegaprotocol/market-list';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
titlefy,
|
||||
useDataProvider,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useGlobalStore, usePageTitleStore } from '../../stores';
|
||||
|
||||
export const Home = () => {
|
||||
const navigate = useNavigate();
|
||||
@@ -13,26 +17,40 @@ export const Home = () => {
|
||||
const { data, error, loading } = useDataProvider({
|
||||
dataProvider: marketsWithDataProvider,
|
||||
});
|
||||
const update = useGlobalStore((store) => store.update);
|
||||
const marketId = useGlobalStore((store) => store.marketId);
|
||||
const { update } = useGlobalStore((store) => ({
|
||||
update: store.update,
|
||||
}));
|
||||
|
||||
const { pageTitle, updateTitle } = usePageTitleStore((store) => ({
|
||||
pageTitle: store.pageTitle,
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
if (marketId) {
|
||||
navigate(Links[Routes.MARKET](marketId), {
|
||||
replace: true,
|
||||
});
|
||||
} else if (data) {
|
||||
const marketDataId = data[0]?.id;
|
||||
if (marketDataId) {
|
||||
navigate(Links[Routes.MARKET](marketDataId), {
|
||||
if (data) {
|
||||
const marketId = data[0]?.id;
|
||||
const marketName = data[0]?.tradableInstrument.instrument.name;
|
||||
const marketPrice = data[0]?.data?.markPrice
|
||||
? addDecimalsFormatNumber(
|
||||
data[0]?.data?.markPrice,
|
||||
data[0]?.decimalPlaces
|
||||
)
|
||||
: null;
|
||||
const newPageTitle = titlefy([marketName, marketPrice]);
|
||||
|
||||
if (marketId) {
|
||||
navigate(Links[Routes.MARKET](marketId), {
|
||||
replace: true,
|
||||
});
|
||||
update({ marketId });
|
||||
if (pageTitle !== newPageTitle) {
|
||||
updateTitle(newPageTitle);
|
||||
}
|
||||
} else {
|
||||
navigate(Links[Routes.MARKET]());
|
||||
}
|
||||
update({ shouldDisplayWelcomeDialog: true });
|
||||
}
|
||||
}, [marketId, data, navigate, update]);
|
||||
}, [data, navigate, update, pageTitle, updateTitle]);
|
||||
|
||||
return (
|
||||
<AsyncRenderer data={data} loading={loading} error={error}>
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
NetworkParams,
|
||||
t,
|
||||
useDataProvider,
|
||||
useNetworkParams,
|
||||
useNetworkParam,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
@@ -91,10 +91,11 @@ export const LiquidityContainer = ({
|
||||
marketProvision?.market?.tradableInstrument.instrument.product
|
||||
.settlementAsset.symbol;
|
||||
|
||||
const { params } = useNetworkParams([
|
||||
NetworkParams.market_liquidity_stakeToCcyVolume,
|
||||
]);
|
||||
const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume;
|
||||
const { param: stakeToCcySiskas } = useNetworkParam(
|
||||
NetworkParams.market_liquidity_stakeToCcySiskas
|
||||
);
|
||||
const stakeToCcySiska = stakeToCcySiskas && stakeToCcySiskas[0];
|
||||
|
||||
const filteredEdges = useMemo(
|
||||
() =>
|
||||
liquidityProviders?.filter((e) =>
|
||||
@@ -114,7 +115,7 @@ export const LiquidityContainer = ({
|
||||
data={filteredEdges}
|
||||
symbol={symbol}
|
||||
assetDecimalPlaces={assetDecimalPlaces}
|
||||
stakeToCcyVolume={stakeToCcyVolume}
|
||||
stakeToCcySiskas={stakeToCcySiska}
|
||||
/>
|
||||
</AsyncRenderer>
|
||||
);
|
||||
@@ -179,10 +180,11 @@ export const LiquidityViewContainer = ({
|
||||
marketProvision?.market?.tradableInstrument.instrument.product
|
||||
.settlementAsset.symbol;
|
||||
|
||||
const { params } = useNetworkParams([
|
||||
NetworkParams.market_liquidity_stakeToCcyVolume,
|
||||
]);
|
||||
const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume;
|
||||
const { param: stakeToCcySiskas } = useNetworkParam(
|
||||
NetworkParams.market_liquidity_stakeToCcySiskas
|
||||
);
|
||||
const stakeToCcySiska = stakeToCcySiskas && stakeToCcySiskas[0];
|
||||
|
||||
const myLpEdges = useMemo(
|
||||
() => liquidityProviders?.filter((e) => e.party.id === pubKey),
|
||||
[liquidityProviders, pubKey]
|
||||
@@ -277,7 +279,7 @@ export const LiquidityViewContainer = ({
|
||||
ref={gridRef}
|
||||
data={myLpEdges}
|
||||
symbol={symbol}
|
||||
stakeToCcyVolume={stakeToCcyVolume}
|
||||
stakeToCcySiskas={stakeToCcySiska}
|
||||
assetDecimalPlaces={assetDecimalPlaces}
|
||||
/>
|
||||
)}
|
||||
@@ -289,7 +291,7 @@ export const LiquidityViewContainer = ({
|
||||
data={activeEdges}
|
||||
symbol={symbol}
|
||||
assetDecimalPlaces={assetDecimalPlaces}
|
||||
stakeToCcyVolume={stakeToCcyVolume}
|
||||
stakeToCcySiskas={stakeToCcySiska}
|
||||
/>
|
||||
)}
|
||||
</Tab>
|
||||
@@ -301,7 +303,7 @@ export const LiquidityViewContainer = ({
|
||||
data={inactiveEdges}
|
||||
symbol={symbol}
|
||||
assetDecimalPlaces={assetDecimalPlaces}
|
||||
stakeToCcyVolume={stakeToCcyVolume}
|
||||
stakeToCcySiskas={stakeToCcySiska}
|
||||
/>
|
||||
)}
|
||||
</Tab>
|
||||
|
||||
@@ -32,23 +32,29 @@ export interface SingleMarketData extends SingleMarketFieldsFragment {
|
||||
}
|
||||
|
||||
export const Market = () => {
|
||||
const { marketId } = useParams();
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { w } = useWindowSize();
|
||||
const update = useGlobalStore((store) => store.update);
|
||||
const lastMarketId = useGlobalStore((store) => store.marketId);
|
||||
const marketId = params.marketId;
|
||||
|
||||
const pageTitle = usePageTitleStore((store) => store.pageTitle);
|
||||
const updateTitle = usePageTitleStore((store) => store.updateTitle);
|
||||
const { w } = useWindowSize();
|
||||
const { update } = useGlobalStore((store) => ({
|
||||
update: store.update,
|
||||
}));
|
||||
|
||||
const { pageTitle, updateTitle } = usePageTitleStore((store) => ({
|
||||
pageTitle: store.pageTitle,
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
|
||||
const onSelect = useCallback(
|
||||
(id: string) => {
|
||||
if (id && id !== marketId) {
|
||||
update({ marketId: id });
|
||||
navigate(Links[Routes.MARKET](id));
|
||||
}
|
||||
},
|
||||
[marketId, navigate]
|
||||
[marketId, update, navigate]
|
||||
);
|
||||
|
||||
const variables = useMemo(
|
||||
@@ -58,22 +64,12 @@ export const Market = () => {
|
||||
[marketId]
|
||||
);
|
||||
|
||||
const updateMarketId = useCallback(
|
||||
({ data }: { data: { id?: string } | null }) => {
|
||||
if (data?.id && data.id !== lastMarketId) {
|
||||
update({ marketId: data.id });
|
||||
}
|
||||
return true;
|
||||
},
|
||||
[update, lastMarketId]
|
||||
);
|
||||
const { data, error, loading } = useDataProvider<
|
||||
SingleMarketFieldsFragment,
|
||||
never
|
||||
>({
|
||||
dataProvider: marketProvider,
|
||||
variables,
|
||||
update: updateMarketId,
|
||||
skip: !marketId,
|
||||
});
|
||||
|
||||
@@ -108,10 +104,11 @@ export const Market = () => {
|
||||
}
|
||||
return <TradePanels market={data} onSelect={onSelect} />;
|
||||
}, [w, data, onSelect]);
|
||||
|
||||
if (!data && marketId) {
|
||||
return (
|
||||
<Splash>
|
||||
<p>{t('Market not found')}</p>
|
||||
<p>{t('Not found')}</p>
|
||||
</Splash>
|
||||
);
|
||||
}
|
||||
@@ -122,9 +119,13 @@ export const Market = () => {
|
||||
error={error}
|
||||
data={data || undefined}
|
||||
noDataCondition={(data) => false}
|
||||
>
|
||||
{tradeView}
|
||||
</AsyncRenderer>
|
||||
render={(data) => {
|
||||
if (!data && marketId) {
|
||||
return <Splash>{t('Market not found')}</Splash>;
|
||||
}
|
||||
return <>{tradeView}</>;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import { Last24hPriceChange } from '../../components/last-24h-price-change';
|
||||
import { Last24hVolume } from '../../components/last-24h-volume';
|
||||
import { MarketState } from '../../components/market-state';
|
||||
import { MarketTradingMode } from '../../components/market-trading-mode';
|
||||
import { MarketLiquiditySupplied } from '../../components/liquidity-supplied';
|
||||
|
||||
interface TradeMarketHeaderProps {
|
||||
market: SingleMarketFieldsFragment | null;
|
||||
@@ -97,10 +96,6 @@ export const TradeMarketHeader = ({
|
||||
</HeaderStat>
|
||||
) : null}
|
||||
<MarketProposalNotification marketId={market?.id} />
|
||||
<MarketLiquiditySupplied
|
||||
marketId={market?.id}
|
||||
assetDecimals={asset?.decimals || 0}
|
||||
/>
|
||||
</Header>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import { useCallback } from 'react';
|
||||
import { MarketsContainer } from '@vegaprotocol/market-list';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
|
||||
export const Markets = () => {
|
||||
const navigate = useNavigate();
|
||||
const { update } = useGlobalStore((store) => ({ update: store.update }));
|
||||
const handleOnSelect = useCallback(
|
||||
(marketId: string) => {
|
||||
update({ marketId });
|
||||
navigate(Links[Routes.MARKET](marketId));
|
||||
},
|
||||
[navigate]
|
||||
[update, navigate]
|
||||
);
|
||||
|
||||
return <MarketsContainer onSelect={handleOnSelect} />;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './liquidity-supplied';
|
||||
@@ -1,130 +0,0 @@
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumberPercentage,
|
||||
NetworkParams,
|
||||
t,
|
||||
useDataProvider,
|
||||
useNetworkParams,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
MarketData,
|
||||
MarketDataUpdateFieldsFragment,
|
||||
SingleMarketFieldsFragment,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
|
||||
import { HeaderStat } from '../header';
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { useCheckLiquidityStatus } from '@vegaprotocol/liquidity';
|
||||
import { DataGrid } from '@vegaprotocol/react-helpers';
|
||||
|
||||
interface Props {
|
||||
marketId?: string;
|
||||
noUpdate?: boolean;
|
||||
assetDecimals: number;
|
||||
}
|
||||
|
||||
export const MarketLiquiditySupplied = ({
|
||||
marketId,
|
||||
assetDecimals,
|
||||
noUpdate = false,
|
||||
}: Props) => {
|
||||
const [market, setMarket] = useState<MarketData>();
|
||||
const { params } = useNetworkParams([
|
||||
NetworkParams.market_liquidity_stakeToCcyVolume,
|
||||
NetworkParams.market_liquidity_targetstake_triggering_ratio,
|
||||
]);
|
||||
|
||||
const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume;
|
||||
const triggeringRatio = Number(
|
||||
params.market_liquidity_targetstake_triggering_ratio
|
||||
);
|
||||
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
marketId: marketId,
|
||||
}),
|
||||
[marketId]
|
||||
);
|
||||
|
||||
const { data } = useDataProvider<SingleMarketFieldsFragment, never>({
|
||||
dataProvider: marketProvider,
|
||||
variables,
|
||||
skip: !marketId,
|
||||
});
|
||||
|
||||
const update = useCallback(
|
||||
({ data: marketData }: { data: MarketData | null }) => {
|
||||
if (!noUpdate && marketData) {
|
||||
setMarket(marketData);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
[noUpdate]
|
||||
);
|
||||
|
||||
useDataProvider<MarketData, MarketDataUpdateFieldsFragment>({
|
||||
dataProvider: marketDataProvider,
|
||||
update,
|
||||
variables,
|
||||
skip: noUpdate || !marketId || !data,
|
||||
});
|
||||
|
||||
const supplied = market?.suppliedStake
|
||||
? addDecimalsFormatNumber(
|
||||
new BigNumber(market?.suppliedStake)
|
||||
.multipliedBy(stakeToCcyVolume || 1)
|
||||
.toString(),
|
||||
assetDecimals
|
||||
)
|
||||
: '-';
|
||||
|
||||
const { percentage } = useCheckLiquidityStatus({
|
||||
suppliedStake: market?.suppliedStake || 0,
|
||||
targetStake: market?.targetStake || 0,
|
||||
triggeringRatio,
|
||||
});
|
||||
|
||||
const compiledGrid = [
|
||||
{
|
||||
label: t('Supplied stake'),
|
||||
value: market?.suppliedStake
|
||||
? addDecimalsFormatNumber(
|
||||
new BigNumber(market?.suppliedStake).toString(),
|
||||
assetDecimals
|
||||
)
|
||||
: '-',
|
||||
},
|
||||
{
|
||||
label: t('Target stake'),
|
||||
value: market?.targetStake
|
||||
? addDecimalsFormatNumber(
|
||||
new BigNumber(market?.targetStake).toString(),
|
||||
assetDecimals
|
||||
)
|
||||
: '-',
|
||||
},
|
||||
];
|
||||
|
||||
const description = (
|
||||
<section>
|
||||
{compiledGrid && <DataGrid grid={compiledGrid} />}
|
||||
<br />
|
||||
<Link href={`/#/liquidity/${marketId}`} data-testid="view-liquidity-link">
|
||||
{t('View liquidity provision table')}
|
||||
</Link>
|
||||
</section>
|
||||
);
|
||||
|
||||
return (
|
||||
<HeaderStat
|
||||
heading={t('Liquidity supplied')}
|
||||
description={description}
|
||||
testId="liquidity-supplied"
|
||||
>
|
||||
{/* <Indicator variant={status} /> */}
|
||||
{supplied} ({formatNumberPercentage(percentage, 2)})
|
||||
</HeaderStat>
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useMemo, useState, useCallback } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { Dialog } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
@@ -12,50 +12,59 @@ import * as constants from '../constants';
|
||||
import { RiskNoticeDialog } from './risk-notice-dialog';
|
||||
import { WelcomeNoticeDialog } from './welcome-notice-dialog';
|
||||
import { WelcomeLandingDialog } from './welcome-landing-dialog';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
|
||||
interface DialogConfig {
|
||||
open?: boolean;
|
||||
content: React.ReactNode;
|
||||
title?: string;
|
||||
size?: 'small' | 'medium';
|
||||
onClose: () => void;
|
||||
}
|
||||
export const WelcomeDialog = () => {
|
||||
const { pathname } = useLocation();
|
||||
const { VEGA_ENV } = useEnvironment();
|
||||
let dialogContent: React.ReactNode = null;
|
||||
let title = '';
|
||||
let size: 'small' | 'medium' = 'small';
|
||||
const [dialog, setDialog] = useState<DialogConfig | null>(null);
|
||||
const onClose = useCallback(() => {
|
||||
setDialog(null);
|
||||
}, [setDialog]);
|
||||
const [riskAccepted] = useLocalStorage(constants.RISK_ACCEPTED_KEY);
|
||||
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: activeMarketsProvider,
|
||||
});
|
||||
|
||||
const { update, shouldDisplayWelcomeDialog } = useGlobalStore((store) => ({
|
||||
update: store.update,
|
||||
shouldDisplayWelcomeDialog: store.shouldDisplayWelcomeDialog,
|
||||
}));
|
||||
const isRiskDialogNeeded =
|
||||
riskAccepted !== 'true' && VEGA_ENV === Networks.MAINNET;
|
||||
const isWelcomeDialogNeeded = pathname === '/' || shouldDisplayWelcomeDialog;
|
||||
const onClose = useCallback(() => {
|
||||
update({ shouldDisplayWelcomeDialog: isRiskDialogNeeded });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
dialogContent = null;
|
||||
}, [update, isRiskDialogNeeded]);
|
||||
|
||||
if (isRiskDialogNeeded) {
|
||||
dialogContent = <RiskNoticeDialog onClose={onClose} />;
|
||||
title = t('WARNING');
|
||||
size = 'medium';
|
||||
} else if (isWelcomeDialogNeeded && data?.length === 0) {
|
||||
dialogContent = <WelcomeNoticeDialog />;
|
||||
} else if (isWelcomeDialogNeeded && (data?.length || 0) > 0) {
|
||||
dialogContent = <WelcomeLandingDialog onClose={onClose} />;
|
||||
}
|
||||
|
||||
return (
|
||||
useMemo(() => {
|
||||
switch (true) {
|
||||
case riskAccepted !== 'true' && VEGA_ENV === Networks.MAINNET:
|
||||
setDialog({
|
||||
content: <RiskNoticeDialog onClose={onClose} />,
|
||||
title: t('WARNING'),
|
||||
size: 'medium',
|
||||
onClose,
|
||||
});
|
||||
break;
|
||||
case pathname === '/' && data?.length === 0:
|
||||
setDialog({
|
||||
content: <WelcomeNoticeDialog />,
|
||||
onClose,
|
||||
});
|
||||
break;
|
||||
case pathname === '/' && (data?.length || 0) > 0:
|
||||
setDialog({
|
||||
content: <WelcomeLandingDialog onClose={onClose} />,
|
||||
onClose,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}, [onClose, data?.length, riskAccepted, pathname, VEGA_ENV, setDialog]);
|
||||
return dialog ? (
|
||||
<Dialog
|
||||
open={Boolean(dialogContent)}
|
||||
title={title}
|
||||
size={size}
|
||||
onChange={onClose}
|
||||
open={Boolean(dialog.content)}
|
||||
title={dialog.title}
|
||||
size={dialog.size}
|
||||
onChange={dialog.onClose}
|
||||
>
|
||||
{dialogContent}
|
||||
{dialog.content}
|
||||
</Dialog>
|
||||
);
|
||||
) : null;
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from '../select-market';
|
||||
import { WelcomeDialogHeader } from './welcome-dialog-header';
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
import { ProposedMarkets } from './proposed-markets';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
|
||||
@@ -26,13 +27,18 @@ export const SelectMarketLandingTable = ({
|
||||
const navigate = useNavigate();
|
||||
const marketId = params.marketId;
|
||||
|
||||
const { update } = useGlobalStore((store) => ({
|
||||
update: store.update,
|
||||
}));
|
||||
|
||||
const onSelect = useCallback(
|
||||
(id: string) => {
|
||||
if (id && id !== marketId) {
|
||||
update({ marketId: id });
|
||||
navigate(Links[Routes.MARKET](id));
|
||||
}
|
||||
},
|
||||
[marketId, navigate]
|
||||
[marketId, update, navigate]
|
||||
);
|
||||
|
||||
const onSelectMarket = useCallback(
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { RouteObject } from 'react-router-dom';
|
||||
import { useRoutes } from 'react-router-dom';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import trimEnd from 'lodash/trimEnd';
|
||||
|
||||
const LazyHome = dynamic(() => import('../client-pages/home'), {
|
||||
@@ -91,7 +91,7 @@ export const ClientRouter = () => {
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="w-full h-full flex justify-center items-center">
|
||||
<Loader />
|
||||
{t('Loading...')}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { LocalStorage } from '@vegaprotocol/react-helpers';
|
||||
import create from 'zustand';
|
||||
import produce from 'immer';
|
||||
|
||||
interface GlobalStore {
|
||||
networkSwitcherDialog: boolean;
|
||||
marketId: string | null;
|
||||
update: (store: Partial<Omit<GlobalStore, 'update'>>) => void;
|
||||
shouldDisplayWelcomeDialog: boolean;
|
||||
}
|
||||
|
||||
interface PageTitleStore {
|
||||
@@ -17,15 +15,10 @@ interface PageTitleStore {
|
||||
export const useGlobalStore = create<GlobalStore>((set) => ({
|
||||
networkSwitcherDialog: false,
|
||||
marketId: LocalStorage.getItem('marketId') || null,
|
||||
shouldDisplayWelcomeDialog: false,
|
||||
update: (newState) => {
|
||||
set(
|
||||
produce((state: GlobalStore) => {
|
||||
Object.assign(state, newState);
|
||||
})
|
||||
);
|
||||
if (newState.marketId) {
|
||||
LocalStorage.setItem('marketId', newState.marketId);
|
||||
update: (state) => {
|
||||
set(state);
|
||||
if (state.marketId) {
|
||||
LocalStorage.setItem('marketId', state.marketId);
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -213,7 +213,7 @@ export const AssetDetailsTable = ({
|
||||
}: AssetDetailsTableProps) => {
|
||||
const longStringModifiers = (key: AssetDetail, value: string) =>
|
||||
(value && key === AssetDetail.CONTRACT_ADDRESS) || key === AssetDetail.ID
|
||||
? { className: 'break-all', title: value }
|
||||
? { className: 'truncate', title: value }
|
||||
: {};
|
||||
|
||||
const details = rows.map((r) => ({
|
||||
|
||||
@@ -10,10 +10,7 @@ import { addVegaWalletReceiveFaucetedAsset } from './lib/commands/vega-wallet-re
|
||||
import { addContainsExactly } from './lib/commands/contains-exactly';
|
||||
import { addGetNetworkParameters } from './lib/commands/get-network-parameters';
|
||||
import { addUpdateCapsuleMultiSig } from './lib/commands/add-validators-to-multisig';
|
||||
import {
|
||||
addVegaWalletConnect,
|
||||
addSetVegaWallet,
|
||||
} from './lib/commands/vega-wallet-connect';
|
||||
import { addVegaWalletConnect } from './lib/commands/vega-wallet-connect';
|
||||
import { addMockTransactionResponse } from './lib/commands/mock-transaction-response';
|
||||
|
||||
addGetTestIdcommand();
|
||||
@@ -29,7 +26,6 @@ addContainsExactly();
|
||||
addGetNetworkParameters();
|
||||
addUpdateCapsuleMultiSig();
|
||||
addVegaWalletConnect();
|
||||
addSetVegaWallet();
|
||||
addMockTransactionResponse();
|
||||
|
||||
export { mockConnectWallet } from './lib/commands/vega-wallet-connect';
|
||||
|
||||
@@ -7,10 +7,6 @@ declare global {
|
||||
interface Chainable<Subject> {
|
||||
connectVegaWallet(): void;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
interface Chainable<Subject> {
|
||||
setVegaWallet(): void;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +21,7 @@ export const mockConnectWallet = () => {
|
||||
};
|
||||
|
||||
export function addVegaWalletConnect() {
|
||||
// @ts-ignore - ignoring Cypress type error which gets resolved when Cypress uses the command
|
||||
Cypress.Commands.add('connectVegaWallet', () => {
|
||||
mockConnectWallet();
|
||||
cy.highlight(`Connecting Vega Wallet`);
|
||||
@@ -41,18 +38,3 @@ export function addVegaWalletConnect() {
|
||||
cy.get('[data-testid=dialog-content]').should('not.exist');
|
||||
});
|
||||
}
|
||||
|
||||
export function addSetVegaWallet() {
|
||||
Cypress.Commands.add('setVegaWallet', () => {
|
||||
cy.window().then((win) => {
|
||||
win.localStorage.setItem(
|
||||
'vega_wallet_config',
|
||||
JSON.stringify({
|
||||
token: Cypress.env('VEGA_WALLET_API_TOKEN'),
|
||||
connector: 'jsonRpc',
|
||||
url: 'http://localhost:1789',
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { FormGroup, Input, InputError } from '@vegaprotocol/ui-toolkit';
|
||||
import { t, toDecimal, validateAmount } from '@vegaprotocol/react-helpers';
|
||||
import { t, toDecimal } from '@vegaprotocol/react-helpers';
|
||||
import type { DealTicketAmountProps } from './deal-ticket-amount';
|
||||
import { validateAmount } from '../../utils';
|
||||
|
||||
export type DealTicketLimitAmountProps = Omit<
|
||||
DealTicketAmountProps,
|
||||
|
||||
@@ -2,10 +2,9 @@ import {
|
||||
addDecimalsFormatNumber,
|
||||
t,
|
||||
toDecimal,
|
||||
validateAmount,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { Input, InputError, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { isMarketInAuction } from '../../utils';
|
||||
import { isMarketInAuction, validateAmount } from '../../utils';
|
||||
import type { DealTicketAmountProps } from './deal-ticket-amount';
|
||||
import { getMarketPrice } from '../../utils/get-price';
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ import {
|
||||
Tooltip,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { DataGrid, t } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { timeInForceLabel } from '@vegaprotocol/orders';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import { compileGridData } from '../trading-mode-tooltip';
|
||||
import { compileGridData, MarketDataGrid } from '../trading-mode-tooltip';
|
||||
import { MarketModeValidationType } from '../../constants';
|
||||
|
||||
interface TimeInForceSelectorProps {
|
||||
@@ -78,7 +78,9 @@ export const TimeInForceSelector = ({
|
||||
return (
|
||||
<span>
|
||||
{t('This market is in auction until it reaches')}{' '}
|
||||
<Tooltip description={<DataGrid grid={compileGridData(market)} />}>
|
||||
<Tooltip
|
||||
description={<MarketDataGrid grid={compileGridData(market)} />}
|
||||
>
|
||||
<span>{t('sufficient liquidity')}</span>
|
||||
</Tooltip>
|
||||
{'. '}
|
||||
@@ -93,7 +95,9 @@ export const TimeInForceSelector = ({
|
||||
return (
|
||||
<span>
|
||||
{t('This market is in auction due to')}{' '}
|
||||
<Tooltip description={<DataGrid grid={compileGridData(market)} />}>
|
||||
<Tooltip
|
||||
description={<MarketDataGrid grid={compileGridData(market)} />}
|
||||
>
|
||||
<span>{t('high price volatility')}</span>
|
||||
</Tooltip>
|
||||
{'. '}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { FormGroup, InputError, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { DataGrid, t } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { Toggle } from '@vegaprotocol/ui-toolkit';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import { compileGridData } from '../trading-mode-tooltip';
|
||||
import { compileGridData, MarketDataGrid } from '../trading-mode-tooltip';
|
||||
import { MarketModeValidationType } from '../../constants';
|
||||
|
||||
interface TypeSelectorProps {
|
||||
@@ -33,7 +33,9 @@ export const TypeSelector = ({
|
||||
return (
|
||||
<span>
|
||||
{t('This market is in auction until it reaches')}{' '}
|
||||
<Tooltip description={<DataGrid grid={compileGridData(market)} />}>
|
||||
<Tooltip
|
||||
description={<MarketDataGrid grid={compileGridData(market)} />}
|
||||
>
|
||||
<span>{t('sufficient liquidity')}</span>
|
||||
</Tooltip>
|
||||
{'. '}
|
||||
@@ -46,7 +48,9 @@ export const TypeSelector = ({
|
||||
return (
|
||||
<span>
|
||||
{t('This market is in auction due to')}{' '}
|
||||
<Tooltip description={<DataGrid grid={compileGridData(market)} />}>
|
||||
<Tooltip
|
||||
description={<MarketDataGrid grid={compileGridData(market)} />}
|
||||
>
|
||||
<span>{t('high price volatility')}</span>
|
||||
</Tooltip>
|
||||
{'. '}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { DataGridProps } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
t,
|
||||
getDateTimeFormat,
|
||||
@@ -7,6 +6,7 @@ import {
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { Link as UILink } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { MarketDataGridProps } from './market-data-grid';
|
||||
import { Link } from 'react-router-dom';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
|
||||
@@ -14,7 +14,7 @@ export const compileGridData = (
|
||||
market: MarketDealTicket,
|
||||
onSelect?: (id: string) => void
|
||||
): { label: ReactNode; value?: ReactNode }[] => {
|
||||
const grid: DataGridProps['grid'] = [];
|
||||
const grid: MarketDataGridProps['grid'] = [];
|
||||
const isLiquidityMonitoringAuction =
|
||||
market.data.marketTradingMode ===
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './market-data-grid';
|
||||
export * from './trading-mode-tooltip';
|
||||
export * from './compile-grid-data';
|
||||
|
||||
+2
-2
@@ -1,13 +1,13 @@
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
export type DataGridProps = {
|
||||
export type MarketDataGridProps = {
|
||||
grid: {
|
||||
label: string | ReactNode;
|
||||
value?: ReactNode;
|
||||
}[];
|
||||
};
|
||||
|
||||
export const DataGrid = ({ grid }: DataGridProps) => {
|
||||
export const MarketDataGrid = ({ grid }: MarketDataGridProps) => {
|
||||
return (
|
||||
<>
|
||||
{grid.map(
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { DataGrid, t } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { createDocsLinks } from '@vegaprotocol/react-helpers';
|
||||
import { MarketDataGrid } from './market-data-grid';
|
||||
|
||||
type TradingModeTooltipProps = {
|
||||
tradingMode: Schema.MarketTradingMode | null;
|
||||
@@ -45,7 +46,7 @@ export const TradingModeTooltip = ({
|
||||
</ExternalLink>
|
||||
)}
|
||||
</p>
|
||||
{compiledGrid && <DataGrid grid={compiledGrid} />}
|
||||
{compiledGrid && <MarketDataGrid grid={compiledGrid} />}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -71,7 +72,7 @@ export const TradingModeTooltip = ({
|
||||
</ExternalLink>
|
||||
)}
|
||||
</p>
|
||||
{compiledGrid && <DataGrid grid={compiledGrid} />}
|
||||
{compiledGrid && <MarketDataGrid grid={compiledGrid} />}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -93,7 +94,7 @@ export const TradingModeTooltip = ({
|
||||
</ExternalLink>
|
||||
)}
|
||||
</p>
|
||||
{compiledGrid && <DataGrid grid={compiledGrid} />}
|
||||
{compiledGrid && <MarketDataGrid grid={compiledGrid} />}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from './get-default-order';
|
||||
export * from './is-market-in-auction';
|
||||
export * from './validate-amount';
|
||||
export * from './validate-expiration';
|
||||
export * from './validate-market-state';
|
||||
export * from './validate-market-trading-mode';
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { t } from '../i18n';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const validateAmount = (step: number, field: string) => {
|
||||
const [, stepDecimals = ''] = String(step).split('.');
|
||||
@@ -29,7 +29,7 @@ import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import {
|
||||
ETHEREUM_EAGER_CONNECT,
|
||||
useWeb3ConnectStore,
|
||||
getChainName,
|
||||
ChainIdMap,
|
||||
} from '@vegaprotocol/web3';
|
||||
|
||||
interface FormFields {
|
||||
@@ -323,7 +323,7 @@ const FormButton = ({
|
||||
);
|
||||
} else if (chainId !== desiredChainId) {
|
||||
console.log(chainId, desiredChainId);
|
||||
const chainName = getChainName(desiredChainId);
|
||||
const chainName = desiredChainId ? ChainIdMap[desiredChainId] : 'Unknown';
|
||||
message = t(`This app only works on ${chainName}.`);
|
||||
button = (
|
||||
<Button
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { act, render, screen, waitFor } from '@testing-library/react';
|
||||
import { Networks } from '../types';
|
||||
import { EnvironmentProvider } from './use-environment';
|
||||
|
||||
describe('EnvironmentProvider', () => {
|
||||
beforeAll(() => {
|
||||
process.env['NX_MAINTENANCE_PAGE'] = 'true';
|
||||
process.env['NX_VEGA_URL'] = 'https://vega.xyz';
|
||||
process.env['NX_VEGA_ENV'] = Networks.TESTNET;
|
||||
});
|
||||
afterAll(() => {
|
||||
process.env['NX_MAINTENANCE_PAGE'] = '';
|
||||
});
|
||||
it('EnvironmentProvider should return maintenance page', async () => {
|
||||
await act(async () => {
|
||||
render(<EnvironmentProvider />);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('maintenance-page')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
useContext,
|
||||
useCallback,
|
||||
} from 'react';
|
||||
import { MaintenancePage } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
import { NodeSwitcherDialog } from '../components/node-switcher-dialog';
|
||||
import { useConfig } from './use-config';
|
||||
import { useNodes } from './use-nodes';
|
||||
@@ -76,10 +76,7 @@ export const EnvironmentProvider = ({
|
||||
}
|
||||
}
|
||||
);
|
||||
const { state: nodes, clients } = useNodes(
|
||||
config,
|
||||
environment.MAINTENANCE_PAGE
|
||||
);
|
||||
const { state: nodes, clients } = useNodes(config);
|
||||
const nodeKeys = Object.keys(nodes);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -131,10 +128,6 @@ export const EnvironmentProvider = ({
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
if (environment.MAINTENANCE_PAGE) {
|
||||
return <MaintenancePage />;
|
||||
}
|
||||
|
||||
return (
|
||||
<EnvironmentContext.Provider
|
||||
value={{
|
||||
|
||||
@@ -178,7 +178,7 @@ const reducer = (state: Record<string, NodeData>, action: Action) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const useNodes = (config?: Configuration, skip?: boolean) => {
|
||||
export const useNodes = (config?: Configuration) => {
|
||||
const [clients, setClients] = useState<ClientCollection>({});
|
||||
const [state, dispatch] = useReducer(reducer, getInitialState(config));
|
||||
const configCacheKey = config?.hosts.join(';');
|
||||
@@ -193,8 +193,10 @@ export const useNodes = (config?: Configuration, skip?: boolean) => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const hosts = skip ? [] : config?.hosts || [];
|
||||
const nodeUrlMap = hosts.reduce((acc, url) => ({ ...acc, [url]: url }), {});
|
||||
const nodeUrlMap = (config?.hosts || []).reduce(
|
||||
(acc, url) => ({ ...acc, [url]: url }),
|
||||
{}
|
||||
);
|
||||
const { clients: newClients, subscriptions } = initializeNodes(
|
||||
dispatch,
|
||||
nodeUrlMap
|
||||
@@ -206,7 +208,7 @@ export const useNodes = (config?: Configuration, skip?: boolean) => {
|
||||
};
|
||||
// use primitive cache key to prevent infinite rerender loop
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [configCacheKey, skip]);
|
||||
}, [configCacheKey]);
|
||||
|
||||
useEffect(() => {
|
||||
const allNodes = Object.keys(state);
|
||||
|
||||
@@ -38,8 +38,6 @@ const transformValue = (key: EnvKey, value?: string) => {
|
||||
}
|
||||
return {};
|
||||
}
|
||||
case 'MAINTENANCE_PAGE':
|
||||
return ['true', '1', 'yes'].includes(value?.toLowerCase() || '');
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
@@ -78,10 +76,6 @@ const getBundledEnvironmentValue = (key: EnvKey) => {
|
||||
return process.env['NX_VEGA_DOCS_URL'];
|
||||
case 'HOSTED_WALLET_URL':
|
||||
return process.env['NX_HOSTED_WALLET_URL'];
|
||||
case 'MAINTENANCE_PAGE':
|
||||
return (
|
||||
process.env['MAINTENANCE_PAGE'] || process.env['NX_MAINTENANCE_PAGE']
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ const schemaObject = {
|
||||
message: 'The NX_ETHERSCAN_URL environment variable must be a valid url',
|
||||
}),
|
||||
HOSTED_WALLET_URL: z.optional(z.string()),
|
||||
MAINTENANCE_PAGE: z.optional(z.boolean()),
|
||||
};
|
||||
|
||||
export const ENV_KEYS = Object.keys(schemaObject) as Array<
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
import type { LiquidityProviderFeeShare } from '@vegaprotocol/types';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
import { getLiquidityProvision } from './liquidity-data-provider';
|
||||
import type {
|
||||
LiquidityProvisionFieldsFragment,
|
||||
MarketLpQuery,
|
||||
} from './__generated__/MarketLiquidity';
|
||||
|
||||
const input = {
|
||||
liquidityProvisions: [
|
||||
{
|
||||
party: {
|
||||
id: 'dde288688af2aeb5feb349dd72d3679a7a9be34c7375f6a4a48ef2f6140e7e59',
|
||||
accountsConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
type: AccountType.ACCOUNT_TYPE_BOND,
|
||||
balance: '18003328918633596575000',
|
||||
__typename: 'AccountBalance',
|
||||
},
|
||||
__typename: 'AccountEdge',
|
||||
},
|
||||
],
|
||||
__typename: 'AccountsConnection',
|
||||
},
|
||||
__typename: 'Party',
|
||||
},
|
||||
createdAt: '2022-12-16T09:28:29.071781Z',
|
||||
updatedAt: '2023-01-04T22:13:27.761985Z',
|
||||
commitmentAmount: '18003328918633596575000',
|
||||
fee: '0.001',
|
||||
status: 'STATUS_ACTIVE',
|
||||
__typename: 'LiquidityProvision',
|
||||
} as LiquidityProvisionFieldsFragment,
|
||||
],
|
||||
marketLiquidity: {
|
||||
market: {
|
||||
id: 'ccbd651b4a1167fd73c4a0340ac759fa0a31ca487ad46a13254b741ad71947ed',
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 3,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
code: 'UNIDAI.MF21',
|
||||
name: 'UNIDAI Monthly (Dec 2022)',
|
||||
product: {
|
||||
settlementAsset: {
|
||||
id: '16ae5dbb1fd7aa2ddef725703bfe66b3647a4da7b844bfdd04e985756f53d9d6',
|
||||
symbol: 'tDAI',
|
||||
decimals: 18,
|
||||
__typename: 'Asset',
|
||||
},
|
||||
__typename: 'Future',
|
||||
},
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
__typename: 'TradableInstrument',
|
||||
},
|
||||
data: {
|
||||
market: {
|
||||
id: 'ccbd651b4a1167fd73c4a0340ac759fa0a31ca487ad46a13254b741ad71947ed',
|
||||
__typename: 'Market',
|
||||
},
|
||||
marketTradingMode: 'TRADING_MODE_CONTINUOUS',
|
||||
suppliedStake: '18003328918633596575000',
|
||||
openInterest: '89660',
|
||||
targetStake: '70159269843504000000',
|
||||
trigger: 'AUCTION_TRIGGER_UNSPECIFIED',
|
||||
marketValueProxy: '18003328918633596575000',
|
||||
__typename: 'MarketData',
|
||||
},
|
||||
__typename: 'Market',
|
||||
},
|
||||
} as MarketLpQuery,
|
||||
liquidityFeeShare: [
|
||||
{
|
||||
party: {
|
||||
id: 'dde288688af2aeb5feb349dd72d3679a7a9be34c7375f6a4a48ef2f6140e7e59',
|
||||
__typename: 'Party',
|
||||
},
|
||||
equityLikeShare: '1',
|
||||
averageEntryValuation: '12064118310408958216220.7224556301338111',
|
||||
__typename: 'LiquidityProviderFeeShare',
|
||||
} as LiquidityProviderFeeShare,
|
||||
],
|
||||
};
|
||||
|
||||
const result = [
|
||||
{
|
||||
__typename: 'LiquidityProvision',
|
||||
assetDecimalPlaces: 18,
|
||||
averageEntryValuation: '12064118310408958216220.7224556301338111',
|
||||
balance: '1.8003328918633596575e+22',
|
||||
commitmentAmount: '18003328918633596575000',
|
||||
createdAt: '2022-12-16T09:28:29.071781Z',
|
||||
equityLikeShare: '1',
|
||||
fee: '0.001',
|
||||
party: {
|
||||
__typename: 'Party',
|
||||
accountsConnection: {
|
||||
__typename: 'AccountsConnection',
|
||||
edges: [
|
||||
{
|
||||
__typename: 'AccountEdge',
|
||||
node: {
|
||||
__typename: 'AccountBalance',
|
||||
balance: '18003328918633596575000',
|
||||
type: 'ACCOUNT_TYPE_BOND',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
id: 'dde288688af2aeb5feb349dd72d3679a7a9be34c7375f6a4a48ef2f6140e7e59',
|
||||
},
|
||||
status: 'STATUS_ACTIVE',
|
||||
updatedAt: '2023-01-04T22:13:27.761985Z',
|
||||
},
|
||||
];
|
||||
|
||||
describe('getLiquidityProvision', () => {
|
||||
it('should return an empty array when no data is provided', () => {
|
||||
const data = getLiquidityProvision([], {}, []);
|
||||
expect(data).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return correct array when correct liquidity provision parameters are provided', () => {
|
||||
const data = getLiquidityProvision(
|
||||
input.liquidityProvisions,
|
||||
input.marketLiquidity,
|
||||
input.liquidityFeeShare
|
||||
);
|
||||
expect(data).toStrictEqual(result);
|
||||
});
|
||||
|
||||
it('should return empty array when no liquidity provision parameters are provided', () => {
|
||||
const data = getLiquidityProvision(
|
||||
[],
|
||||
input.marketLiquidity,
|
||||
input.liquidityFeeShare
|
||||
);
|
||||
expect(data).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it('should return empty array when no market lp query parameter is provided', () => {
|
||||
const data = getLiquidityProvision(
|
||||
input.liquidityProvisions,
|
||||
{},
|
||||
input.liquidityFeeShare
|
||||
);
|
||||
const result = [
|
||||
{
|
||||
__typename: 'LiquidityProvision',
|
||||
assetDecimalPlaces: undefined,
|
||||
averageEntryValuation: '12064118310408958216220.7224556301338111',
|
||||
balance: '1.8003328918633596575e+22',
|
||||
commitmentAmount: '18003328918633596575000',
|
||||
createdAt: '2022-12-16T09:28:29.071781Z',
|
||||
equityLikeShare: '1',
|
||||
fee: '0.001',
|
||||
party: {
|
||||
__typename: 'Party',
|
||||
accountsConnection: {
|
||||
__typename: 'AccountsConnection',
|
||||
edges: [
|
||||
{
|
||||
__typename: 'AccountEdge',
|
||||
node: {
|
||||
__typename: 'AccountBalance',
|
||||
balance: '18003328918633596575000',
|
||||
type: 'ACCOUNT_TYPE_BOND',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
id: 'dde288688af2aeb5feb349dd72d3679a7a9be34c7375f6a4a48ef2f6140e7e59',
|
||||
},
|
||||
status: 'STATUS_ACTIVE',
|
||||
updatedAt: '2023-01-04T22:13:27.761985Z',
|
||||
},
|
||||
];
|
||||
expect(data).toStrictEqual(result);
|
||||
});
|
||||
|
||||
it('should return empty array when no liquidity fee share param is provided', () => {
|
||||
const data = getLiquidityProvision(
|
||||
input.liquidityProvisions,
|
||||
input.marketLiquidity,
|
||||
[]
|
||||
);
|
||||
const result = [
|
||||
{
|
||||
__typename: 'LiquidityProvision',
|
||||
commitmentAmount: '18003328918633596575000',
|
||||
createdAt: '2022-12-16T09:28:29.071781Z',
|
||||
fee: '0.001',
|
||||
party: {
|
||||
__typename: 'Party',
|
||||
accountsConnection: {
|
||||
__typename: 'AccountsConnection',
|
||||
edges: [
|
||||
{
|
||||
__typename: 'AccountEdge',
|
||||
node: {
|
||||
__typename: 'AccountBalance',
|
||||
balance: '18003328918633596575000',
|
||||
type: 'ACCOUNT_TYPE_BOND',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
id: 'dde288688af2aeb5feb349dd72d3679a7a9be34c7375f6a4a48ef2f6140e7e59',
|
||||
},
|
||||
status: 'STATUS_ACTIVE',
|
||||
updatedAt: '2023-01-04T22:13:27.761985Z',
|
||||
},
|
||||
];
|
||||
expect(data).toStrictEqual(result);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import compact from 'lodash/compact';
|
||||
import { accountsDataProvider } from '@vegaprotocol/accounts';
|
||||
import {
|
||||
makeDataProvider,
|
||||
makeDerivedDataProvider,
|
||||
@@ -24,6 +24,7 @@ import type {
|
||||
LiquidityProvisionsQuery,
|
||||
LiquidityProvisionsUpdateSubscription,
|
||||
} from './__generated__/MarketLiquidity';
|
||||
import type { Account } from '@vegaprotocol/accounts';
|
||||
import type { IterableElement } from 'type-fest';
|
||||
|
||||
export const liquidityProvisionsDataProvider = makeDataProvider<
|
||||
@@ -156,16 +157,22 @@ export const lpAggregatedDataProvider = makeDerivedDataProvider(
|
||||
liquidityProvisionsDataProvider(callback, client, {
|
||||
marketId: variables?.marketId,
|
||||
}),
|
||||
(callback, client, variables) =>
|
||||
accountsDataProvider(callback, client, {
|
||||
partyId: variables?.partyId || '', // party Id can not be null
|
||||
}),
|
||||
marketLiquidityDataProvider,
|
||||
liquidityFeeShareDataProvider,
|
||||
],
|
||||
([
|
||||
liquidityProvisions,
|
||||
accounts,
|
||||
marketLiquidity,
|
||||
liquidityFeeShare,
|
||||
]): LiquidityProvisionData[] => {
|
||||
return getLiquidityProvision(
|
||||
liquidityProvisions,
|
||||
accounts,
|
||||
marketLiquidity,
|
||||
liquidityFeeShare
|
||||
);
|
||||
@@ -174,6 +181,7 @@ export const lpAggregatedDataProvider = makeDerivedDataProvider(
|
||||
|
||||
export const getLiquidityProvision = (
|
||||
liquidityProvisions: LiquidityProvisionFieldsFragment[],
|
||||
accounts: Account[],
|
||||
marketLiquidity: MarketLpQuery,
|
||||
liquidityFeeShare: LiquidityProviderFeeShareFieldsFragment[]
|
||||
): LiquidityProvisionData[] => {
|
||||
@@ -181,27 +189,26 @@ export const getLiquidityProvision = (
|
||||
const market = marketLiquidity?.market;
|
||||
const feeShare = liquidityFeeShare.find((f) => f.party.id === lp.party.id);
|
||||
if (!feeShare) return lp;
|
||||
const accounts = compact(lp.party.accountsConnection?.edges).map(
|
||||
(e) => e.node
|
||||
);
|
||||
const bondAccounts = accounts?.filter(
|
||||
(a) => a?.type === Schema.AccountType.ACCOUNT_TYPE_BOND
|
||||
(a) =>
|
||||
a?.type === Schema.AccountType.ACCOUNT_TYPE_BOND &&
|
||||
(!a.party?.id || a.party?.id === lp.party.id)
|
||||
);
|
||||
const balance =
|
||||
bondAccounts
|
||||
?.reduce(
|
||||
(acc, a) => acc.plus(new BigNumber(a.balance ?? 0)),
|
||||
new BigNumber(0)
|
||||
)
|
||||
.toString() || '0';
|
||||
return {
|
||||
const lpData: LiquidityProvisionData = {
|
||||
...lp,
|
||||
averageEntryValuation: feeShare?.averageEntryValuation,
|
||||
equityLikeShare: feeShare?.equityLikeShare,
|
||||
assetDecimalPlaces:
|
||||
market?.tradableInstrument.instrument.product.settlementAsset.decimals,
|
||||
balance,
|
||||
balance:
|
||||
bondAccounts
|
||||
?.reduce(
|
||||
(acc, a) => acc.plus(new BigNumber(a.balance ?? 0)),
|
||||
new BigNumber(0)
|
||||
)
|
||||
.toString() ?? '0',
|
||||
};
|
||||
return lpData;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('LiquidityTable', () => {
|
||||
it('should render successfully', async () => {
|
||||
await act(async () => {
|
||||
const { baseElement } = render(
|
||||
<LiquidityTable data={[]} stakeToCcyVolume={'1'} />
|
||||
<LiquidityTable data={[]} stakeToCcySiskas={'1'} />
|
||||
);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
@@ -30,7 +30,7 @@ describe('LiquidityTable', () => {
|
||||
|
||||
it('should render correct columns', async () => {
|
||||
await act(async () => {
|
||||
render(<LiquidityTable data={singleRowData} stakeToCcyVolume={'0.3'} />);
|
||||
render(<LiquidityTable data={singleRowData} stakeToCcySiskas={'0.3'} />);
|
||||
});
|
||||
|
||||
const headers = await screen.getAllByRole('columnheader');
|
||||
|
||||
@@ -34,11 +34,11 @@ export interface LiquidityTableProps {
|
||||
data?: LiquidityProvisionData[];
|
||||
symbol?: string;
|
||||
assetDecimalPlaces?: number;
|
||||
stakeToCcyVolume: string | null;
|
||||
stakeToCcySiskas: string | null;
|
||||
}
|
||||
|
||||
export const LiquidityTable = forwardRef<AgGridReact, LiquidityTableProps>(
|
||||
({ data, symbol = '', assetDecimalPlaces, stakeToCcyVolume }, ref) => {
|
||||
({ data, symbol = '', assetDecimalPlaces, stakeToCcySiskas }, ref) => {
|
||||
const assetDecimalsFormatter = ({ value }: ValueFormatterParams) => {
|
||||
if (!value) return '-';
|
||||
return `${addDecimalsFormatNumber(value, assetDecimalPlaces ?? 0, 5)}`;
|
||||
@@ -46,7 +46,7 @@ export const LiquidityTable = forwardRef<AgGridReact, LiquidityTableProps>(
|
||||
const stakeToCcyVolumeFormatter = ({ value }: ValueFormatterParams) => {
|
||||
if (!value) return '-';
|
||||
const newValue = new BigNumber(value)
|
||||
.times(Number(stakeToCcyVolume) || 1)
|
||||
.times(Number(stakeToCcySiskas) || 1)
|
||||
.toString();
|
||||
return `${addDecimalsFormatNumber(newValue, assetDecimalPlaces ?? 0, 5)}`;
|
||||
};
|
||||
|
||||
@@ -31,8 +31,6 @@ import {
|
||||
getTargetStake,
|
||||
} from './utils/liquidity-utils';
|
||||
import type { Provider, LiquidityProvisionMarket } from './utils';
|
||||
import { proposalsListDataProvider } from '@vegaprotocol/governance';
|
||||
import type { Proposal } from '@vegaprotocol/types';
|
||||
|
||||
export interface FeeLevels {
|
||||
commitmentAmount: number;
|
||||
@@ -46,7 +44,6 @@ export type Market = MarketWithData &
|
||||
dayVolume: string;
|
||||
liquidityCommitted: number;
|
||||
volumeChange: string;
|
||||
proposal?: Proposal;
|
||||
};
|
||||
|
||||
export interface Markets {
|
||||
@@ -66,8 +63,7 @@ const getData = (
|
||||
export const addData = (
|
||||
markets: (MarketWithData & MarketWithCandles)[],
|
||||
marketsCandles24hAgo: MarketCandles[],
|
||||
marketsLiquidity: LiquidityProvisionMarket[],
|
||||
proposals: Proposal[]
|
||||
marketsLiquidity: LiquidityProvisionMarket[]
|
||||
) => {
|
||||
return markets.map((market) => {
|
||||
const dayVolume = calcDayVolume(market.candles);
|
||||
@@ -80,9 +76,6 @@ export const addData = (
|
||||
marketsLiquidity
|
||||
) as Provider[];
|
||||
|
||||
const proposalForMarket =
|
||||
proposals && proposals.find((p) => p.id === market.id);
|
||||
|
||||
return {
|
||||
...market,
|
||||
dayVolume,
|
||||
@@ -90,7 +83,6 @@ export const addData = (
|
||||
liquidityCommitted: sumLiquidityCommitted(liquidityProviders),
|
||||
feeLevels: getFeeLevels(liquidityProviders) || [],
|
||||
target: getTargetStake(market.id, marketsLiquidity),
|
||||
proposal: proposalForMarket,
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -114,14 +106,12 @@ const liquidityProvisionProvider = makeDerivedDataProvider<Markets, never>(
|
||||
interval: Schema.Interval.INTERVAL_I1D,
|
||||
}),
|
||||
liquidityMarketsProvider,
|
||||
proposalsListDataProvider,
|
||||
],
|
||||
(parts) => {
|
||||
const data = addData(
|
||||
parts[0] as (MarketWithData & MarketWithCandles)[],
|
||||
parts[1] as MarketCandles[],
|
||||
parts[2] as LiquidityProvisionMarket[],
|
||||
parts[3] as Proposal[]
|
||||
parts[2] as LiquidityProvisionMarket[]
|
||||
);
|
||||
return { markets: data };
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import {
|
||||
formatWithAsset,
|
||||
sumLiquidityCommitted,
|
||||
@@ -9,7 +6,6 @@ import {
|
||||
getCandle24hAgo,
|
||||
getChange,
|
||||
EMPTY_VALUE,
|
||||
useCheckLiquidityStatus,
|
||||
} from './liquidity-utils';
|
||||
|
||||
const CANDLES_1 = [
|
||||
@@ -122,50 +118,3 @@ describe('getChange', () => {
|
||||
expect(result).toEqual(EMPTY_VALUE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useCheckLiquidityStatus', () => {
|
||||
it('should return amber if liquidity is enough', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useCheckLiquidityStatus({
|
||||
suppliedStake: '60',
|
||||
targetStake: '100',
|
||||
triggeringRatio: '0.5',
|
||||
})
|
||||
);
|
||||
|
||||
expect(result.current).toEqual({
|
||||
status: Intent.Warning,
|
||||
percentage: new BigNumber('60'),
|
||||
});
|
||||
});
|
||||
|
||||
it('should return red if liquidity is not enough', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useCheckLiquidityStatus({
|
||||
suppliedStake: '60',
|
||||
targetStake: '100',
|
||||
triggeringRatio: '1',
|
||||
})
|
||||
);
|
||||
|
||||
expect(result.current).toEqual({
|
||||
status: Intent.Danger,
|
||||
percentage: new BigNumber('60'),
|
||||
});
|
||||
});
|
||||
|
||||
it('should return green if liquidity is enough', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useCheckLiquidityStatus({
|
||||
suppliedStake: '101',
|
||||
targetStake: '100',
|
||||
triggeringRatio: '1',
|
||||
})
|
||||
);
|
||||
|
||||
expect(result.current).toEqual({
|
||||
status: Intent.Success,
|
||||
percentage: new BigNumber('101'),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@ import BigNumber from 'bignumber.js';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import type { MarketNodeFragment } from './../__generated__/MarketsLiquidity';
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export type LiquidityProvisionMarket = MarketNodeFragment;
|
||||
|
||||
@@ -118,46 +117,3 @@ export const getTargetStake = (
|
||||
) => {
|
||||
return markets.find((m) => m.id === marketId)?.data?.targetStake || '0';
|
||||
};
|
||||
|
||||
export const useCheckLiquidityStatus = ({
|
||||
suppliedStake,
|
||||
targetStake,
|
||||
triggeringRatio,
|
||||
}: {
|
||||
suppliedStake: string | number;
|
||||
targetStake: string | number;
|
||||
triggeringRatio: string | number;
|
||||
}): {
|
||||
status: Intent;
|
||||
percentage: BigNumber;
|
||||
} => {
|
||||
// percentage supplied
|
||||
const percentage = new BigNumber(suppliedStake)
|
||||
.dividedBy(targetStake)
|
||||
.multipliedBy(100);
|
||||
// IF supplied_stake >= target_stake THEN
|
||||
if (new BigNumber(suppliedStake).gte(new BigNumber(targetStake))) {
|
||||
// show a green status, e.g. "🟢 $13,666,999 liquidity supplied"
|
||||
return {
|
||||
status: Intent.Success,
|
||||
percentage,
|
||||
};
|
||||
// ELSE IF supplied_stake > NETPARAM[market.liquidity.targetstake.triggering.ratio] * target_stake THEN
|
||||
} else if (
|
||||
new BigNumber(suppliedStake).gte(
|
||||
new BigNumber(targetStake).multipliedBy(triggeringRatio)
|
||||
)
|
||||
) {
|
||||
// show an amber status, e.g. "🟠 $3,456,123 liquidity supplied"
|
||||
return {
|
||||
status: Intent.Warning,
|
||||
percentage,
|
||||
};
|
||||
// ELSE show a red status, e.g. "🔴 $600,002 liquidity supplied"
|
||||
} else {
|
||||
return {
|
||||
status: Intent.Danger,
|
||||
percentage,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
+2
-4
@@ -3,14 +3,14 @@ import * as Types from '@vegaprotocol/types';
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type MarketDataUpdateFieldsFragment = { __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null };
|
||||
export type MarketDataUpdateFieldsFragment = { __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string };
|
||||
|
||||
export type MarketDataUpdateSubscriptionVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarketDataUpdateSubscription = { __typename?: 'Subscription', marketsData: Array<{ __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null }> };
|
||||
export type MarketDataUpdateSubscription = { __typename?: 'Subscription', marketsData: Array<{ __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string }> };
|
||||
|
||||
export type MarketDataFieldsFragment = { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, market: { __typename?: 'Market', id: string } };
|
||||
|
||||
@@ -35,8 +35,6 @@ export const MarketDataUpdateFieldsFragmentDoc = gql`
|
||||
indicativePrice
|
||||
bestStaticBidPrice
|
||||
bestStaticOfferPrice
|
||||
targetStake
|
||||
suppliedStake
|
||||
}
|
||||
`;
|
||||
export const MarketDataFieldsFragmentDoc = gql`
|
||||
|
||||
@@ -11,8 +11,6 @@ fragment MarketDataUpdateFields on ObservableMarketData {
|
||||
indicativePrice
|
||||
bestStaticBidPrice
|
||||
bestStaticOfferPrice
|
||||
targetStake
|
||||
suppliedStake
|
||||
}
|
||||
|
||||
subscription MarketDataUpdate($marketId: ID!) {
|
||||
|
||||
@@ -31,7 +31,7 @@ const compileData = (data?: StatsQuery) => {
|
||||
value.forEach((x) => {
|
||||
const stat = {
|
||||
...x,
|
||||
value: statData || '-',
|
||||
value: statData,
|
||||
};
|
||||
|
||||
stat.promoted ? acc.promoted.push(stat) : acc.table.push(stat);
|
||||
@@ -75,7 +75,7 @@ export const StatsManager = ({ className }: StatsManagerProps) => {
|
||||
return (
|
||||
<PromotedStatsItem
|
||||
title={stat.title}
|
||||
value={stat.value || '-'}
|
||||
value={stat.value}
|
||||
formatter={stat.formatter}
|
||||
goodThreshold={stat.goodThreshold}
|
||||
description={stat.description}
|
||||
@@ -92,7 +92,7 @@ export const StatsManager = ({ className }: StatsManagerProps) => {
|
||||
return (
|
||||
<TableRow
|
||||
title={stat.title}
|
||||
value={stat.value || '-'}
|
||||
value={stat.value}
|
||||
formatter={stat.formatter}
|
||||
goodThreshold={stat.goodThreshold}
|
||||
description={stat.description}
|
||||
|
||||
@@ -48,7 +48,13 @@ export const statsFields: { [key in keyof Stats]: StatFields[] } = {
|
||||
description: t('The total number of nodes registered on the network'),
|
||||
},
|
||||
],
|
||||
inactiveNodes: [],
|
||||
inactiveNodes: [
|
||||
{
|
||||
title: t('Inactive nodes'),
|
||||
goodThreshold: (totalInactive: number) => totalInactive < 1,
|
||||
description: t('Nodes that are registered but not validating'),
|
||||
},
|
||||
],
|
||||
stakedTotal: [
|
||||
{
|
||||
title: t('Total staked'),
|
||||
@@ -168,11 +174,11 @@ export const statsFields: { [key in keyof Stats]: StatFields[] } = {
|
||||
title: t('Uptime'),
|
||||
formatter: (t: string) => {
|
||||
if (!t) {
|
||||
return '-';
|
||||
return;
|
||||
}
|
||||
const date = new Date(t);
|
||||
if (!isValidDate(date)) {
|
||||
return '-';
|
||||
return;
|
||||
}
|
||||
const secSinceStart = (new Date().getTime() - date.getTime()) / 1000;
|
||||
const days = Math.floor(secSinceStart / 60 / 60 / 24);
|
||||
@@ -188,13 +194,13 @@ export const statsFields: { [key in keyof Stats]: StatFields[] } = {
|
||||
title: t('Up since'),
|
||||
formatter: (t: string) => {
|
||||
if (!t) {
|
||||
return '-';
|
||||
return;
|
||||
}
|
||||
const date = new Date(t);
|
||||
if (!isValidDate(date)) {
|
||||
return '-';
|
||||
return;
|
||||
}
|
||||
return getDateTimeFormat().format(date) || '-';
|
||||
return getDateTimeFormat().format(date);
|
||||
},
|
||||
description: t('Genesis'),
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user