Merge branch 'master' into task/token-flow-tests
This commit is contained in:
commit
2e15e4dc2e
@ -16,7 +16,7 @@ The trading interface built based on a component toolkit. It will provide a way
|
||||
|
||||
### [Token](./apps/token)
|
||||
|
||||
The utlity dApp for interacting with the Vega token and using its' utility. This includes; delegation, nomination, governance and redemption of tokens.
|
||||
The utility dApp for interacting with the Vega token and using its' utility. This includes; delegation, nomination, governance and redemption of tokens.
|
||||
|
||||
### [Explorer](./apps/explorer)
|
||||
|
||||
@ -51,7 +51,7 @@ A utility library for connecting to the Ethereum network and interacting with Ve
|
||||
|
||||
### [React Helpers](./libs/react-helpers)
|
||||
|
||||
Generic react helpers that can be used across multilpe applications, along with other utilities.
|
||||
Generic react helpers that can be used across multiple applications, along with other utilities.
|
||||
|
||||
# 💻 Develop
|
||||
|
||||
|
26
apps/explorer-e2e/cypress.config.js
Normal file
26
apps/explorer-e2e/cypress.config.js
Normal file
@ -0,0 +1,26 @@
|
||||
const { defineConfig } = require('cypress');
|
||||
const setupNodeEvents = require('./src/plugins/index.js');
|
||||
|
||||
module.exports = defineConfig({
|
||||
projectId: 'et4snf',
|
||||
|
||||
e2e: {
|
||||
setupNodeEvents,
|
||||
baseUrl: 'http://localhost:3000',
|
||||
fileServerFolder: '.',
|
||||
fixturesFolder: false,
|
||||
specPattern: '**/*.feature',
|
||||
excludeSpecPattern: '**/*.js',
|
||||
modifyObstructiveCode: false,
|
||||
supportFile: './src/support/index.ts',
|
||||
video: true,
|
||||
videosFolder: '../../dist/cypress/apps/explorer-e2e/videos',
|
||||
screenshotsFolder: '../../dist/cypress/apps/explorer-e2e/screenshots',
|
||||
chromeWebSecurity: false,
|
||||
},
|
||||
env: {
|
||||
environment: 'CUSTOM',
|
||||
tsConfig: 'tsconfig.json',
|
||||
TAGS: 'not @todo and not @ignore and not @manual',
|
||||
},
|
||||
});
|
@ -1,21 +0,0 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:3000",
|
||||
"projectId": "et4snf",
|
||||
"fileServerFolder": ".",
|
||||
"fixturesFolder": false,
|
||||
"pluginsFile": "./src/plugins/index.js",
|
||||
"testFiles": "*.{ts,feature,features}",
|
||||
"ignoreTestFiles": "**/*.js",
|
||||
"integrationFolder": "./src/integration",
|
||||
"modifyObstructiveCode": false,
|
||||
"supportFile": "./src/support/index.ts",
|
||||
"video": true,
|
||||
"videosFolder": "../../dist/cypress/apps/explorer-e2e/videos",
|
||||
"screenshotsFolder": "../../dist/cypress/apps/explorer-e2e/screenshots",
|
||||
"chromeWebSecurity": false,
|
||||
"env": {
|
||||
"environment": "CUSTOM",
|
||||
"tsConfig": "tsconfig.json",
|
||||
"TAGS": "not @todo and not @ignore and not @manual"
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"e2e": {
|
||||
"executor": "@nrwl/cypress:cypress",
|
||||
"options": {
|
||||
"cypressConfig": "apps/explorer-e2e/cypress.json",
|
||||
"cypressConfig": "apps/explorer-e2e/cypress.config.js",
|
||||
"devServerTarget": "explorer:serve"
|
||||
},
|
||||
"configurations": {
|
||||
|
@ -1,3 +1,5 @@
|
||||
@ignore
|
||||
# tendermint times out getting txs on testnet atm
|
||||
Feature: Transactions Page
|
||||
|
||||
Scenario: Navigate to transactions page
|
||||
@ -5,14 +7,12 @@ Feature: Transactions Page
|
||||
When I navigate to the transactions page
|
||||
Then transactions page is correctly displayed
|
||||
|
||||
@ignore
|
||||
Scenario: Navigate to transaction details page
|
||||
Given I am on the homepage
|
||||
When I navigate to the transactions page
|
||||
And I click on the top transaction
|
||||
Then transaction details are displayed
|
||||
|
||||
@ignore
|
||||
Scenario: Navigate to transactions page using mobile
|
||||
Given I am on mobile and open the toggle menu
|
||||
When I navigate to the transactions page
|
||||
|
@ -15,11 +15,9 @@ export default class TransactionsPage extends BasePage {
|
||||
txType = 'tx-type';
|
||||
|
||||
validateTransactionsPagedisplayed() {
|
||||
cy.getByTestId(this.transactionsList).should('have.length.above', 1);
|
||||
cy.getByTestId(this.blockHeight).first().should('not.be.empty');
|
||||
cy.getByTestId(this.numberOfTransactions).first().should('not.be.empty');
|
||||
cy.getByTestId(this.validatorLink).first().should('not.be.empty');
|
||||
cy.getByTestId(this.blockTime).first().should('not.be.empty');
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(5000); // Wait for transactions to load if there are any
|
||||
cy.getByTestId(this.transactionRow).should('have.length.above', 1);
|
||||
}
|
||||
|
||||
validateRefreshBtn() {
|
||||
|
@ -28,9 +28,10 @@ export const Nav = ({ menuOpen }: NavProps) => {
|
||||
className={({ isActive }) =>
|
||||
classnames(
|
||||
'block mb-8 px-8',
|
||||
'text-h5 hover:bg-vega-yellow hover:text-black',
|
||||
'text-h5 hover:bg-vega-pink dark:hover:bg-vega-yellow hover:text-white dark:hover:text-black',
|
||||
{
|
||||
'bg-vega-yellow text-black': isActive,
|
||||
'bg-vega-pink text-white dark:bg-vega-yellow dark:text-black':
|
||||
isActive,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
export { TxList } from './tx-list';
|
||||
export { BlockTxsData } from './block-txs-data';
|
||||
export { TxOrderType } from './tx-order-type';
|
||||
export { TxsInfiniteList } from './txs-infinite-list';
|
||||
export { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||
|
@ -0,0 +1,92 @@
|
||||
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||
import { render, screen, fireEvent, act } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
describe('Txs infinite list item', () => {
|
||||
it('should display "missing vital data" if "Type" data missing', () => {
|
||||
render(
|
||||
<TxsInfiniteListItem
|
||||
// @ts-ignore testing deliberate failure
|
||||
Type={undefined}
|
||||
Command={'test'}
|
||||
Sig={'test'}
|
||||
PubKey={'test'}
|
||||
Nonce={1}
|
||||
TxHash={'test'}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByText('Missing vital data')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display "missing vital data" if "Command" data missing', () => {
|
||||
render(
|
||||
<TxsInfiniteListItem
|
||||
Type={'test'}
|
||||
// @ts-ignore testing deliberate failure
|
||||
Command={undefined}
|
||||
Sig={'test'}
|
||||
PubKey={'test'}
|
||||
Nonce={1}
|
||||
TxHash={'test'}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByText('Missing vital data')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display "missing vital data" if "Pubkey" data missing', () => {
|
||||
render(
|
||||
<TxsInfiniteListItem
|
||||
Type={'test'}
|
||||
Command={'test'}
|
||||
Sig={'test'}
|
||||
// @ts-ignore testing deliberate failure
|
||||
PubKey={undefined}
|
||||
Nonce={1}
|
||||
TxHash={'test'}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByText('Missing vital data')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display "missing vital data" if "TxHash" data missing', () => {
|
||||
render(
|
||||
<TxsInfiniteListItem
|
||||
Type={'test'}
|
||||
Command={'test'}
|
||||
Sig={'test'}
|
||||
PubKey={'test'}
|
||||
Nonce={1}
|
||||
// @ts-ignore testing deliberate failure
|
||||
TxHash={undefined}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByText('Missing vital data')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders data correctly', () => {
|
||||
const testCommandData = JSON.stringify({
|
||||
test: 'test of command data',
|
||||
});
|
||||
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<TxsInfiniteListItem
|
||||
Type={'testType'}
|
||||
Command={testCommandData}
|
||||
Sig={'testSig'}
|
||||
PubKey={'testPubKey'}
|
||||
Nonce={1}
|
||||
TxHash={'testTxHash'}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
expect(screen.getByTestId('tx-hash')).toHaveTextContent('testTxHash');
|
||||
expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey');
|
||||
expect(screen.getByTestId('type')).toHaveTextContent('testType');
|
||||
const button = screen.getByTestId('command-details');
|
||||
act(() => {
|
||||
fireEvent.click(button);
|
||||
});
|
||||
expect(screen.getByText('"test of command data"')).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -0,0 +1,70 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Dialog,
|
||||
Icon,
|
||||
Intent,
|
||||
SyntaxHighlighter,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { TruncatedLink } from '../truncate/truncated-link';
|
||||
import { Routes } from '../../routes/route-names';
|
||||
import { TxOrderType } from './tx-order-type';
|
||||
import type { ChainExplorerTxResponse } from '../../routes/types/chain-explorer-response';
|
||||
|
||||
const TRUNCATE_LENGTH = 14;
|
||||
|
||||
export const TxsInfiniteListItem = ({
|
||||
TxHash,
|
||||
PubKey,
|
||||
Type,
|
||||
Command,
|
||||
}: ChainExplorerTxResponse) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
if (!TxHash || !PubKey || !Type || !Command) {
|
||||
return <div>Missing vital data</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid="transaction-row"
|
||||
className="grid grid-cols-[repeat(2,_1fr)_240px] gap-12 w-full border-t border-black-60 dark:border-white-25 py-8 txs-infinite-list-item"
|
||||
>
|
||||
<div className="whitespace-nowrap overflow-scroll" data-testid="tx-hash">
|
||||
<TruncatedLink
|
||||
to={`/${Routes.TX}/${TxHash}`}
|
||||
text={TxHash}
|
||||
startChars={TRUNCATE_LENGTH}
|
||||
endChars={TRUNCATE_LENGTH}
|
||||
/>
|
||||
</div>
|
||||
<div className="whitespace-nowrap overflow-scroll" data-testid="pub-key">
|
||||
<TruncatedLink
|
||||
to={`/${Routes.PARTIES}/${PubKey}`}
|
||||
text={PubKey}
|
||||
startChars={TRUNCATE_LENGTH}
|
||||
endChars={TRUNCATE_LENGTH}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="flex justify-between whitespace-nowrap overflow-scroll"
|
||||
data-testid="type"
|
||||
>
|
||||
<TxOrderType orderType={Type} />
|
||||
<button
|
||||
title="More details"
|
||||
onClick={() => setOpen(true)}
|
||||
data-testid="command-details"
|
||||
>
|
||||
<Icon name="search-template" />
|
||||
<Dialog
|
||||
open={open}
|
||||
onChange={(isOpen) => setOpen(isOpen)}
|
||||
intent={Intent.None}
|
||||
>
|
||||
<SyntaxHighlighter data={JSON.parse(Command)} />
|
||||
</Dialog>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
134
apps/explorer/src/app/components/txs/txs-infinite-list.spec.tsx
Normal file
134
apps/explorer/src/app/components/txs/txs-infinite-list.spec.tsx
Normal file
@ -0,0 +1,134 @@
|
||||
import { TxsInfiniteList } from './txs-infinite-list';
|
||||
import { render, screen, fireEvent, act } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
const generateTxs = (number: number) => {
|
||||
return Array.from(Array(number)).map((_) => ({
|
||||
Type: 'ChainEvent',
|
||||
Command:
|
||||
'{"txId":"0xc8941ac4ea989988cb8f72e8fdab2e2009376fd17619491439d36b519d27bc93","nonce":"1494","stakingEvent":{"index":"263","block":"14805346","stakeDeposited":{"ethereumAddress":"0x2e5fe63e5d49c26998cf4bfa9b64de1cf9ae7ef2","vegaPublicKey":"657c2a8a5867c43c831e24820b7544e2fdcc1cf610cfe0ece940fe78137400fd","amount":"38471116086510047870875","blockTime":"1652968806"}}}',
|
||||
Sig: 'fe7624ab742c492cf1e667e79de4777992aca8e093c8707e1f22685c3125c6082cd21b85cd966a61ad4ca0cca2f8bed3082565caa5915bc3b2f78c1ae35cac0b',
|
||||
PubKey:
|
||||
'0x7d69327393cdfaaae50e5e215feca65273eafabfb38f32b8124e66298af346d5',
|
||||
Nonce: 18296387398179254000,
|
||||
TxHash:
|
||||
'0x9C753FA6325F7A40D9C4FA5C25E24476C54613E12B1FA2DD841E3BB00D088B77',
|
||||
}));
|
||||
};
|
||||
|
||||
describe('Txs infinite list', () => {
|
||||
it('should display a "no items" message when no items provided', () => {
|
||||
render(
|
||||
<TxsInfiniteList
|
||||
txs={undefined}
|
||||
areTxsLoading={false}
|
||||
hasMoreTxs={false}
|
||||
loadMoreTxs={() => null}
|
||||
error={undefined}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByText('No items')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('error is displayed at item level', () => {
|
||||
const txs = generateTxs(1);
|
||||
render(
|
||||
<TxsInfiniteList
|
||||
txs={txs}
|
||||
areTxsLoading={false}
|
||||
hasMoreTxs={false}
|
||||
loadMoreTxs={() => null}
|
||||
error={Error('test error!')}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByText('Error: test error!')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('item renders data of n length into list of n length', () => {
|
||||
// Provided the number of items doesn't exceed the 30 it initially
|
||||
// desires, all txs will initially render
|
||||
const txs = generateTxs(10);
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<TxsInfiniteList
|
||||
txs={txs}
|
||||
areTxsLoading={false}
|
||||
hasMoreTxs={false}
|
||||
loadMoreTxs={() => null}
|
||||
error={undefined}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(
|
||||
screen
|
||||
.getByTestId('infinite-scroll-wrapper')
|
||||
.querySelectorAll('.txs-infinite-list-item')
|
||||
).toHaveLength(10);
|
||||
});
|
||||
|
||||
it('tries to load more items when required to initially fill the list', () => {
|
||||
// For example, if initially rendering 15, the bottom of the list is
|
||||
// in view of the viewport, and the callback should be executed
|
||||
const txs = generateTxs(15);
|
||||
const callback = jest.fn();
|
||||
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<TxsInfiniteList
|
||||
txs={txs}
|
||||
areTxsLoading={false}
|
||||
hasMoreTxs={true}
|
||||
loadMoreTxs={callback}
|
||||
error={undefined}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(callback.mock.calls.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('does not try to load more items if there are no more', () => {
|
||||
const txs = generateTxs(3);
|
||||
const callback = jest.fn();
|
||||
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<TxsInfiniteList
|
||||
txs={txs}
|
||||
areTxsLoading={false}
|
||||
hasMoreTxs={false}
|
||||
loadMoreTxs={callback}
|
||||
error={undefined}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(callback.mock.calls.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('loads more items is called when scrolled', () => {
|
||||
const txs = generateTxs(20);
|
||||
const callback = jest.fn();
|
||||
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<TxsInfiniteList
|
||||
txs={txs}
|
||||
areTxsLoading={false}
|
||||
hasMoreTxs={true}
|
||||
loadMoreTxs={callback}
|
||||
error={undefined}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
act(() => {
|
||||
fireEvent.scroll(screen.getByTestId('infinite-scroll-wrapper'), {
|
||||
target: { scrollY: 600 },
|
||||
});
|
||||
});
|
||||
|
||||
expect(callback.mock.calls.length).toEqual(1);
|
||||
});
|
||||
});
|
109
apps/explorer/src/app/components/txs/txs-infinite-list.tsx
Normal file
109
apps/explorer/src/app/components/txs/txs-infinite-list.tsx
Normal file
@ -0,0 +1,109 @@
|
||||
import React from 'react';
|
||||
import { FixedSizeList as List } from 'react-window';
|
||||
import InfiniteLoader from 'react-window-infinite-loader';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { TxsInfiniteListItem } from './txs-infinite-list-item';
|
||||
import type { ChainExplorerTxResponse } from '../../routes/types/chain-explorer-response';
|
||||
|
||||
interface TxsInfiniteListProps {
|
||||
hasMoreTxs: boolean;
|
||||
areTxsLoading: boolean | undefined;
|
||||
txs: ChainExplorerTxResponse[] | undefined;
|
||||
loadMoreTxs: () => void;
|
||||
error: Error | undefined;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
interface ItemProps {
|
||||
index: ChainExplorerTxResponse;
|
||||
style: React.CSSProperties;
|
||||
isLoading: boolean;
|
||||
error: Error | undefined;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const NOOP = () => {};
|
||||
|
||||
const Item = ({ index, style, isLoading, error }: ItemProps) => {
|
||||
let content;
|
||||
if (error) {
|
||||
content = t(`${error}`);
|
||||
} else if (isLoading) {
|
||||
content = t('Loading...');
|
||||
} else {
|
||||
const { TxHash, PubKey, Type, Command, Sig, Nonce } = index;
|
||||
content = (
|
||||
<TxsInfiniteListItem
|
||||
Type={Type}
|
||||
Command={Command}
|
||||
Sig={Sig}
|
||||
PubKey={PubKey}
|
||||
Nonce={Nonce}
|
||||
TxHash={TxHash}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <div style={style}>{content}</div>;
|
||||
};
|
||||
|
||||
export const TxsInfiniteList = ({
|
||||
hasMoreTxs,
|
||||
areTxsLoading,
|
||||
txs,
|
||||
loadMoreTxs,
|
||||
error,
|
||||
className,
|
||||
}: TxsInfiniteListProps) => {
|
||||
if (!txs) {
|
||||
return <div>No items</div>;
|
||||
}
|
||||
|
||||
// If there are more items to be loaded then add an extra row to hold a loading indicator.
|
||||
const itemCount = hasMoreTxs ? txs.length + 1 : txs.length;
|
||||
|
||||
// Pass an empty callback to InfiniteLoader in case it asks us to load more than once.
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const loadMoreItems = areTxsLoading ? NOOP : loadMoreTxs;
|
||||
|
||||
// Every row is loaded except for our loading indicator row.
|
||||
const isItemLoaded = (index: number) => !hasMoreTxs || index < txs.length;
|
||||
|
||||
return (
|
||||
<div className={className} data-testid="transactions-list">
|
||||
<div className="grid grid-cols-[repeat(2,_1fr)_240px] gap-12 w-full mb-8">
|
||||
<div className="text-h5 font-bold">Txn hash</div>
|
||||
<div className="text-h5 font-bold">Party</div>
|
||||
<div className="text-h5 font-bold pl-2">Type</div>
|
||||
</div>
|
||||
<div data-testid="infinite-scroll-wrapper">
|
||||
<InfiniteLoader
|
||||
isItemLoaded={isItemLoaded}
|
||||
itemCount={itemCount}
|
||||
loadMoreItems={loadMoreItems}
|
||||
>
|
||||
{({ onItemsRendered, ref }) => (
|
||||
<List
|
||||
className="List"
|
||||
height={595}
|
||||
itemCount={itemCount}
|
||||
itemSize={41}
|
||||
onItemsRendered={onItemsRendered}
|
||||
ref={ref}
|
||||
width={'100%'}
|
||||
>
|
||||
{({ index, style }) => (
|
||||
<Item
|
||||
index={txs[index]}
|
||||
style={style}
|
||||
isLoading={!isItemLoaded(index)}
|
||||
error={error}
|
||||
/>
|
||||
)}
|
||||
</List>
|
||||
)}
|
||||
</InfiniteLoader>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -12,7 +12,7 @@ import Genesis from './genesis';
|
||||
import { Block } from './blocks/id';
|
||||
import { Blocks } from './blocks/home';
|
||||
import { Tx } from './txs/id';
|
||||
import { Txs as TxHome } from './txs/home';
|
||||
import { TxsHome } from './txs/home';
|
||||
import { PendingTxs } from './pending';
|
||||
import flags from '../config/flags';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
@ -129,7 +129,7 @@ const routerConfig = [
|
||||
},
|
||||
{
|
||||
index: true,
|
||||
element: <TxHome />,
|
||||
element: <TxsHome />,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -1,32 +1,122 @@
|
||||
import type { TendermintBlockchainResponse } from '../../blocks/tendermint-blockchain-response';
|
||||
import { DATA_SOURCES } from '../../../config';
|
||||
import { useCallback, useState, useMemo } from 'react';
|
||||
import { t, useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { RouteTitle } from '../../../components/route-title';
|
||||
import { BlocksRefetch } from '../../../components/blocks';
|
||||
import { RenderFetched } from '../../../components/render-fetched';
|
||||
import { BlockTxsData } from '../../../components/txs';
|
||||
import { JumpToBlock } from '../../../components/jump-to-block';
|
||||
import { t, useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { TxsInfiniteList } from '../../../components/txs';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ChainExplorerTxResponse } from '../../types/chain-explorer-response';
|
||||
import type { TendermintBlockchainResponse } from '../../blocks/tendermint-blockchain-response';
|
||||
|
||||
const Txs = () => {
|
||||
const {
|
||||
state: { data, error, loading },
|
||||
refetch,
|
||||
} = useFetch<TendermintBlockchainResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/blockchain`
|
||||
interface TxsProps {
|
||||
latestBlockHeight: string;
|
||||
}
|
||||
|
||||
interface TxsStateProps {
|
||||
txsData: ChainExplorerTxResponse[];
|
||||
hasMoreTxs: boolean;
|
||||
nextPage: number;
|
||||
}
|
||||
|
||||
const Txs = ({ latestBlockHeight }: TxsProps) => {
|
||||
const [{ txsData, hasMoreTxs, nextPage }, setTxsState] =
|
||||
useState<TxsStateProps>({
|
||||
txsData: [],
|
||||
hasMoreTxs: true,
|
||||
nextPage: 1,
|
||||
});
|
||||
|
||||
const reusedBodyParams = useMemo(
|
||||
() => ({
|
||||
node_url: DATA_SOURCES.tendermintUrl,
|
||||
transaction_height: parseInt(latestBlockHeight),
|
||||
page_size: 30,
|
||||
}),
|
||||
[latestBlockHeight]
|
||||
);
|
||||
|
||||
const {
|
||||
state: { error, loading },
|
||||
refetch,
|
||||
} = useFetch(
|
||||
DATA_SOURCES.chainExplorerUrl,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify(reusedBodyParams),
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
const loadTxs = useCallback(async () => {
|
||||
const data = await refetch(
|
||||
undefined,
|
||||
JSON.stringify({
|
||||
...reusedBodyParams,
|
||||
page_number: nextPage,
|
||||
})
|
||||
);
|
||||
|
||||
if (data) {
|
||||
setTxsState((prev) => ({
|
||||
...prev,
|
||||
nextPage: prev.nextPage + 1,
|
||||
hasMoreTxs: true,
|
||||
txsData: [...prev.txsData, ...(data as ChainExplorerTxResponse[])],
|
||||
}));
|
||||
}
|
||||
}, [nextPage, refetch, reusedBodyParams]);
|
||||
|
||||
return (
|
||||
<section>
|
||||
<RouteTitle>{t('Transactions')}</RouteTitle>
|
||||
<RenderFetched error={error} loading={loading}>
|
||||
<>
|
||||
<BlocksRefetch refetch={refetch} />
|
||||
<BlockTxsData data={data} />
|
||||
</>
|
||||
</RenderFetched>
|
||||
<BlocksRefetch
|
||||
refetch={() =>
|
||||
refetch(
|
||||
undefined,
|
||||
JSON.stringify({
|
||||
...reusedBodyParams,
|
||||
page_number: 1,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
<TxsInfiniteList
|
||||
hasMoreTxs={hasMoreTxs}
|
||||
areTxsLoading={loading}
|
||||
txs={txsData}
|
||||
loadMoreTxs={loadTxs}
|
||||
error={error}
|
||||
className="mb-28"
|
||||
/>
|
||||
<JumpToBlock />
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export { Txs };
|
||||
const Wrapper = () => {
|
||||
const {
|
||||
state: { data, error, loading },
|
||||
} = useFetch<TendermintBlockchainResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/blockchain`
|
||||
);
|
||||
|
||||
return (
|
||||
<AsyncRenderer
|
||||
loading={!!loading}
|
||||
loadingMessage={t('Getting latest block height...')}
|
||||
error={error}
|
||||
data={data}
|
||||
noDataMessage={t('Could not get latest block height')}
|
||||
render={(data) => (
|
||||
<Txs
|
||||
latestBlockHeight={
|
||||
data?.result?.block_metas?.[0]?.header?.height || ''
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export { Wrapper as TxsHome };
|
||||
|
18
apps/simple-trading-app-e2e/cypress.config.js
Normal file
18
apps/simple-trading-app-e2e/cypress.config.js
Normal file
@ -0,0 +1,18 @@
|
||||
const { defineConfig } = require('cypress');
|
||||
module.exports = defineConfig({
|
||||
projectId: 'et4snf',
|
||||
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:4200',
|
||||
fileServerFolder: '.',
|
||||
fixturesFolder: false,
|
||||
specPattern: './src/integration/*.ts',
|
||||
excludeSpecPattern: '**/*.js',
|
||||
modifyObstructiveCode: false,
|
||||
supportFile: './src/support/index.ts',
|
||||
video: true,
|
||||
videosFolder: '../../dist/cypress/apps/explorer-e2e/videos',
|
||||
screenshotsFolder: '../../dist/cypress/apps/explorer-e2e/screenshots',
|
||||
chromeWebSecurity: false,
|
||||
},
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:4200",
|
||||
"fileServerFolder": ".",
|
||||
"testFiles": "*.{ts,feature,features}",
|
||||
"ignoreTestFiles": "**/*.js",
|
||||
"fixturesFolder": "./src/fixtures",
|
||||
"integrationFolder": "./src/integration",
|
||||
"modifyObstructiveCode": false,
|
||||
"supportFile": "./src/support/index.ts",
|
||||
"pluginsFile": false,
|
||||
"video": true,
|
||||
"videosFolder": "../../dist/cypress/apps/simple-trading-app-e2e/videos",
|
||||
"screenshotsFolder": "../../dist/cypress/apps/simple-trading-app-e2e/screenshots",
|
||||
"chromeWebSecurity": false,
|
||||
"projectId": "et4snf"
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"e2e": {
|
||||
"executor": "@nrwl/cypress:cypress",
|
||||
"options": {
|
||||
"cypressConfig": "apps/simple-trading-app-e2e/cypress.json",
|
||||
"cypressConfig": "apps/simple-trading-app-e2e/cypress.config.js",
|
||||
"devServerTarget": "simple-trading-app:serve"
|
||||
},
|
||||
"configurations": {
|
||||
|
@ -60,7 +60,7 @@ describe('market list', () => {
|
||||
cy.intercept('POST', '/query').as('Filters');
|
||||
cy.visit('/markets');
|
||||
cy.wait('@Filters').then((filters) => {
|
||||
if (filters?.response?.body.data.markets.length) {
|
||||
if (filters?.response?.body?.data?.markets?.length) {
|
||||
const asset =
|
||||
filters.response.body.data.markets[0].tradableInstrument.instrument
|
||||
.product.settlementAsset.symbol;
|
||||
|
@ -47,6 +47,10 @@ export interface SimpleMarkets_markets_tradableInstrument_instrument_product_set
|
||||
|
||||
export interface SimpleMarkets_markets_tradableInstrument_instrument_product {
|
||||
__typename: "Future";
|
||||
/**
|
||||
* String representing the quote (e.g. BTCUSD -> USD is quote)
|
||||
*/
|
||||
quoteName: string;
|
||||
/**
|
||||
* The name of the asset (string)
|
||||
*/
|
||||
|
@ -1,19 +1,5 @@
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const MARKET_STATUS: Record<MarketState | '', Intent> = {
|
||||
[MarketState.Active]: Intent.Success,
|
||||
[MarketState.Cancelled]: Intent.Primary,
|
||||
[MarketState.Closed]: Intent.None,
|
||||
[MarketState.Pending]: Intent.Warning,
|
||||
[MarketState.Proposed]: Intent.Warning,
|
||||
[MarketState.Rejected]: Intent.Danger,
|
||||
[MarketState.Settled]: Intent.Primary,
|
||||
[MarketState.Suspended]: Intent.Warning,
|
||||
[MarketState.TradingTerminated]: Intent.Danger,
|
||||
'': Intent.Primary,
|
||||
};
|
||||
import { themelite as theme } from '@vegaprotocol/tailwindcss-config';
|
||||
|
||||
export const STATES_FILTER = [
|
||||
{ value: 'all', text: t('All') },
|
||||
@ -27,3 +13,115 @@ export const STATES_FILTER = [
|
||||
{ value: 'Suspended', text: t('Suspended') },
|
||||
{ value: 'TradingTerminated', text: t('TradingTerminated') },
|
||||
];
|
||||
|
||||
export const agGridLightVariables = `
|
||||
.ag-theme-balham {
|
||||
--ag-row-border-color: ${theme.colors.transparent};
|
||||
--ag-row-hover-color: ${theme.colors.transparent};
|
||||
--ag-font-size: 15px;
|
||||
}
|
||||
.ag-theme-balham .ag-row-hover {
|
||||
--ag-row-border-color: ${theme.colors.black[100]};
|
||||
}
|
||||
.ag-theme-balham [col-id="status"] .ag-header-cell-label,
|
||||
.ag-theme-balham [col-id="asset"] .ag-header-cell-label,
|
||||
.ag-theme-balham [col-id="change"] .ag-header-cell-label{
|
||||
justify-content: center;
|
||||
}
|
||||
.ag-theme-balham .ag-header-row .ag-header-cell:first-child{
|
||||
padding-left: 0;
|
||||
}
|
||||
.ag-theme-balham .ag-ltr .ag-header-cell::after, .ag-theme-balham .ag-ltr .ag-header-group-cell::after {
|
||||
right: 0;
|
||||
}
|
||||
.ag-theme-balham .ag-header-cell::after{
|
||||
width: 0;
|
||||
}
|
||||
.ag-theme-balham .ag-header{
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
.ag-theme-balham .ag-has-focus .ag-row.ag-row-focus .ag-cell-focus {
|
||||
outline: none;
|
||||
border-width: 0;
|
||||
}
|
||||
.ag-theme-balham .ag-header-label-icon .ag-icon{
|
||||
position: relative;
|
||||
}
|
||||
.ag-theme-balham .ag-icon::before{
|
||||
font-size: 10px;
|
||||
line-height: 12px;
|
||||
position: absolute;
|
||||
transform: rotate(45deg);
|
||||
top: -6px;
|
||||
right: -14px;
|
||||
content: "◾";
|
||||
background: -webkit-linear-gradient(135deg, rgba(0,0,0,0.54) 0%, rgba(0,0,0,0.54) 40%, rgba(0,0,0,0) 40%, rgba(0,0,0,0) 52%, rgba(0,0,0,0.54) 52%, rgba(0,0,0,0.54) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
.ag-theme-balham .ag-icon-desc::before{
|
||||
background: -webkit-linear-gradient(135deg, #000 0%, #000 40%, rgba(0,0,0,0) 40%, rgba(0,0,0,0) 52%, rgba(0,0,0,0.54) 52%, rgba(0,0,0,0.54) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
.ag-theme-balham .ag-icon-asc::before{
|
||||
background: -webkit-linear-gradient(135deg, rgba(0,0,0,0.54) 0%, rgba(0,0,0,0.54) 40%, rgba(0,0,0,0) 40%, rgba(0,0,0,0) 52%, #000 52%, #000 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
`;
|
||||
|
||||
export const agGridDarkVariables = `
|
||||
.ag-theme-balham-dark {
|
||||
--ag-row-border-color: ${theme.colors.transparent};
|
||||
--ag-row-hover-color: ${theme.colors.transparent};
|
||||
--ag-font-size: 15px;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-row-hover {
|
||||
--ag-row-border-color: ${theme.colors.white[100]};
|
||||
}
|
||||
.ag-theme-balham-dark [col-id="status"] .ag-header-cell-label,
|
||||
.ag-theme-balham-dark [col-id="asset"] .ag-header-cell-label,
|
||||
.ag-theme-balham-dark [col-id="change"] .ag-header-cell-label{
|
||||
justify-content: center;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-header-row .ag-header-cell:first-child{
|
||||
padding-left: 0;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-header-cell::after{
|
||||
width: 0;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-header{
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-has-focus .ag-row.ag-row-focus .ag-cell-focus {
|
||||
outline: none;
|
||||
border-width: 0;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-header-label-icon .ag-icon{
|
||||
position: relative;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-icon::before{
|
||||
font-size: 10px;
|
||||
line-height: 12px;
|
||||
position: absolute;
|
||||
transform: rotate(45deg);
|
||||
top: -6px;
|
||||
right: -14px;
|
||||
content: "◾";
|
||||
background: -webkit-linear-gradient(135deg, rgba(245, 245, 245, 0.64) 0%, rgba(245, 245, 245, 0.64) 40%, rgba(0,0,0,0) 40%, rgba(0,0,0,0) 52%, rgba(245, 245, 245, 0.64) 52%, rgba(245, 245, 245, 0.64) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-position: center;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-icon-desc::before{
|
||||
background: -webkit-linear-gradient(135deg, #fff 0%, #fff 40%, rgba(0,0,0,0) 40%, rgba(0,0,0,0) 52%, rgba(245, 245, 245, 0.64) 52%, rgba(245, 245, 245, 0.64) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
.ag-theme-balham-dark .ag-icon-asc::before{
|
||||
background: -webkit-linear-gradient(135deg, rgba(245, 245, 245, 0.64) 0%, rgba(245, 245, 245, 0.64) 40%, rgba(0,0,0,0) 40%, rgba(0,0,0,0) 52%, #fff 52%, #fff 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
`;
|
||||
|
@ -36,6 +36,7 @@ export const MARKETS_QUERY = gql`
|
||||
product {
|
||||
__typename
|
||||
... on Future {
|
||||
quoteName
|
||||
settlementAsset {
|
||||
symbol
|
||||
}
|
||||
|
@ -1,6 +1,12 @@
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import {
|
||||
render,
|
||||
screen,
|
||||
waitFor,
|
||||
cleanup,
|
||||
getAllByRole,
|
||||
} from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
@ -37,6 +43,7 @@ describe('SimpleMarketList', () => {
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should be properly renderer as empty', async () => {
|
||||
@ -130,8 +137,12 @@ describe('SimpleMarketList', () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('simple-market-list')).toBeInTheDocument();
|
||||
expect(
|
||||
document.querySelector('.ag-center-cols-container')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByTestId('simple-market-list').children).toHaveLength(2);
|
||||
|
||||
const container = document.querySelector('.ag-center-cols-container');
|
||||
expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
@ -1,17 +1,29 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import React, {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { subDays } from 'date-fns';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { AsyncRenderer, Lozenge, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import { ThemeContext } from '@vegaprotocol/react-helpers';
|
||||
import type { MarketState } from '@vegaprotocol/types';
|
||||
import SimpleMarketPercentChange from './simple-market-percent-change';
|
||||
import SimpleMarketExpires from './simple-market-expires';
|
||||
import DataProvider from './data-provider';
|
||||
import { MARKET_STATUS } from './constants';
|
||||
import SimpleMarketToolbar from './simple-market-toolbar';
|
||||
import useMarketsFilterData from '../../hooks/use-markets-filter-data';
|
||||
import useColumnDefinitions from '../../hooks/use-column-definitions';
|
||||
import DataProvider from './data-provider';
|
||||
import * as constants from './constants';
|
||||
import SimpleMarketToolbar from './simple-market-toolbar';
|
||||
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
||||
|
||||
export type SimpleMarketsType = SimpleMarkets_markets & {
|
||||
percentChange?: number | '-';
|
||||
};
|
||||
|
||||
export type RouterParams = Partial<{
|
||||
product: string;
|
||||
@ -22,8 +34,9 @@ export type RouterParams = Partial<{
|
||||
const SimpleMarketList = () => {
|
||||
const navigate = useNavigate();
|
||||
const params = useParams<RouterParams>();
|
||||
|
||||
const theme = useContext(ThemeContext);
|
||||
const statusesRef = useRef<Record<string, MarketState | ''>>({});
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
CandleSince: subDays(Date.now(), 1).toJSON(),
|
||||
@ -40,7 +53,14 @@ const SimpleMarketList = () => {
|
||||
update,
|
||||
variables
|
||||
);
|
||||
const localData = useMarketsFilterData(data || [], params);
|
||||
const localData: Array<SimpleMarketsType> = useMarketsFilterData(
|
||||
data || [],
|
||||
params
|
||||
);
|
||||
|
||||
const handleOnGridReady = useCallback(() => {
|
||||
gridRef.current?.api.sizeColumnsToFit();
|
||||
}, [gridRef]);
|
||||
|
||||
useEffect(() => {
|
||||
const statuses: Record<string, MarketState | ''> = {};
|
||||
@ -50,6 +70,11 @@ const SimpleMarketList = () => {
|
||||
statusesRef.current = statuses;
|
||||
}, [data, statusesRef]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', handleOnGridReady);
|
||||
return () => window.removeEventListener('resize', handleOnGridReady);
|
||||
}, [handleOnGridReady]);
|
||||
|
||||
const onClick = useCallback(
|
||||
(marketId) => {
|
||||
navigate(`/trading/${marketId}`);
|
||||
@ -57,62 +82,34 @@ const SimpleMarketList = () => {
|
||||
[navigate]
|
||||
);
|
||||
|
||||
const { columnDefs, defaultColDef } = useColumnDefinitions({ onClick });
|
||||
|
||||
const getRowId = useCallback(({ data }) => data.id, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="h-full grid grid-rows-[min-content,1fr]">
|
||||
<SimpleMarketToolbar />
|
||||
<AsyncRenderer loading={loading} error={error} data={localData}>
|
||||
{localData && localData.length > 0 ? (
|
||||
<ul
|
||||
className="list-none relative pt-8 pb-8"
|
||||
data-testid="simple-market-list"
|
||||
>
|
||||
{localData?.map((market) => (
|
||||
<li
|
||||
className="w-full relative flex justify-start items-center no-underline box-border text-left py-8 mb-10"
|
||||
key={market.id}
|
||||
>
|
||||
<div className="w-full grid sm:grid-cols-2">
|
||||
<div className="w-full grid sm:auto-rows-auto">
|
||||
<div className="font-extrabold py-2">{market.name}</div>
|
||||
<SimpleMarketExpires
|
||||
tags={market.tradableInstrument.instrument.metadata.tags}
|
||||
/>
|
||||
<div className="py-2">{`${t('settled in')} ${
|
||||
market.tradableInstrument.instrument.product
|
||||
.settlementAsset.symbol
|
||||
}`}</div>
|
||||
</div>
|
||||
<div className="w-full grid sm:grid-rows-2">
|
||||
<div>
|
||||
<SimpleMarketPercentChange
|
||||
candles={market.candles}
|
||||
marketId={market.id}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Lozenge
|
||||
variant={MARKET_STATUS[market.data?.market.state || '']}
|
||||
>
|
||||
{market.data?.market.state}
|
||||
</Lozenge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute right-16 top-1/2 -translate-y-1/2">
|
||||
<Button
|
||||
onClick={() => onClick(market.id)}
|
||||
variant="inline-link"
|
||||
prependIconName="chevron-right"
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<Splash>{t('No data to display')}</Splash>
|
||||
)}
|
||||
<AgGrid
|
||||
className="mb-32 min-h-[300px]"
|
||||
defaultColDef={defaultColDef}
|
||||
columnDefs={columnDefs}
|
||||
rowData={localData}
|
||||
rowHeight={60}
|
||||
customThemeParams={
|
||||
theme === 'dark'
|
||||
? constants.agGridDarkVariables
|
||||
: constants.agGridLightVariables
|
||||
}
|
||||
onGridReady={handleOnGridReady}
|
||||
ref={gridRef}
|
||||
overlayNoRowsTemplate={t('No data to display')}
|
||||
suppressContextMenu
|
||||
getRowId={getRowId}
|
||||
suppressMovableColumns
|
||||
/>
|
||||
</AsyncRenderer>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -7,11 +7,16 @@ import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarket
|
||||
|
||||
describe('SimpleMarketPercentChange should parse proper change', () => {
|
||||
let candles: (SimpleMarkets_markets_candles | null)[] | null;
|
||||
const setValue = () => undefined;
|
||||
it('empty array', () => {
|
||||
candles = [];
|
||||
render(
|
||||
<MockedProvider>
|
||||
<SimpleMarketPercentChange candles={candles} marketId={'1'} />
|
||||
<SimpleMarketPercentChange
|
||||
candles={candles}
|
||||
marketId={'1'}
|
||||
setValue={setValue}
|
||||
/>
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(screen.getByText('-')).toBeInTheDocument();
|
||||
@ -20,7 +25,11 @@ describe('SimpleMarketPercentChange should parse proper change', () => {
|
||||
candles = null;
|
||||
render(
|
||||
<MockedProvider>
|
||||
<SimpleMarketPercentChange candles={candles} marketId={'1'} />
|
||||
<SimpleMarketPercentChange
|
||||
candles={candles}
|
||||
marketId={'1'}
|
||||
setValue={setValue}
|
||||
/>
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(screen.getByText('-')).toBeInTheDocument();
|
||||
@ -33,7 +42,11 @@ describe('SimpleMarketPercentChange should parse proper change', () => {
|
||||
];
|
||||
render(
|
||||
<MockedProvider>
|
||||
<SimpleMarketPercentChange candles={candles} marketId={'1'} />
|
||||
<SimpleMarketPercentChange
|
||||
candles={candles}
|
||||
marketId={'1'}
|
||||
setValue={setValue}
|
||||
/>
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(screen.getByText('100.000%')).toBeInTheDocument();
|
||||
@ -49,7 +62,11 @@ describe('SimpleMarketPercentChange should parse proper change', () => {
|
||||
];
|
||||
render(
|
||||
<MockedProvider>
|
||||
<SimpleMarketPercentChange candles={candles} marketId={'1'} />
|
||||
<SimpleMarketPercentChange
|
||||
candles={candles}
|
||||
marketId={'1'}
|
||||
setValue={setValue}
|
||||
/>
|
||||
</MockedProvider>
|
||||
);
|
||||
expect(screen.getByText('-50.000%')).toBeInTheDocument();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { InView } from 'react-intersection-observer';
|
||||
import { useSubscription } from '@apollo/client';
|
||||
import { themelite as theme } from '@vegaprotocol/tailwindcss-config';
|
||||
@ -12,6 +12,7 @@ import { CANDLE_SUB } from './data-provider';
|
||||
interface Props {
|
||||
candles: (SimpleMarkets_markets_candles | null)[] | null;
|
||||
marketId: string;
|
||||
setValue: (arg: unknown) => void;
|
||||
}
|
||||
|
||||
const getChange = (
|
||||
@ -51,20 +52,32 @@ const SimpleMarketPercentChangeWrapper = (props: Props) => {
|
||||
|
||||
return (
|
||||
// @ts-ignore falsy wrong type?
|
||||
<InView onChange={setInView}>
|
||||
<InView
|
||||
onChange={setInView}
|
||||
className="flex h-full items-center justify-center"
|
||||
>
|
||||
{inView && <SimpleMarketPercentChange {...props} />}
|
||||
</InView>
|
||||
);
|
||||
};
|
||||
|
||||
const SimpleMarketPercentChange = ({ candles, marketId }: Props) => {
|
||||
const SimpleMarketPercentChange = ({ candles, marketId, setValue }: Props) => {
|
||||
const { data: { candles: { close = undefined } = {} } = {} } =
|
||||
useSubscription<CandleLive, CandleLiveVariables>(CANDLE_SUB, {
|
||||
variables: { marketId },
|
||||
});
|
||||
const change = getChange(candles, close);
|
||||
const color = getColor(change);
|
||||
return <p style={{ color }}>{change}</p>;
|
||||
useEffect(() => {
|
||||
const value = parseFloat(change);
|
||||
setValue(isNaN(value) ? '-' : value);
|
||||
}, [setValue, change]);
|
||||
|
||||
return (
|
||||
<div className="flex text-center" style={{ color }}>
|
||||
{change}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SimpleMarketPercentChangeWrapper;
|
||||
|
@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
||||
import SimpleMarketExpires from './simple-market-expires';
|
||||
|
||||
interface Props {
|
||||
data: SimpleMarkets_markets;
|
||||
}
|
||||
|
||||
const MarketNameRenderer = ({ data }: Props) => {
|
||||
return (
|
||||
<div className="flex h-full items-center grid grid-rows-2 grid-flow-col gap-x-8 gap-y-0 grid-cols-[min-content,1fr,1fr]">
|
||||
<div className="w-60 row-span-2 bg-pink rounded-full w-44 h-44 bg-gradient-to-br from-white-60 to--white-80 opacity-30" />
|
||||
<div className="col-span-2 uppercase justify-start text-black dark:text-white text-market self-end">
|
||||
{data.name}{' '}
|
||||
<SimpleMarketExpires
|
||||
tags={data.tradableInstrument.instrument.metadata.tags}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-2 ui-small text-deemphasise dark:text-midGrey self-start leading-3">
|
||||
{data.tradableInstrument.instrument.product.quoteName}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MarketNameRenderer;
|
@ -67,7 +67,7 @@ const SimpleMarketToolbar = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="w-max mb-16 font-alpha">
|
||||
<div className="w-max mb-32 font-alpha">
|
||||
<ul
|
||||
ref={slideContRef}
|
||||
className="grid grid-flow-col auto-cols-min gap-8 relative pb-4 mb-16"
|
||||
@ -162,7 +162,7 @@ const SimpleMarketToolbar = () => {
|
||||
</div>
|
||||
{activeNumber > 0 && (
|
||||
<ul
|
||||
className="grid grid-flow-col auto-cols-min md:gap-16 sm:gap-12 pb-4 md:ml-16"
|
||||
className="grid grid-flow-col auto-cols-min md:gap-16 gap-12 pb-4 md:ml-16"
|
||||
data-testid="market-assets-menu"
|
||||
aria-label={t('Asset on the market')}
|
||||
>
|
||||
|
125
apps/simple-trading-app/src/app/hooks/use-column-definitions.tsx
Normal file
125
apps/simple-trading-app/src/app/hooks/use-column-definitions.tsx
Normal file
@ -0,0 +1,125 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import type { SimpleMarkets_markets } from '../components/simple-market-list/__generated__/SimpleMarkets';
|
||||
import MarketNameRenderer from '../components/simple-market-list/simple-market-renderer';
|
||||
import SimpleMarketPercentChange from '../components/simple-market-list/simple-market-percent-change';
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ValueSetterParams } from 'ag-grid-community';
|
||||
import type { SimpleMarketsType } from '../components/simple-market-list/simple-market-list';
|
||||
|
||||
interface Props {
|
||||
onClick: (marketId: string) => void;
|
||||
}
|
||||
|
||||
const useColumnDefinitions = ({ onClick }: Props) => {
|
||||
const columnDefs = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
colId: 'market',
|
||||
headerName: t('Markets'),
|
||||
headerClass: 'uppercase',
|
||||
minWidth: 300,
|
||||
field: 'name',
|
||||
cellRenderer: ({ data }: { data: SimpleMarketsType }) => (
|
||||
<MarketNameRenderer data={data} />
|
||||
),
|
||||
},
|
||||
{
|
||||
colId: 'asset',
|
||||
headerName: t('Settlement asset'),
|
||||
headerClass: 'uppercase',
|
||||
minWidth: 100,
|
||||
cellClass: 'uppercase flex h-full items-center',
|
||||
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
||||
cellRenderer: ({ data }: { data: SimpleMarketsType }) => (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
{data.tradableInstrument.instrument.product.settlementAsset.symbol}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
colId: 'change',
|
||||
headerName: t('24h change'),
|
||||
headerClass: 'uppercase',
|
||||
field: 'percentChange',
|
||||
minWidth: 100,
|
||||
valueSetter: (params: ValueSetterParams): boolean => {
|
||||
const { oldValue, newValue, api, data } = params;
|
||||
if (oldValue !== newValue) {
|
||||
const newdata = { percentChange: newValue, ...data };
|
||||
api.applyTransaction({ update: [newdata] });
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
cellRenderer: ({
|
||||
data,
|
||||
setValue,
|
||||
}: {
|
||||
data: SimpleMarketsType;
|
||||
setValue: (arg: unknown) => void;
|
||||
}) => (
|
||||
<SimpleMarketPercentChange
|
||||
candles={data.candles}
|
||||
marketId={data.id}
|
||||
setValue={setValue}
|
||||
/>
|
||||
),
|
||||
comparator: (valueA: number | '-', valueB: number | '-') => {
|
||||
if (valueA === valueB) return 0;
|
||||
if (valueA === '-') {
|
||||
return -1;
|
||||
}
|
||||
if (valueB === '-') {
|
||||
return 1;
|
||||
}
|
||||
return valueA > valueB ? 1 : -1;
|
||||
},
|
||||
},
|
||||
{
|
||||
colId: 'status',
|
||||
headerName: t('Status'),
|
||||
field: 'data.market.state',
|
||||
headerClass: 'uppercase',
|
||||
minWidth: 100,
|
||||
cellRenderer: ({ data }: { data: SimpleMarkets_markets }) => (
|
||||
<div className="uppercase flex h-full items-center justify-center">
|
||||
<div className="border text-center px-8">
|
||||
{data.data?.market.state}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
colId: 'trade',
|
||||
headerName: '',
|
||||
headerClass: 'uppercase',
|
||||
sortable: false,
|
||||
minWidth: 100,
|
||||
cellRenderer: ({ data }: { data: SimpleMarkets_markets }) => (
|
||||
<div className="h-full flex h-full items-center justify-end">
|
||||
<Button
|
||||
onClick={() => onClick(data.id)}
|
||||
variant="inline-link"
|
||||
appendIconName="arrow-top-right"
|
||||
className="uppercase no-underline hover:no-underline"
|
||||
>
|
||||
{t('Trade')}
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
}, [onClick]);
|
||||
|
||||
const defaultColDef = useMemo(() => {
|
||||
return {
|
||||
sortable: true,
|
||||
unSortIcon: true,
|
||||
};
|
||||
}, []);
|
||||
|
||||
return { columnDefs, defaultColDef };
|
||||
};
|
||||
|
||||
export default useColumnDefinitions;
|
@ -38,7 +38,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "129999.45",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "124661.013711767544930765",
|
||||
"locked_amount": "123949.3351449367653555",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129999.45",
|
||||
@ -488,7 +488,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "97499.58",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "65503.04337545080622283",
|
||||
"locked_amount": "64804.952997247079204604",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "97499.58",
|
||||
@ -521,7 +521,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "135173.4239508",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "89531.35166557213976323285608",
|
||||
"locked_amount": "88577.18263884362270361639432",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "135173.4239508",
|
||||
@ -554,7 +554,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "32499.86",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "27555.99917099787937361",
|
||||
"locked_amount": "27262.324604263582721104",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "32499.86",
|
||||
@ -587,7 +587,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "10833.29",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "8969.210333073256934278",
|
||||
"locked_amount": "8873.622111351784071168",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10833.29",
|
||||
@ -675,7 +675,7 @@
|
||||
"tranche_end": "2022-11-01T00:00:00.000Z",
|
||||
"total_added": "22500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "15468.3027626811615",
|
||||
"locked_amount": "15101.45352128623275",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "15000",
|
||||
@ -761,7 +761,7 @@
|
||||
"tranche_end": "2023-06-02T00:00:00.000Z",
|
||||
"total_added": "1939928.38",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1804379.69836047439128314",
|
||||
"locked_amount": "1788435.020023831121162896",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1852091.69",
|
||||
@ -1777,7 +1777,7 @@
|
||||
"tranche_end": "2022-09-30T00:00:00.000Z",
|
||||
"total_added": "60916.66666633337",
|
||||
"total_removed": "18705.279504739679372649",
|
||||
"locked_amount": "14760.0056484630890178248654459722",
|
||||
"locked_amount": "14291.414097045104884895635487211",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2833.333333",
|
||||
@ -5226,9 +5226,9 @@
|
||||
"tranche_id": 11,
|
||||
"tranche_start": "2021-09-03T00:00:00.000Z",
|
||||
"tranche_end": "2022-09-03T00:00:00.000Z",
|
||||
"total_added": "19455.000000000000000003",
|
||||
"total_added": "19457.000000000000000003",
|
||||
"total_removed": "5056.88782409978",
|
||||
"locked_amount": "3597.64752092846370375055476445966514475",
|
||||
"locked_amount": "3438.09619897894364166053010683028919314",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "75",
|
||||
@ -5260,6 +5260,11 @@
|
||||
"user": "0x3a380f7CFdEeb723228cA57d2795EA215094000d",
|
||||
"tx": "0x72adba1aa2d918148f1a95eb6a447da22fa06217cadafa94d56f12fd22a389be"
|
||||
},
|
||||
{
|
||||
"amount": "2",
|
||||
"user": "0xB2BddeEb907797F9be51E3f9f75824f83cD71B67",
|
||||
"tx": "0x09792a45790c762f046f34979cbbe7687661ce7643da9ba6bc9c128710191b46"
|
||||
},
|
||||
{
|
||||
"amount": "30",
|
||||
"user": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f",
|
||||
@ -8669,6 +8674,21 @@
|
||||
"withdrawn_tokens": "940.30940496195",
|
||||
"remaining_tokens": "649.69059503805"
|
||||
},
|
||||
{
|
||||
"address": "0xB2BddeEb907797F9be51E3f9f75824f83cD71B67",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2",
|
||||
"user": "0xB2BddeEb907797F9be51E3f9f75824f83cD71B67",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x09792a45790c762f046f34979cbbe7687661ce7643da9ba6bc9c128710191b46"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "2",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "2"
|
||||
},
|
||||
{
|
||||
"address": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f",
|
||||
"deposits": [
|
||||
@ -14123,7 +14143,7 @@
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "3732368.4671",
|
||||
"total_removed": "74162.9780761646031",
|
||||
"locked_amount": "2797204.7028220379638062054",
|
||||
"locked_amount": "2772703.2835660003368440463",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1998.95815",
|
||||
@ -14835,8 +14855,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "15788853.065470999700000001",
|
||||
"total_removed": "7926.7627792759659",
|
||||
"locked_amount": "15140482.7365636033722263648641426217383077",
|
||||
"total_removed": "8977.81072959055965",
|
||||
"locked_amount": "15054047.07609322321427388182456345806299",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "16249.93",
|
||||
@ -15360,6 +15380,26 @@
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xa79f7f3e6436a1f473f3beab9e0a5c8bc4f52b38ac7aedb8610a1a9a9c4a786c"
|
||||
},
|
||||
{
|
||||
"amount": "180.278846094717375",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xca332ec8365253d3b17445c182d287e56783ab4552f3581f3a43dc6334fbfc7b"
|
||||
},
|
||||
{
|
||||
"amount": "173.18268014001675",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x793dabbba22d3e8e88f7600162ee6456d6d1b58e49ce07209d3f97eaa485161f"
|
||||
},
|
||||
{
|
||||
"amount": "368.40753967648125",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x959378e42a224a7cff0dde794e80a0f07cbbe6b61e9158092a037efaa726aa28"
|
||||
},
|
||||
{
|
||||
"amount": "329.178884403378375",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x57a5f040ac80c34cc5c90c2cf939c21fa2ef872042998703d69995c71184ab44"
|
||||
},
|
||||
{
|
||||
"amount": "2446.31552516990115",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@ -15482,6 +15522,30 @@
|
||||
"tranche_id": 2,
|
||||
"tx": "0xa79f7f3e6436a1f473f3beab9e0a5c8bc4f52b38ac7aedb8610a1a9a9c4a786c"
|
||||
},
|
||||
{
|
||||
"amount": "180.278846094717375",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xca332ec8365253d3b17445c182d287e56783ab4552f3581f3a43dc6334fbfc7b"
|
||||
},
|
||||
{
|
||||
"amount": "173.18268014001675",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x793dabbba22d3e8e88f7600162ee6456d6d1b58e49ce07209d3f97eaa485161f"
|
||||
},
|
||||
{
|
||||
"amount": "368.40753967648125",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x959378e42a224a7cff0dde794e80a0f07cbbe6b61e9158092a037efaa726aa28"
|
||||
},
|
||||
{
|
||||
"amount": "329.178884403378375",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x57a5f040ac80c34cc5c90c2cf939c21fa2ef872042998703d69995c71184ab44"
|
||||
},
|
||||
{
|
||||
"amount": "2446.31552516990115",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@ -15526,8 +15590,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "194999.1675",
|
||||
"withdrawn_tokens": "7926.7627792759659",
|
||||
"remaining_tokens": "187072.4047207240341"
|
||||
"withdrawn_tokens": "8977.81072959055965",
|
||||
"remaining_tokens": "186021.35677040944035"
|
||||
},
|
||||
{
|
||||
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
|
||||
@ -16931,8 +16995,8 @@
|
||||
"tranche_start": "2021-11-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-05T00:00:00.000Z",
|
||||
"total_added": "14597706.0446472999",
|
||||
"total_removed": "2113641.840890679071831632",
|
||||
"locked_amount": "8328080.66510881884167481291924447",
|
||||
"total_removed": "2158746.556523576443330677",
|
||||
"locked_amount": "8247873.1795980633455589418403988",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129284.449",
|
||||
@ -17181,6 +17245,41 @@
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xc62ffa6bf5029422f44d9406972fc074b498e02f667a86ae9faba138b6cfd758"
|
||||
},
|
||||
{
|
||||
"amount": "331.7071722886032605",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xc279c1a171709ff76a9875fea2e8f98ceb5797714ead511ba95a12f61412fc13"
|
||||
},
|
||||
{
|
||||
"amount": "321.15600624174480075",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x7289f6af545a72235c26ecd98b8a0c14fbb5e62af98ded20862cfad2ef59d3bc"
|
||||
},
|
||||
{
|
||||
"amount": "679.7663781595895195",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x4cef72f21dd9cf51cb6fbc965bc0b514b9c2ea4e2d9ca62f19c5a5defc6eef60"
|
||||
},
|
||||
{
|
||||
"amount": "614.746506577953841",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x4ef5e959da18a286e010bc26fdc2bdda73f3e612334b232cb3e4af4c8c3d018d"
|
||||
},
|
||||
{
|
||||
"amount": "17701.463096745440206695",
|
||||
"user": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
|
||||
"tx": "0x8ff111c8ad92e1fa74add7edaadb2a7fd781d6d50e43c17d8042b32054c2a210"
|
||||
},
|
||||
{
|
||||
"amount": "20364.3503859717532968",
|
||||
"user": "0x47FbE34Fd93416c63d35544dEE6c6f442Db8513d",
|
||||
"tx": "0x0327fb136e8b6a56b8ed65d6f5e7c729455a2b3d3684fc22c92cedcce5c00fc5"
|
||||
},
|
||||
{
|
||||
"amount": "5091.5260869122865738",
|
||||
"user": "0xcc2cf726A84e71301f9079FC177BA946aa98A694",
|
||||
"tx": "0x1f9f8184e28b9dabb8878b08ea6e50c93b7f18a724b1070a62c0223f12256339"
|
||||
},
|
||||
{
|
||||
"amount": "652.48254356494551875",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@ -18799,6 +18898,30 @@
|
||||
"tranche_id": 3,
|
||||
"tx": "0xc62ffa6bf5029422f44d9406972fc074b498e02f667a86ae9faba138b6cfd758"
|
||||
},
|
||||
{
|
||||
"amount": "331.7071722886032605",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xc279c1a171709ff76a9875fea2e8f98ceb5797714ead511ba95a12f61412fc13"
|
||||
},
|
||||
{
|
||||
"amount": "321.15600624174480075",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x7289f6af545a72235c26ecd98b8a0c14fbb5e62af98ded20862cfad2ef59d3bc"
|
||||
},
|
||||
{
|
||||
"amount": "679.7663781595895195",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x4cef72f21dd9cf51cb6fbc965bc0b514b9c2ea4e2d9ca62f19c5a5defc6eef60"
|
||||
},
|
||||
{
|
||||
"amount": "614.746506577953841",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x4ef5e959da18a286e010bc26fdc2bdda73f3e612334b232cb3e4af4c8c3d018d"
|
||||
},
|
||||
{
|
||||
"amount": "652.48254356494551875",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@ -20037,8 +20160,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "359123.469575",
|
||||
"withdrawn_tokens": "154092.9757912160630365",
|
||||
"remaining_tokens": "205030.4937837839369635"
|
||||
"withdrawn_tokens": "156040.35185448395445825",
|
||||
"remaining_tokens": "203083.11772051604554175"
|
||||
},
|
||||
{
|
||||
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
|
||||
@ -20185,6 +20308,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "5091.5260869122865738",
|
||||
"user": "0xcc2cf726A84e71301f9079FC177BA946aa98A694",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x1f9f8184e28b9dabb8878b08ea6e50c93b7f18a724b1070a62c0223f12256339"
|
||||
},
|
||||
{
|
||||
"amount": "6310.1901227904940866",
|
||||
"user": "0xcc2cf726A84e71301f9079FC177BA946aa98A694",
|
||||
@ -20211,8 +20340,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "66299.71746",
|
||||
"withdrawn_tokens": "23745.761900811119424",
|
||||
"remaining_tokens": "42553.955559188880576"
|
||||
"withdrawn_tokens": "28837.2879877234059978",
|
||||
"remaining_tokens": "37462.4294722765940022"
|
||||
},
|
||||
{
|
||||
"address": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
|
||||
@ -20529,6 +20658,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "20364.3503859717532968",
|
||||
"user": "0x47FbE34Fd93416c63d35544dEE6c6f442Db8513d",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x0327fb136e8b6a56b8ed65d6f5e7c729455a2b3d3684fc22c92cedcce5c00fc5"
|
||||
},
|
||||
{
|
||||
"amount": "25242.3008271937471296",
|
||||
"user": "0x47FbE34Fd93416c63d35544dEE6c6f442Db8513d",
|
||||
@ -20555,8 +20690,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "265198.86984",
|
||||
"withdrawn_tokens": "94983.1600369573350624",
|
||||
"remaining_tokens": "170215.7098030426649376"
|
||||
"withdrawn_tokens": "115347.5104229290883592",
|
||||
"remaining_tokens": "149851.3594170709116408"
|
||||
},
|
||||
{
|
||||
"address": "0x35022e6c85B50F4904C7BC7e692A9F3bbEE8D2CE",
|
||||
@ -20726,6 +20861,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "17701.463096745440206695",
|
||||
"user": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x8ff111c8ad92e1fa74add7edaadb2a7fd781d6d50e43c17d8042b32054c2a210"
|
||||
},
|
||||
{
|
||||
"amount": "45513.77740810577941926",
|
||||
"user": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
|
||||
@ -20746,8 +20887,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "230391.5181735",
|
||||
"withdrawn_tokens": "82506.25192192818881679",
|
||||
"remaining_tokens": "147885.26625157181118321"
|
||||
"withdrawn_tokens": "100207.715018673629023485",
|
||||
"remaining_tokens": "130183.803154826370976515"
|
||||
},
|
||||
{
|
||||
"address": "0xC6b2864fbCD2A8dEC8DEfD1D421bC1E450C370AD",
|
||||
@ -21034,8 +21175,8 @@
|
||||
"tranche_start": "2021-10-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "5778205.3912159303",
|
||||
"total_removed": "1390546.591547348229906227",
|
||||
"locked_amount": "2973571.63505682836710488797665665",
|
||||
"total_removed": "1417003.438054406291892727",
|
||||
"locked_amount": "2941881.17244069509858904234270872",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "552496.6455",
|
||||
@ -21184,6 +21325,21 @@
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
"tx": "0xa6b9993b9288eac739756499b2997155ce8b1bc6e862c1a6569c8e04463bb31f"
|
||||
},
|
||||
{
|
||||
"amount": "3635.564694620199747",
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
"tx": "0x89b7e9f6200ba171c5f1115f9fd110284ef4ffaba58cf174b686bbe4905fe18a"
|
||||
},
|
||||
{
|
||||
"amount": "10109.350358551032104",
|
||||
"user": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75",
|
||||
"tx": "0xc695996be3df837d7040aec8c5532965ac6554d5615575ee46fc87d604e2ebc0"
|
||||
},
|
||||
{
|
||||
"amount": "12711.9314538868301355",
|
||||
"user": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
|
||||
"tx": "0x68b69c1a3ebd9666638809539b4d8ced5b1ab8fe19c720dfffdc548b378513d3"
|
||||
},
|
||||
{
|
||||
"amount": "13341.31568777778021",
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
@ -21552,6 +21708,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "12711.9314538868301355",
|
||||
"user": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
|
||||
"tranche_id": 4,
|
||||
"tx": "0x68b69c1a3ebd9666638809539b4d8ced5b1ab8fe19c720dfffdc548b378513d3"
|
||||
},
|
||||
{
|
||||
"amount": "32683.576612762644585",
|
||||
"user": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
|
||||
@ -21572,8 +21734,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "165749.29365",
|
||||
"withdrawn_tokens": "68641.624849504055385",
|
||||
"remaining_tokens": "97107.668800495944615"
|
||||
"withdrawn_tokens": "81353.5563033908855205",
|
||||
"remaining_tokens": "84395.7373466091144795"
|
||||
},
|
||||
{
|
||||
"address": "0x72e7BB93E73b2885a22CA29c34759361399a5C0e",
|
||||
@ -21666,6 +21828,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "10109.350358551032104",
|
||||
"user": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75",
|
||||
"tranche_id": 4,
|
||||
"tx": "0xc695996be3df837d7040aec8c5532965ac6554d5615575ee46fc87d604e2ebc0"
|
||||
},
|
||||
{
|
||||
"amount": "7013.412182841867109",
|
||||
"user": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75",
|
||||
@ -21722,8 +21890,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "110499.5291",
|
||||
"withdrawn_tokens": "43654.936134887817154",
|
||||
"remaining_tokens": "66844.592965112182846"
|
||||
"withdrawn_tokens": "53764.286493438849258",
|
||||
"remaining_tokens": "56735.242606561150742"
|
||||
},
|
||||
{
|
||||
"address": "0xdbC5d439F373EB646345e1c67D1d46231ACE7dD3",
|
||||
@ -22018,6 +22186,12 @@
|
||||
"tranche_id": 4,
|
||||
"tx": "0xa6b9993b9288eac739756499b2997155ce8b1bc6e862c1a6569c8e04463bb31f"
|
||||
},
|
||||
{
|
||||
"amount": "3635.564694620199747",
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
"tranche_id": 4,
|
||||
"tx": "0x89b7e9f6200ba171c5f1115f9fd110284ef4ffaba58cf174b686bbe4905fe18a"
|
||||
},
|
||||
{
|
||||
"amount": "13341.31568777778021",
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
@ -22080,8 +22254,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "331498.5873",
|
||||
"withdrawn_tokens": "157304.28913691490831",
|
||||
"remaining_tokens": "174194.29816308509169"
|
||||
"withdrawn_tokens": "160939.853831535108057",
|
||||
"remaining_tokens": "170558.733468464891943"
|
||||
},
|
||||
{
|
||||
"address": "0x16da609341ed67750A8BCC5AAa2005471006Cd77",
|
||||
@ -22157,8 +22331,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "472355.6199999996",
|
||||
"total_removed": "34.173053016",
|
||||
"locked_amount": "443233.07466590775804275636428212",
|
||||
"total_removed": "75.634316334",
|
||||
"locked_amount": "439350.6847287052296870462810756",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "3000",
|
||||
@ -28786,6 +28960,11 @@
|
||||
"amount": "23.010020292",
|
||||
"user": "0xD27929d68ac0E5fd5C919A5eb5968C1D06D3Fb83",
|
||||
"tx": "0x8daf320262d0384cf5f9c290cc33721587beabd5e93026b3e9b76dc3fcd6659c"
|
||||
},
|
||||
{
|
||||
"amount": "41.461263318",
|
||||
"user": "0x6EfF23b65688CaE71Af19128A7674b7Dd53f7f19",
|
||||
"tx": "0x16a1ae4e6602247b005985fff7824f896a344caa9b6be09f4eacd3df840fa36c"
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
@ -43700,10 +43879,17 @@
|
||||
"tx": "0xd23813c30e93f3867eaa257b7aef7052a050b1ee1c1a90102a3f40c5d989fe82"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "41.461263318",
|
||||
"user": "0x6EfF23b65688CaE71Af19128A7674b7Dd53f7f19",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x16a1ae4e6602247b005985fff7824f896a344caa9b6be09f4eacd3df840fa36c"
|
||||
}
|
||||
],
|
||||
"total_tokens": "600",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "600"
|
||||
"withdrawn_tokens": "41.461263318",
|
||||
"remaining_tokens": "558.538736682"
|
||||
},
|
||||
{
|
||||
"address": "0xa37d20cd446898508Ab961c6Be8d3fe1c15413fA",
|
||||
@ -47836,7 +48022,7 @@
|
||||
"tranche_start": "2021-12-05T00:00:00.000Z",
|
||||
"tranche_end": "2022-06-05T00:00:00.000Z",
|
||||
"total_added": "171288.42",
|
||||
"total_removed": "32094.1716569431377",
|
||||
"total_removed": "32535.6624708206377",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@ -52136,6 +52322,26 @@
|
||||
"user": "0xDD5730a33719083470e641cF0e4154Dd04D5738d",
|
||||
"tx": "0x49bd6332008e65069aad8012f76f15f3dae19f664237b02f9152946297db812d"
|
||||
},
|
||||
{
|
||||
"amount": "101.100697625",
|
||||
"user": "0x6886CA9FfE30C5BB86590c71799Bf5550EDF845b",
|
||||
"tx": "0x204f08eb22345e352efcbfd3921f813fdf1097ea3fc33b36387c3c1cc5678936"
|
||||
},
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0xbCc28D073f7a96c0568D36FdB21A98105ee60Ca3",
|
||||
"tx": "0xf1201851e334cac5ab0920f89874163c5074c608b8d810b5eb89fb62454ddc19"
|
||||
},
|
||||
{
|
||||
"amount": "63.3869111225",
|
||||
"user": "0x002dA530f8691f012Cecf0ba859Dd5dFa7d9871D",
|
||||
"tx": "0x901a76735076a5058146ce6fc79628d78d71e8d2b3161459c2daf64ae043f1d5"
|
||||
},
|
||||
{
|
||||
"amount": "27.00320513",
|
||||
"user": "0x2fCBC94236FeF3e5173a7ec27a25925cd2304540",
|
||||
"tx": "0xf44b015cc0a7f3c369d48e8c9b71985ad5280c709fd7d541c4d3194dac79482d"
|
||||
},
|
||||
{
|
||||
"amount": "183.6335597275",
|
||||
"user": "0x690Fc36d52eD3f198F0eBDea1557333a1766f786",
|
||||
@ -53517,6 +53723,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "101.100697625",
|
||||
"user": "0x6886CA9FfE30C5BB86590c71799Bf5550EDF845b",
|
||||
"tranche_id": 6,
|
||||
"tx": "0x204f08eb22345e352efcbfd3921f813fdf1097ea3fc33b36387c3c1cc5678936"
|
||||
},
|
||||
{
|
||||
"amount": "148.899302375",
|
||||
"user": "0x6886CA9FfE30C5BB86590c71799Bf5550EDF845b",
|
||||
@ -53525,8 +53737,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "250",
|
||||
"withdrawn_tokens": "148.899302375",
|
||||
"remaining_tokens": "101.100697625"
|
||||
"withdrawn_tokens": "250",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0xDFdC0c291ee8499777272ab3A7B786518c895966",
|
||||
@ -56458,6 +56670,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "63.3869111225",
|
||||
"user": "0x002dA530f8691f012Cecf0ba859Dd5dFa7d9871D",
|
||||
"tranche_id": 6,
|
||||
"tx": "0x901a76735076a5058146ce6fc79628d78d71e8d2b3161459c2daf64ae043f1d5"
|
||||
},
|
||||
{
|
||||
"amount": "186.6130888775",
|
||||
"user": "0x002dA530f8691f012Cecf0ba859Dd5dFa7d9871D",
|
||||
@ -56466,8 +56684,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "250",
|
||||
"withdrawn_tokens": "186.6130888775",
|
||||
"remaining_tokens": "63.3869111225"
|
||||
"withdrawn_tokens": "250",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0xDE321bC0E688C3cfda2D07f4BE1B7D4fB019cc91",
|
||||
@ -64583,6 +64801,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "27.00320513",
|
||||
"user": "0x2fCBC94236FeF3e5173a7ec27a25925cd2304540",
|
||||
"tranche_id": 6,
|
||||
"tx": "0xf44b015cc0a7f3c369d48e8c9b71985ad5280c709fd7d541c4d3194dac79482d"
|
||||
},
|
||||
{
|
||||
"amount": "129.597196785",
|
||||
"user": "0x2fCBC94236FeF3e5173a7ec27a25925cd2304540",
|
||||
@ -64603,8 +64827,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "500",
|
||||
"withdrawn_tokens": "472.99679487",
|
||||
"remaining_tokens": "27.00320513"
|
||||
"withdrawn_tokens": "500",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x45564345F125F78d3C3894A2C5226C673F8eB0Ae",
|
||||
@ -65762,10 +65986,17 @@
|
||||
"tx": "0xc8541da6a57f410b6faba47a5e5184bae700193b7bd042914fffc562114d92f5"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0xbCc28D073f7a96c0568D36FdB21A98105ee60Ca3",
|
||||
"tranche_id": 6,
|
||||
"tx": "0xf1201851e334cac5ab0920f89874163c5074c608b8d810b5eb89fb62454ddc19"
|
||||
}
|
||||
],
|
||||
"total_tokens": "250",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "250"
|
||||
"withdrawn_tokens": "250",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x8c951C54F9cd08Cf81F770248e835D7A4F491a46",
|
||||
|
@ -38,7 +38,7 @@
|
||||
"tranche_end": "2022-11-26T13:48:10.000Z",
|
||||
"total_added": "100",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "41.663429096905125",
|
||||
"locked_amount": "40.84151128868595",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "100",
|
||||
@ -242,7 +242,7 @@
|
||||
"tranche_end": "2022-10-12T00:53:20.000Z",
|
||||
"total_added": "1100",
|
||||
"total_removed": "673.04388635",
|
||||
"locked_amount": "321.05967465753423",
|
||||
"locked_amount": "312.01857876712325",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1000",
|
||||
|
@ -69,7 +69,7 @@
|
||||
"tranche_end": "2022-10-12T00:53:20.000Z",
|
||||
"total_added": "1010.000000000000000001",
|
||||
"total_removed": "668.4622323651",
|
||||
"locked_amount": "294.7911558219177930002918724315068493",
|
||||
"locked_amount": "286.4897859589040750002836532534246575",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1000",
|
||||
|
18
apps/stats-e2e/cypress.config.js
Normal file
18
apps/stats-e2e/cypress.config.js
Normal file
@ -0,0 +1,18 @@
|
||||
const { defineConfig } = require('cypress');
|
||||
module.exports = defineConfig({
|
||||
projectId: 'et4snf',
|
||||
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:3010',
|
||||
fileServerFolder: '.',
|
||||
fixturesFolder: false,
|
||||
specPattern: './src/integration/*.ts',
|
||||
excludeSpecPattern: '**/*.js',
|
||||
modifyObstructiveCode: false,
|
||||
supportFile: './src/support/index.ts',
|
||||
video: true,
|
||||
videosFolder: '../../dist/cypress/apps/explorer-e2e/videos',
|
||||
screenshotsFolder: '../../dist/cypress/apps/explorer-e2e/screenshots',
|
||||
chromeWebSecurity: false,
|
||||
},
|
||||
});
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:3010",
|
||||
"projectId": "et4snf",
|
||||
"fileServerFolder": ".",
|
||||
"fixturesFolder": "./src/fixtures",
|
||||
"integrationFolder": "./src/integration",
|
||||
"modifyObstructiveCode": false,
|
||||
"supportFile": "./src/support/index.ts",
|
||||
"pluginsFile": false,
|
||||
"video": true,
|
||||
"videosFolder": "../../dist/cypress/apps/stats-e2e/videos",
|
||||
"screenshotsFolder": "../../dist/cypress/apps/stats-e2e/screenshots",
|
||||
"chromeWebSecurity": false
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"e2e": {
|
||||
"executor": "@nrwl/cypress:cypress",
|
||||
"options": {
|
||||
"cypressConfig": "apps/stats-e2e/cypress.json",
|
||||
"cypressConfig": "apps/stats-e2e/cypress.config.js",
|
||||
"devServerTarget": "stats:serve"
|
||||
},
|
||||
"configurations": {
|
||||
|
17
apps/token-e2e/cypress.config.js
Normal file
17
apps/token-e2e/cypress.config.js
Normal file
@ -0,0 +1,17 @@
|
||||
const { defineConfig } = require('cypress');
|
||||
module.exports = defineConfig({
|
||||
projectId: 'et4snf',
|
||||
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:4210',
|
||||
fileServerFolder: '.',
|
||||
fixturesFolder: false,
|
||||
specPattern: '**/*.cy.{js,jsx,ts,tsx}',
|
||||
modifyObstructiveCode: false,
|
||||
supportFile: './src/support/index.ts',
|
||||
video: true,
|
||||
videosFolder: '../../dist/cypress/apps/explorer-e2e/videos',
|
||||
screenshotsFolder: '../../dist/cypress/apps/explorer-e2e/screenshots',
|
||||
chromeWebSecurity: false,
|
||||
},
|
||||
});
|
@ -1,20 +0,0 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:4210",
|
||||
"projectId": "et4snf",
|
||||
"fileServerFolder": ".",
|
||||
"fixturesFolder": "./src/fixtures",
|
||||
"integrationFolder": "./src/integration",
|
||||
"modifyObstructiveCode": false,
|
||||
"supportFile": "./src/support/index.ts",
|
||||
"pluginsFile": false,
|
||||
"video": true,
|
||||
"videosFolder": "../../dist/cypress/apps/token-e2e/videos",
|
||||
"screenshotsFolder": "../../dist/cypress/apps/token-e2e/screenshots",
|
||||
"chromeWebSecurity": false,
|
||||
"env": {
|
||||
"ETH_WALLET_MNEMONIC": "ugly gallery notice network true range brave clarify flat logic someone chunk",
|
||||
"VEGA_WALLET_NAME" : "capsule_wallet",
|
||||
"VEGA_WALLET_LOCATION" : "~/.vegacapsule/testnet/wallet",
|
||||
"VEGA_WALLET_PASSPHRASE" : "123"
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"e2e": {
|
||||
"executor": "@nrwl/cypress:cypress",
|
||||
"options": {
|
||||
"cypressConfig": "apps/token-e2e/cypress.json",
|
||||
"cypressConfig": "apps/token-e2e/cypress.config.js",
|
||||
"devServerTarget": "token:serve"
|
||||
},
|
||||
"configurations": {
|
||||
|
12
apps/token-e2e/src/integration/app.cy.ts
Normal file
12
apps/token-e2e/src/integration/app.cy.ts
Normal file
@ -0,0 +1,12 @@
|
||||
const fairgroundSet = Cypress.env('FAIRGROUND');
|
||||
|
||||
describe('token', () => {
|
||||
beforeEach(() => cy.visit('/'));
|
||||
|
||||
it('should always have a header title based on environment', () => {
|
||||
cy.get('[data-testid="header-title"]', { timeout: 8000 }).should(
|
||||
'have.text',
|
||||
`${fairgroundSet ? 'Fairground token' : 'VEGA TOKEN'}`
|
||||
);
|
||||
});
|
||||
});
|
@ -1,6 +1,7 @@
|
||||
import navigation from '../../locators/navigation.locators';
|
||||
import home from '../../locators/home.locators';
|
||||
import vegaToken from '../../fixtures/vegaToken.json';
|
||||
|
||||
import navigation from '../locators/navigation.locators';
|
||||
import home from '../locators/home.locators';
|
||||
import vegaToken from '../fixtures/vegaToken.json';
|
||||
|
||||
context('Home Page - verify elements on page', function () {
|
||||
before('visit token home page', function () {
|
34
apps/token-e2e/src/integration/vesting.cy.js
Normal file
34
apps/token-e2e/src/integration/vesting.cy.js
Normal file
@ -0,0 +1,34 @@
|
||||
import navigation from '../locators/navigation.locators';
|
||||
import vesting from '../locators/vesting.locators';
|
||||
|
||||
context('Vesting Page - verify elements on page', function () {
|
||||
before('navigate to vesting page', function () {
|
||||
cy.visit('/')
|
||||
.get(navigation.section)
|
||||
.within(() => {
|
||||
cy.get(navigation.vesting).click();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with wallets disconnected', function () {
|
||||
it('should have vesting tab highlighted', function () {
|
||||
cy.get(navigation.section).within(() => {
|
||||
cy.get(navigation.vesting).should('have.attr', 'aria-current');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have VESTING header visible', function () {
|
||||
cy.get(vesting.header).should('be.visible').and('have.text', 'Vesting');
|
||||
});
|
||||
|
||||
it('should have connect Eth wallet info', function () {
|
||||
cy.get(vesting.connectPrompt).should('be.visible');
|
||||
});
|
||||
|
||||
it('should have connect Eth wallet button', function () {
|
||||
cy.get(vesting.connectButton)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect Ethereum wallet');
|
||||
});
|
||||
});
|
||||
});
|
5
apps/token-e2e/src/locators/vesting.locators.js
Normal file
5
apps/token-e2e/src/locators/vesting.locators.js
Normal file
@ -0,0 +1,5 @@
|
||||
export default {
|
||||
header: 'header h1',
|
||||
connectPrompt: '[data-testid="eth-connect-prompt"]',
|
||||
connectButton: '[data-testid="connect-to-eth-btn"]',
|
||||
};
|
@ -7,7 +7,7 @@ import { ENV } from '../../config/env';
|
||||
export const AppFooter = () => {
|
||||
return (
|
||||
<footer className="p-12 text-ui">
|
||||
<p className="mb-8">Version: {ENV.commit || 'development'}</p>
|
||||
<p>Version: {ENV.commit || 'development'}</p>
|
||||
<p>
|
||||
<Trans
|
||||
i18nKey="footerLinksText"
|
||||
|
@ -9,7 +9,10 @@ interface BulletHeaderProps {
|
||||
export const BulletHeader = ({ tag, children, style }: BulletHeaderProps) => {
|
||||
return React.createElement(
|
||||
tag,
|
||||
{ className: 'mt-24 pt-8 pb-20 uppercase text-white', style },
|
||||
{
|
||||
className: 'mt-24 py-8 border-t border-white uppercase text-white',
|
||||
style,
|
||||
},
|
||||
<>
|
||||
<span className="inline-block w-[12px] h-[12px] mr-12 bg-white" />
|
||||
{children}
|
||||
|
@ -9,9 +9,7 @@ export const ConnectedVegaKey = ({ pubKey }: { pubKey: string | null }) => {
|
||||
<strong data-testid="connected-vega-key-label">
|
||||
{pubKey ? t('Connected Vega key') : <ConnectToVega />}
|
||||
</strong>
|
||||
<p className="mb-12" data-testid="connected-vega-key">
|
||||
{pubKey}
|
||||
</p>
|
||||
<p data-testid="connected-vega-key">{pubKey}</p>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
@ -74,19 +74,24 @@ const AssociatedAmounts = ({
|
||||
light={false}
|
||||
/>
|
||||
{vestingAssociationByVegaKey.length ? (
|
||||
<>
|
||||
<hr style={{ borderStyle: 'dashed', color: Colors.text }} />
|
||||
<WalletCardRow label="Associated with Vega keys" bold={true} />
|
||||
<div>
|
||||
<hr style={{ borderStyle: 'dashed' }} />
|
||||
<WalletCardRow
|
||||
label="Associated with Vega keys"
|
||||
bold={true}
|
||||
dark={true}
|
||||
/>
|
||||
{vestingAssociationByVegaKey.map(([key, amount]) => {
|
||||
return (
|
||||
<WalletCardRow
|
||||
key={key}
|
||||
label={removeLeadingAddressSymbol(key)}
|
||||
value={amount}
|
||||
dark={true}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
|
@ -7,9 +7,7 @@ export const Heading = ({ title }: HeadingProps) => {
|
||||
|
||||
return (
|
||||
<header className="my-0 mx-auto">
|
||||
<h1 className="font-alpha calt text-h3 text-white uppercase mb-4">
|
||||
{title}
|
||||
</h1>
|
||||
<h1 className="font-alpha calt">{title}</h1>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
@ -1 +1 @@
|
||||
export { Heading } from './heading';
|
||||
export * from './heading';
|
||||
|
@ -14,7 +14,7 @@ const ProgressContents = ({
|
||||
children: React.ReactNode;
|
||||
}) => (
|
||||
<div
|
||||
className={classnames('flex justify-between py-2 font-mono', {
|
||||
className={classnames('flex justify-between py-2 font-mono mb-2', {
|
||||
'gap-0 px-0 text-black': light,
|
||||
'gap-y-0 gap-x-4': !light,
|
||||
})}
|
||||
@ -93,7 +93,7 @@ export const LockedProgress = ({
|
||||
}, [total, unlocked]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-8">
|
||||
<div
|
||||
className={classnames('flex border', {
|
||||
'border-black': light,
|
||||
@ -122,6 +122,6 @@ export const LockedProgress = ({
|
||||
<span>{formatNumber(locked, decimals)}</span>
|
||||
<span>{formatNumber(unlocked, decimals)}</span>
|
||||
</ProgressContents>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -5,7 +5,8 @@ import debounce from 'lodash/debounce';
|
||||
import React from 'react';
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { Link, NavLink } from 'react-router-dom';
|
||||
import vegaWhite from '../../images/vega_white.png';
|
||||
|
||||
import { Flags } from '../../config';
|
||||
import {
|
||||
@ -16,6 +17,69 @@ import { Routes } from '../../routes/router-config';
|
||||
import { EthWallet } from '../eth-wallet';
|
||||
import { VegaWallet } from '../vega-wallet';
|
||||
|
||||
const Fish = () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="33"
|
||||
height="20"
|
||||
viewBox="0 0 200 116"
|
||||
fill="none"
|
||||
data-testid="fairground-icon"
|
||||
>
|
||||
<g clipPath="url(#clip0)">
|
||||
<path
|
||||
d="M70.5918 32.8569L70.5918 22.7932L60.5254 22.7932L60.5254 32.8569L70.5918 32.8569Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M80.6641 83.2006L80.6641 73.1377L70.5977 73.1377L70.5977 83.2006L80.6641 83.2006Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M70.5918 93.2409L70.5918 83.1772L60.5254 83.1772L60.5254 93.2409L70.5918 93.2409Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M100.797 93.2636L100.797 73.1377L90.7305 73.1377L90.7305 93.2636L100.797 93.2636Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M90.7285 103.33L90.7285 93.2671L80.662 93.2671L80.662 103.33L90.7285 103.33Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M90.7285 22.8026L90.7285 12.74L80.662 12.74L80.662 22.8026L90.7285 22.8026Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M110.869 12.6108L110.869 2.54785L100.803 2.54785L100.803 12.6108L110.869 12.6108Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M120.934 103.326L120.934 73.1377L110.867 73.1377L110.867 103.326L120.934 103.326Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M110.869 113.384L110.869 103.321L100.803 103.321L100.803 113.384L110.869 113.384Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M161.328 52.9855L161.328 42.9226L151.262 42.9226L151.262 52.9855L161.328 52.9855Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M20.133 83.187L30.3354 83.187L30.3354 73.124L40.4017 73.124L40.4017 63.0613L50.4681 63.0613L50.4681 73.124L60.5345 73.124L60.5345 63.0613L70.6008 63.0613L80.6672 63.0613L131.135 63.0613L131.135 113.376L161.334 113.376L161.334 103.313L171.4 103.313L171.4 93.25L181.467 93.25L181.467 83.187L191.533 83.187L191.533 63.0613L181.467 63.0613L181.467 73.1241L171.4 73.1241L171.4 83.187L161.334 83.187L161.334 73.1241L171.4 73.1241L171.4 63.0613L161.334 63.0613L151.268 63.0613L141.201 63.0613L141.201 52.9983L141.201 32.8726L161.334 32.8726L171.4 32.8726L171.4 63.0613L181.467 63.0613L181.467 52.9983L191.533 52.9983L191.533 32.8726L181.467 32.8726L181.467 22.8096L171.4 22.8096L171.4 12.7467L161.334 12.7467L161.334 2.54785L141.201 2.54785L131.135 2.54785L131.135 52.9983L120.933 52.9983L120.933 12.7467L110.866 12.7467L110.866 52.9983L100.8 52.9983L100.8 22.8096L90.7336 22.8096L90.7336 52.9983L80.6672 52.9983L80.6672 32.8726L70.6008 32.8726L70.6008 52.9983L60.5345 52.9983L60.5345 42.9354L50.4681 42.9354L50.4681 52.9983L40.4017 52.9983L40.4017 42.9354L30.3354 42.9354L30.3354 32.8726L20.133 32.8726L20.133 22.8096L0.000308081 22.8096L0.000307201 42.9354L10.0666 42.9354L10.0666 52.9983L20.133 52.9983L20.133 63.0613L10.0666 63.0613L10.0666 73.124L0.000305881 73.124L0.000305002 93.25L20.133 93.25L20.133 83.187Z"
|
||||
fill="black"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="200" height="116" fill="none" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const Nav = () => {
|
||||
const [windowWidth, setWindowWidth] = React.useState(window.innerWidth);
|
||||
const isDesktop = windowWidth > 959;
|
||||
@ -35,7 +99,7 @@ export const Nav = () => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`p-16 ${
|
||||
className={`px-16 py-8 ${
|
||||
inverted
|
||||
? 'bg-clouds bg-no-repeat bg-cover bg-vega-yellow'
|
||||
: 'border-b-white border-b-1'
|
||||
@ -46,7 +110,7 @@ export const Nav = () => {
|
||||
{!isDesktop && <NavHeader fairground={inverted} />}
|
||||
<div className="flex gap-12 lg:flex-auto">
|
||||
{isDesktop ? (
|
||||
<NavLinks isDesktop={isDesktop} />
|
||||
<NavLinks isDesktop={isDesktop} isInverted={inverted} />
|
||||
) : (
|
||||
<NavDrawer inverted={inverted} />
|
||||
)}
|
||||
@ -60,15 +124,24 @@ const NavHeader = ({ fairground }: { fairground: boolean }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-[30px] inline-flex items-center lg:h-40 uppercase">
|
||||
<h1
|
||||
data-testid="header-title"
|
||||
className={`text-h3 font-alpha uppercase calt mb-2 ${
|
||||
fairground ? 'text-black' : 'text-white'
|
||||
}`}
|
||||
>
|
||||
{fairground ? t('fairgroundTitle') : t('title')}
|
||||
</h1>
|
||||
<div className="flex items-center gap-8">
|
||||
<Link to="/">
|
||||
{fairground ? (
|
||||
<Fish />
|
||||
) : (
|
||||
<img alt="Vega" src={vegaWhite} height={30} width={30} />
|
||||
)}
|
||||
</Link>
|
||||
<div className="h-[30px] inline-flex items-center lg:h-40 uppercase">
|
||||
<h1
|
||||
data-testid="header-title"
|
||||
className={`text-h4 sm:text-h3 font-alpha uppercase calt mb-2 ${
|
||||
fairground ? 'text-black' : 'text-white'
|
||||
}`}
|
||||
>
|
||||
{fairground ? t('fairgroundTitle') : t('title')}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -135,7 +208,13 @@ const NavDrawer = ({ inverted }: { inverted: boolean }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const NavLinks = ({ isDesktop }: { isDesktop: boolean }) => {
|
||||
const NavLinks = ({
|
||||
isDesktop,
|
||||
isInverted,
|
||||
}: {
|
||||
isDesktop: boolean;
|
||||
isInverted?: boolean;
|
||||
}) => {
|
||||
const { appDispatch } = useAppState();
|
||||
const { t } = useTranslation();
|
||||
const linkProps = {
|
||||
@ -163,18 +242,21 @@ const NavLinks = ({ isDesktop }: { isDesktop: boolean }) => {
|
||||
{...linkProps}
|
||||
to={route}
|
||||
key={route}
|
||||
className={({ isActive }) => {
|
||||
const linkClasses = classNames(
|
||||
'no-underline hover:no-underline',
|
||||
className={({ isActive }) =>
|
||||
classNames(
|
||||
'no-underline hover:no-underline focus-visible:outline-none focus-visible:border-none focus-visible:shadow-inset-white',
|
||||
{
|
||||
'bg-vega-yellow text-black hover:text-black': isActive,
|
||||
'bg-black text-white': !isActive,
|
||||
'bg-vega-yellow text-black': !isInverted && isActive,
|
||||
'bg-transparent text-white hover:text-vega-yellow':
|
||||
!isInverted && !isActive,
|
||||
'bg-black text-white': isInverted && isActive,
|
||||
'bg-transparent text-black hover:text-white':
|
||||
isInverted && !isActive,
|
||||
'py-2 px-12': isDesktop,
|
||||
'border-t border-white p-20': !isDesktop,
|
||||
}
|
||||
);
|
||||
return linkClasses;
|
||||
}}
|
||||
)
|
||||
}
|
||||
>
|
||||
{text}
|
||||
</NavLink>
|
||||
|
@ -23,12 +23,8 @@ export const TransactionComplete = ({
|
||||
intent={Intent.Success}
|
||||
title={heading || t('Complete')}
|
||||
>
|
||||
{body && (
|
||||
<p className="mb-8" data-testid="transaction-complete-body">
|
||||
{body}
|
||||
</p>
|
||||
)}
|
||||
<p className="mb-8">
|
||||
{body && <p data-testid="transaction-complete-body">{body}</p>}
|
||||
<p>
|
||||
<Link
|
||||
title={t('View transaction on Etherscan')}
|
||||
target="_blank"
|
||||
|
@ -20,11 +20,9 @@ export const TransactionError = ({
|
||||
|
||||
return (
|
||||
<Callout iconName="error" intent={Intent.Danger}>
|
||||
<p className="mb-8">
|
||||
{error ? error.message : t('Something went wrong')}
|
||||
</p>
|
||||
<p>{error ? error.message : t('Something went wrong')}</p>
|
||||
{hash ? (
|
||||
<p className="mb-8">
|
||||
<p>
|
||||
<Link
|
||||
title={t('View transaction on Etherscan')}
|
||||
href={`${ETHERSCAN_URL}/tx/${hash}`}
|
||||
|
@ -38,12 +38,8 @@ export const TransactionPending = ({
|
||||
}, [heading, remainingConfirmations, t]);
|
||||
return (
|
||||
<Callout icon={<Loader size="small" />} title={title}>
|
||||
{body && (
|
||||
<p className="mb-8" data-testid="transaction-pending-body">
|
||||
{body}
|
||||
</p>
|
||||
)}
|
||||
<p className="mb-8">
|
||||
{body && <p data-testid="transaction-pending-body">{body}</p>}
|
||||
<p>
|
||||
<Link
|
||||
title={t('View transaction on Etherscan')}
|
||||
target="_blank"
|
||||
|
@ -5,18 +5,18 @@ import { Links } from '../../config';
|
||||
export const DownloadWalletPrompt = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className="mt-8">
|
||||
<h3>{t('getWallet')}</h3>
|
||||
<p>
|
||||
<>
|
||||
<h3 className="mt-12 mb-4">{t('getWallet')}</h3>
|
||||
<p className="mb-4">
|
||||
<Link className="text-deemphasise" href={Links.WALLET_GUIDE}>
|
||||
{t('readGuide')}
|
||||
</Link>
|
||||
</p>
|
||||
<p>
|
||||
<p className="mb-4">
|
||||
<Link className="text-deemphasise" href={Links.WALLET_RELEASES}>
|
||||
{t('downloadWallet')}
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -40,14 +40,16 @@ export const VegaWallet = () => {
|
||||
<section className="vega-wallet" data-testid="vega-wallet">
|
||||
<WalletCard dark={true}>
|
||||
<WalletCardHeader dark={true}>
|
||||
<div>
|
||||
<h1 className="text-h3 uppercase">{t('vegaWallet')}</h1>
|
||||
<span className="text-h6">{keypair && `(${keypair.name})`}</span>
|
||||
</div>
|
||||
<h1 className="col-start-1 m-0">{t('vegaWallet')}</h1>
|
||||
{keypair && (
|
||||
<span className="font-mono px-8">
|
||||
{truncateMiddle(keypair.pub)}
|
||||
</span>
|
||||
<>
|
||||
<div className="sm:row-start-2 sm:col-start-1 sm:col-span-2 text-h6 mb-12">
|
||||
{keypair.name}
|
||||
</div>
|
||||
<span className="sm:col-start-2 place-self-end font-mono pb-2 px-4">
|
||||
{truncateMiddle(keypair.pub)}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</WalletCardHeader>
|
||||
<WalletCardContent>{child}</WalletCardContent>
|
||||
@ -128,6 +130,7 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
||||
<WalletCardActions>
|
||||
<Button
|
||||
variant="inline-link"
|
||||
className="mt-4"
|
||||
onClick={() =>
|
||||
appDispatch({
|
||||
type: AppStateActionType.SET_VEGA_WALLET_MANAGE_OVERLAY,
|
||||
|
@ -29,10 +29,14 @@ interface WalletCardProps {
|
||||
}
|
||||
|
||||
export const WalletCard = ({ dark, children }: WalletCardProps) => {
|
||||
const className = classNames('text-ui border border-white', 'p-8', {
|
||||
'bg-black text-white': dark,
|
||||
'bg-white text-black': !dark,
|
||||
});
|
||||
const className = classNames(
|
||||
'text-ui border border-white',
|
||||
'pt-4 pl-8 pr-12 pb-12',
|
||||
{
|
||||
'bg-black text-white': dark,
|
||||
'bg-white text-black': !dark,
|
||||
}
|
||||
);
|
||||
return <div className={className}>{children}</div>;
|
||||
};
|
||||
|
||||
@ -43,7 +47,9 @@ interface WalletCardHeaderProps {
|
||||
|
||||
export const WalletCardHeader = ({ children }: WalletCardHeaderProps) => {
|
||||
return (
|
||||
<div className="flex gap-4 justify-between items-center">{children}</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-[auto_1fr] gap-4">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -145,23 +151,23 @@ export const WalletCardAsset = ({
|
||||
}`}
|
||||
/>
|
||||
<div>
|
||||
<div className="flex font-medium">
|
||||
<div className="flex font-medium align-center">
|
||||
<h1
|
||||
className={`text-h5 px-8 uppercase ${
|
||||
className={`text-h5 mb-0 px-8 uppercase leading-none ${
|
||||
dark ? 'text-white' : 'text-black'
|
||||
}`}
|
||||
>
|
||||
{name}
|
||||
</h1>
|
||||
<h2
|
||||
className={`text-h5 uppercase ${
|
||||
className={`text-h5 mb-0 uppercase leading-none ${
|
||||
dark ? 'text-white-60' : 'text-black-60'
|
||||
}`}
|
||||
>
|
||||
{subheading || symbol}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="px-8 text-h5 basis-full">
|
||||
<div className="px-8 text-h5 basis-full font-mono">
|
||||
<span>{integers}.</span>
|
||||
<span className={dark ? 'text-white-60' : 'text-black-60'}>
|
||||
{decimalsPlaces}
|
||||
|
@ -79,7 +79,7 @@ export const Web3Content = ({ children, appChainId }: Web3ContentProps) => {
|
||||
return (
|
||||
<Splash>
|
||||
<div className="flex flex-col items-center gap-12">
|
||||
<p className="mb-12">This app only works on chain ID: {appChainId}</p>
|
||||
<p>This app only works on chain ID: {appChainId}</p>
|
||||
<Button onClick={() => connector.deactivate()}>Disconnect</Button>
|
||||
</div>
|
||||
</Splash>
|
||||
|
@ -10,7 +10,7 @@ export const ProposalTermsJson = ({
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<section>
|
||||
<h2 className="text-h4 text-white mb-8">{t('proposalTerms')}</h2>
|
||||
<h2>{t('proposalTerms')}</h2>
|
||||
<SyntaxHighlighter data={terms} />
|
||||
</section>
|
||||
);
|
||||
|
@ -23,10 +23,10 @@ export const ProposalsList = ({ proposals }: ProposalsListProps) => {
|
||||
return (
|
||||
<>
|
||||
<Heading title={t('pageTitleGovernance')} />
|
||||
<p className="mb-8">{t('proposedChangesToVegaNetwork')}</p>
|
||||
<p className="mb-8">{t('vegaTokenHoldersCanVote')}</p>
|
||||
<p className="mb-8">{t('requiredMajorityDescription')}</p>
|
||||
<h2 className="text-h4 text-white">{t('proposals')}</h2>
|
||||
<p>{t('proposedChangesToVegaNetwork')}</p>
|
||||
<p>{t('vegaTokenHoldersCanVote')}</p>
|
||||
<p>{t('requiredMajorityDescription')}</p>
|
||||
<h2>{t('proposals')}</h2>
|
||||
<ul>
|
||||
{proposals.map((proposal) => (
|
||||
<ProposalListItem proposal={proposal} />
|
||||
|
@ -45,7 +45,7 @@ export const VoteDetails = ({ proposal }: VoteDetailsProps) => {
|
||||
return (
|
||||
<section>
|
||||
<h3 className="text-h4 text-white mb-8">{t('votes')}</h3>
|
||||
<p className="mb-8">
|
||||
<p>
|
||||
<span>
|
||||
<CurrentProposalStatus proposal={proposal} />
|
||||
</span>
|
||||
@ -90,7 +90,7 @@ export const VoteDetails = ({ proposal }: VoteDetailsProps) => {
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p className="mb-8">
|
||||
<p>
|
||||
{t('participation')}
|
||||
{': '}
|
||||
{participationMet ? (
|
||||
|
@ -42,13 +42,13 @@ const Home = ({ name }: RouteChildProps) => {
|
||||
/>
|
||||
</HomeSection>
|
||||
<HomeSection>
|
||||
<h2 className="text-h4 text-white">{t('Token Vesting')}</h2>
|
||||
<p className="mb-8">
|
||||
<h2>{t('Token Vesting')}</h2>
|
||||
<p>
|
||||
{t(
|
||||
'The vesting contract holds VEGA tokens until they have become unlocked.'
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-8">
|
||||
<p>
|
||||
<Trans
|
||||
i18nKey="Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked."
|
||||
components={{
|
||||
@ -62,7 +62,7 @@ const Home = ({ name }: RouteChildProps) => {
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<p className="mb-8">
|
||||
<p>
|
||||
{t(
|
||||
'Once unlocked they can be redeemed from the contract so that you can transfer them between wallets.'
|
||||
)}
|
||||
@ -74,13 +74,13 @@ const Home = ({ name }: RouteChildProps) => {
|
||||
</Link>
|
||||
</HomeSection>
|
||||
<HomeSection>
|
||||
<h2 className="text-h4 text-white">{t('Use your Vega tokens')}</h2>
|
||||
<p className="mb-8">
|
||||
<h2 className="uppercase">{t('Use your Vega tokens')}</h2>
|
||||
<p>
|
||||
{t(
|
||||
'To use your tokens on the Vega network they need to be associated with a Vega wallet/key.'
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-8">
|
||||
<p>
|
||||
{t(
|
||||
'This can happen both while held in the vesting contract as well as when redeemed.'
|
||||
)}
|
||||
@ -109,8 +109,8 @@ const Home = ({ name }: RouteChildProps) => {
|
||||
<div className="flex gap-40">
|
||||
<div className="flex-1">
|
||||
<HomeSection>
|
||||
<h2 className="text-h4 text-white">{t('Staking')}</h2>
|
||||
<p className="mb-8">
|
||||
<h2>{t('Staking')}</h2>
|
||||
<p>
|
||||
{t(
|
||||
'VEGA token holders can nominate a validator node and receive staking rewards.'
|
||||
)}
|
||||
@ -129,8 +129,8 @@ const Home = ({ name }: RouteChildProps) => {
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<HomeSection>
|
||||
<h2 className="text-h4 text-white">{t('Governance')}</h2>
|
||||
<p className="mb-8">
|
||||
<h2>{t('Governance')}</h2>
|
||||
<p>
|
||||
{t(
|
||||
'VEGA token holders can vote on proposed changes to the network and create proposals.'
|
||||
)}
|
||||
@ -155,5 +155,5 @@ const Home = ({ name }: RouteChildProps) => {
|
||||
export default Home;
|
||||
|
||||
export const HomeSection = ({ children }: { children: React.ReactNode }) => {
|
||||
return <section className="mb-20">{children}</section>;
|
||||
return <section className="mb-28">{children}</section>;
|
||||
};
|
||||
|
@ -37,7 +37,7 @@ export const TokenDetailsCirculating = ({
|
||||
}) => {
|
||||
const totalCirculating = sumCirculatingTokens(tranches);
|
||||
return (
|
||||
<span data-testid="circulating-supply">
|
||||
<span data-testid="circulating-supply" className="font-mono">
|
||||
{formatNumber(totalCirculating, 2)}
|
||||
</span>
|
||||
);
|
||||
|
@ -42,13 +42,13 @@ export const TokenDetails = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<KeyValueTable className={'token-details'}>
|
||||
<KeyValueTable className={'token-details text-white'}>
|
||||
<KeyValueTableRow>
|
||||
{t('Token address').toUpperCase()}
|
||||
<Link
|
||||
data-testid="token-address"
|
||||
title={t('View on Etherscan (opens in a new tab)')}
|
||||
className="font-mono"
|
||||
className="font-mono text-white text-right"
|
||||
href={`${ETHERSCAN_URL}/address/${token.address}`}
|
||||
>
|
||||
{token.address}
|
||||
@ -59,7 +59,7 @@ export const TokenDetails = ({
|
||||
<Link
|
||||
data-testid="token-contract"
|
||||
title={t('View on Etherscan (opens in a new tab)')}
|
||||
className="font-mono"
|
||||
className="font-mono text-white text-right"
|
||||
href={`${ETHERSCAN_URL}/address/${config.token_vesting_contract.address}`}
|
||||
>
|
||||
{config.token_vesting_contract.address}
|
||||
@ -67,7 +67,9 @@ export const TokenDetails = ({
|
||||
</KeyValueTableRow>
|
||||
<KeyValueTableRow>
|
||||
{t('Total supply').toUpperCase()}
|
||||
<span data-testid="total-supply">{formatNumber(totalSupply, 2)}</span>
|
||||
<span className="font-mono" data-testid="total-supply">
|
||||
{formatNumber(totalSupply, 2)}
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
<KeyValueTableRow>
|
||||
{t('Circulating supply').toUpperCase()}
|
||||
@ -75,7 +77,9 @@ export const TokenDetails = ({
|
||||
</KeyValueTableRow>
|
||||
<KeyValueTableRow>
|
||||
{t('Staked on Vega validator').toUpperCase()}
|
||||
<span data-testid="staked">{formatNumber(totalStaked, 2)}</span>
|
||||
<span data-testid="staked" className="font-mono">
|
||||
{formatNumber(totalStaked, 2)}
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
</KeyValueTable>
|
||||
);
|
||||
|
@ -55,16 +55,18 @@ export const RedemptionInformation = () => {
|
||||
if (!filteredTranches.length) {
|
||||
return (
|
||||
<section data-testid="redemption-page">
|
||||
<p className="mb-12" data-testid="redemption-no-balance">
|
||||
<Trans
|
||||
i18nKey="noVestingTokens"
|
||||
components={{
|
||||
tranchesLink: (
|
||||
<Link className="underline text-white" to={Routes.TRANCHES} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<div className="mb-20">
|
||||
<p data-testid="redemption-no-balance">
|
||||
<Trans
|
||||
i18nKey="noVestingTokens"
|
||||
components={{
|
||||
tranchesLink: (
|
||||
<Link className="underline text-white" to={Routes.TRANCHES} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<AddLockedTokenAddress />
|
||||
</section>
|
||||
);
|
||||
@ -92,9 +94,7 @@ export const RedemptionInformation = () => {
|
||||
vested={totalVestedBalance}
|
||||
/>
|
||||
</div>
|
||||
{filteredTranches.length ? (
|
||||
<h2 className="text-h4 text-white mb-12">{t('Tranche breakdown')}</h2>
|
||||
) : null}
|
||||
{filteredTranches.length ? <h2>{t('Tranche breakdown')}</h2> : null}
|
||||
{zeroTranche && (
|
||||
<Tranche0Table
|
||||
trancheId={0}
|
||||
@ -133,7 +133,7 @@ export const RedemptionInformation = () => {
|
||||
iconName="hand-up"
|
||||
intent={Intent.Warning}
|
||||
>
|
||||
<p className="mb-12">{t('Find out more about Staking.')}</p>
|
||||
<p>{t('Find out more about Staking.')}</p>
|
||||
<Link to="/staking" className="underline text-white">
|
||||
{t('Stake VEGA tokens')}
|
||||
</Link>
|
||||
|
@ -68,7 +68,7 @@ const RedemptionRouter = () => {
|
||||
if (!account) {
|
||||
return (
|
||||
<EthConnectPrompt>
|
||||
<p data-testid="eth-connect-prompt" className="mb-8">
|
||||
<p data-testid="eth-connect-prompt">
|
||||
{t(
|
||||
"Use the Ethereum wallet you want to send your tokens to. You'll also need enough Ethereum to pay gas."
|
||||
)}
|
||||
|
@ -73,7 +73,7 @@ export const RedeemFromTranche = () => {
|
||||
!trancheBalance
|
||||
) {
|
||||
return (
|
||||
<section data-testid="redemption-page">
|
||||
<section data-testid="redemption-page" className="mb-28">
|
||||
<p data-testid="redemption-no-balance">
|
||||
<Trans
|
||||
i18nKey="noVestingTokens"
|
||||
@ -99,7 +99,7 @@ export const RedeemFromTranche = () => {
|
||||
}
|
||||
completeBody={
|
||||
<>
|
||||
<p className="mb-8">
|
||||
<p>
|
||||
{t(
|
||||
'You have redeemed {{redeemedAmount}} VEGA tokens from this tranche. They are now free to transfer from your Ethereum wallet.',
|
||||
{
|
||||
@ -107,7 +107,7 @@ export const RedeemFromTranche = () => {
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-8">
|
||||
<p>
|
||||
{t(
|
||||
'The VEGA token address is {{address}}, make sure you add this to your wallet to see your tokens',
|
||||
{
|
||||
|
@ -109,8 +109,8 @@ export const RewardsIndex = () => {
|
||||
return (
|
||||
<section className="rewards">
|
||||
<Heading title={t('pageTitleRewards')} />
|
||||
<p className="mb-8">{t('rewardsPara1')}</p>
|
||||
<p className="mb-8">{t('rewardsPara2')}</p>
|
||||
<p>{t('rewardsPara1')}</p>
|
||||
<p>{t('rewardsPara2')}</p>
|
||||
{payoutDuration ? (
|
||||
<div className="my-24">
|
||||
<Callout
|
||||
|
@ -64,7 +64,7 @@ export const RewardInfo = ({
|
||||
|
||||
return (
|
||||
<div className="mt-24">
|
||||
<p className="mb-8">
|
||||
<p>
|
||||
{t('Connected Vega key')}: {currVegaKey.pub}
|
||||
</p>
|
||||
{vegaTokenRewards.length ? (
|
||||
|
@ -13,7 +13,7 @@ export const AssociateInfo = ({ pubKey }: { pubKey: string | null }) => {
|
||||
{t('What Vega key is going to control your stake?')}
|
||||
</h2>
|
||||
<ConnectedVegaKey pubKey={pubKey} />
|
||||
<h2 className="text-h4 text-white" data-testid="associate-amount-header">
|
||||
<h2 data-testid="associate-amount-header">
|
||||
{t('How much would you like to associate?')}
|
||||
</h2>
|
||||
</>
|
||||
|
@ -62,13 +62,13 @@ export const AssociateTransaction = ({
|
||||
if (derivedTxState === TxState.Pending) {
|
||||
return (
|
||||
<Callout icon={<Loader size="small" />} title={title}>
|
||||
<p data-testid="transaction-pending-body" className="mb-8">
|
||||
<p data-testid="transaction-pending-body">
|
||||
{t('Associating {{amount}} VEGA tokens with Vega key {{vegaKey}}', {
|
||||
amount,
|
||||
vegaKey: truncateMiddle(vegaKey),
|
||||
})}
|
||||
</p>
|
||||
<p className="mb-8">
|
||||
<p>
|
||||
<Link
|
||||
title={t('View transaction on Etherscan')}
|
||||
href={`${ETHERSCAN_URL}/tx/${state.txData.hash}`}
|
||||
@ -77,7 +77,7 @@ export const AssociateTransaction = ({
|
||||
{t('View on Etherscan (opens in a new tab)')}
|
||||
</Link>
|
||||
</p>
|
||||
<p data-testid="transaction-pending-footer" className="mb-8">
|
||||
<p data-testid="transaction-pending-footer">
|
||||
{t('pendingAssociationText', {
|
||||
confirmations: requiredConfirmations,
|
||||
})}
|
||||
|
@ -60,24 +60,20 @@ export const DisassociatePage = ({
|
||||
|
||||
return (
|
||||
<section className="disassociate-page" data-testid="disassociate-page">
|
||||
<p className="mb-12">
|
||||
<p>
|
||||
{t(
|
||||
'Use this form to disassociate VEGA tokens with a Vega key. This returns them to either the Ethereum wallet that used the Staking bridge or the vesting contract.'
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-12">
|
||||
<p>
|
||||
<span className="text-vega-red">{t('Warning')}:</span>{' '}
|
||||
{t(
|
||||
'Any Tokens that have been nominated to a node will sacrifice any Rewards they are due for the current epoch. If you do not wish to sacrifices fees you should remove stake from a node at the end of an epoch before disassocation.'
|
||||
)}
|
||||
</p>
|
||||
<h2 className="text-h4 text-white mb-8">
|
||||
{t('What Vega wallet are you removing Tokens from?')}
|
||||
</h2>
|
||||
<h2>{t('What Vega wallet are you removing Tokens from?')}</h2>
|
||||
<ConnectedVegaKey pubKey={vegaKey.pub} />
|
||||
<h2 className="text-h4 text-white mb-8">
|
||||
{t('What tokens would you like to return?')}
|
||||
</h2>
|
||||
<h2>{t('What tokens would you like to return?')}</h2>
|
||||
<StakingMethodRadio
|
||||
setSelectedStakingMethod={setSelectedStakingMethod}
|
||||
selectedStakingMethod={selectedStakingMethod}
|
||||
|
@ -223,7 +223,7 @@ export const StakingForm = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 className="text-h4 mb-8">{t('Manage your stake')}</h2>
|
||||
<h2>{t('Manage your stake')}</h2>
|
||||
<FormGroup>
|
||||
<RadioGroup
|
||||
onChange={(value) => {
|
||||
@ -254,9 +254,7 @@ export const StakingForm = ({
|
||||
<>
|
||||
{action === Actions.Add ? (
|
||||
<>
|
||||
<h2 className="text-h4 mb-8">
|
||||
{t('How much to Add in next epoch?')}
|
||||
</h2>
|
||||
<h2>{t('How much to Add in next epoch?')}</h2>
|
||||
<p>
|
||||
{t('minimumNomination', {
|
||||
minTokens: minTokensWithDecimals,
|
||||
|
@ -96,10 +96,7 @@ export const StakingNode = ({ vegaKey, data }: StakingNodeProps) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2
|
||||
data-test-id="validator-node-title"
|
||||
className="text-h4 break-word mb-8"
|
||||
>
|
||||
<h2 data-test-id="validator-node-title" className="text-h4 break-word">
|
||||
{nodeInfo.name
|
||||
? t('validatorTitle', { nodeName: nodeInfo.name })
|
||||
: t('validatorTitle', { nodeName: t('validatorTitleFallback') })}
|
||||
|
@ -19,17 +19,19 @@ import { NodeList } from './node-list';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { truncateMiddle } from '../../lib/truncate-middle';
|
||||
|
||||
const stakingBulletStyles = { marginBottom: '12px', fontSize: '18px' };
|
||||
|
||||
export const Staking = ({ data }: { data?: StakingQueryResult }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="mb-24">
|
||||
<p className="mb-12">{t('stakingDescription1')}</p>
|
||||
<p className="mb-12">{t('stakingDescription2')}</p>
|
||||
<p className="mb-12">{t('stakingDescription3')}</p>
|
||||
<p className="mb-12">{t('stakingDescription4')}</p>
|
||||
<p className="mb-12">
|
||||
<p>{t('stakingDescription1')}</p>
|
||||
<p>{t('stakingDescription2')}</p>
|
||||
<p>{t('stakingDescription3')}</p>
|
||||
<p>{t('stakingDescription4')}</p>
|
||||
<p>
|
||||
<Link
|
||||
href={Links.STAKING_GUIDE}
|
||||
className="text-white underline"
|
||||
@ -41,11 +43,15 @@ export const Staking = ({ data }: { data?: StakingQueryResult }) => {
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<BulletHeader tag="h2">{t('stakingStep1')}</BulletHeader>
|
||||
<BulletHeader tag="h2" style={stakingBulletStyles}>
|
||||
{t('stakingStep1')}
|
||||
</BulletHeader>
|
||||
<StakingStepConnectWallets />
|
||||
</section>
|
||||
<section>
|
||||
<BulletHeader tag="h2">{t('stakingStep1')}</BulletHeader>
|
||||
<BulletHeader tag="h2" style={stakingBulletStyles}>
|
||||
{t('stakingStep2')}
|
||||
</BulletHeader>
|
||||
<StakingStepAssociate
|
||||
associated={
|
||||
new BigNumber(
|
||||
@ -55,7 +61,9 @@ export const Staking = ({ data }: { data?: StakingQueryResult }) => {
|
||||
/>
|
||||
</section>
|
||||
<section>
|
||||
<BulletHeader tag="h2">{t('stakingStep3')}</BulletHeader>
|
||||
<BulletHeader tag="h2" style={stakingBulletStyles}>
|
||||
{t('stakingStep3')}
|
||||
</BulletHeader>
|
||||
<StakingStepSelectNode data={data} />
|
||||
</section>
|
||||
</>
|
||||
@ -82,7 +90,7 @@ export const StakingStepConnectWallets = () => {
|
||||
{truncateMiddle(account)}
|
||||
</Link>
|
||||
</p>
|
||||
<p>
|
||||
<p className="mb-8">
|
||||
{t('stakingVegaWalletConnected', {
|
||||
key: truncateMiddle(keypair.pub),
|
||||
})}
|
||||
@ -93,7 +101,7 @@ export const StakingStepConnectWallets = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className="mb-8">
|
||||
<p>
|
||||
<Trans
|
||||
i18nKey="stakingStep1Text"
|
||||
components={{
|
||||
@ -116,7 +124,7 @@ export const StakingStepConnectWallets = () => {
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<p className="mb-8">
|
||||
<p>
|
||||
<Button
|
||||
onClick={() =>
|
||||
appDispatch({
|
||||
|
@ -17,7 +17,7 @@ export const YourStake = ({
|
||||
|
||||
return (
|
||||
<div data-testid="your-stake">
|
||||
<h2 className="text-h4 mb-8">{t('Your stake')}</h2>
|
||||
<h2>{t('Your stake')}</h2>
|
||||
<KeyValueTable>
|
||||
<KeyValueTableRow>
|
||||
{t('Your Stake On Node (This Epoch)')}
|
||||
|
@ -67,7 +67,7 @@ export const Tranche = () => {
|
||||
{formatNumber(tranche.total_removed)}
|
||||
</span>
|
||||
</div>
|
||||
<h2 className="text-h4 text-white mb-8">{t('Holders')}</h2>
|
||||
<h2>{t('Holders')}</h2>
|
||||
{tranche.users.length ? (
|
||||
<ul role="list">
|
||||
{tranche.users.map((user, i) => {
|
||||
|
@ -29,10 +29,10 @@ export const Tranches = () => {
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h2 className="text-h4">{t('chartTitle')}</h2>
|
||||
<p className="mb-12">{t('chartAbove')}</p>
|
||||
<h2>{t('chartTitle')}</h2>
|
||||
<p>{t('chartAbove')}</p>
|
||||
<VestingChart />
|
||||
<p className="mb-12">{t('chartBelow')}</p>
|
||||
<p>{t('chartBelow')}</p>
|
||||
{tranches?.length ? (
|
||||
<ul role="list">
|
||||
{(showAll ? tranches : filteredTranches).map((tranche) => {
|
||||
|
@ -23,7 +23,7 @@ const Withdraw = () => {
|
||||
return (
|
||||
<>
|
||||
<Heading title={t('withdrawPageHeading')} />
|
||||
<p className="mb-8">{t('withdrawPageText')}</p>
|
||||
<p>{t('withdrawPageText')}</p>
|
||||
<div className="mb-24">
|
||||
<VegaWalletContainer>
|
||||
{(currVegaKey) => <WithdrawContainer currVegaKey={currVegaKey} />}
|
||||
@ -141,7 +141,7 @@ export const WithdrawContainer = ({ currVegaKey }: WithdrawContainerProps) => {
|
||||
title={t('pendingWithdrawalsCalloutTitle')}
|
||||
intent={Intent.Warning}
|
||||
>
|
||||
<p className="mb-8">{t('pendingWithdrawalsCalloutText')}</p>
|
||||
<p>{t('pendingWithdrawalsCalloutText')}</p>
|
||||
<p>
|
||||
<Link to={Routes.WITHDRAWALS} className="underline text-white">
|
||||
{t('pendingWithdrawalsCalloutButton')}
|
||||
|
@ -74,7 +74,7 @@ const WithdrawPendingContainer = () => {
|
||||
return (
|
||||
<>
|
||||
<h2>{t('withdrawalsPreparedWarningHeading')}</h2>
|
||||
<p className="mb-8">{t('withdrawalsText')}</p>
|
||||
<p>{t('withdrawalsText')}</p>
|
||||
<p className="mb-28">{t('withdrawalsPreparedWarningText')}</p>
|
||||
<ul role="list">
|
||||
{withdrawals.map((w) => (
|
||||
|
@ -1,3 +1,15 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
h1 {
|
||||
@apply text-h3 text-white uppercase mb-12;
|
||||
}
|
||||
h2 {
|
||||
@apply text-h4 text-white mb-8;
|
||||
}
|
||||
p {
|
||||
@apply mb-12;
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"stepDefinitions": "src/support/step_definitions"
|
||||
}
|
48
apps/trading-e2e/cypress.config.js
Normal file
48
apps/trading-e2e/cypress.config.js
Normal file
@ -0,0 +1,48 @@
|
||||
const { defineConfig } = require('cypress');
|
||||
|
||||
module.exports = defineConfig({
|
||||
component: {
|
||||
baseUrl: 'http://localhost:4200',
|
||||
fileServerFolder: '.',
|
||||
fixturesFolder: false,
|
||||
specPattern: '**/*.cy.{js,jsx,ts,tsx}',
|
||||
supportFile: './src/support/index.ts',
|
||||
video: true,
|
||||
videosFolder: '../../dist/cypress/apps/trading-e2e/videos',
|
||||
screenshotsFolder: '../../dist/cypress/apps/trading-e2e/screenshots',
|
||||
chromeWebSecurity: false,
|
||||
projectId: 'et4snf',
|
||||
defaultCommandTimeout: 10000,
|
||||
},
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:4200',
|
||||
fileServerFolder: '.',
|
||||
fixturesFolder: false,
|
||||
specPattern: '**/*.cy.{js,jsx,ts,tsx}',
|
||||
supportFile: './src/support/index.ts',
|
||||
video: true,
|
||||
videosFolder: '../../dist/cypress/apps/trading-e2e/videos',
|
||||
screenshotsFolder: '../../dist/cypress/apps/trading-e2e/screenshots',
|
||||
chromeWebSecurity: false,
|
||||
projectId: 'et4snf',
|
||||
defaultCommandTimeout: 10000,
|
||||
},
|
||||
env: {
|
||||
TRADING_TEST_VEGA_WALLET_NAME: 'UI_Trading_Test',
|
||||
ETHEREUM_PROVIDER_URL:
|
||||
'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
|
||||
VEGA_PUBLIC_KEY:
|
||||
'47836c253520d2661bf5bed6339c0de08fd02cf5d4db0efee3b4373f20c7d278',
|
||||
VEGA_PUBLIC_KEY2:
|
||||
'1a18cdcaaa4f44a57b35a4e9b77e0701c17a476f2b407620f8c17371740cf2e4',
|
||||
TRUNCATED_VEGA_PUBLIC_KEY: '47836c…c7d278',
|
||||
TRUNCATED_VEGA_PUBLIC_KEY2: '1a18cd…0cf2e4',
|
||||
ETHEREUM_WALLET_ADDRESS: '0x265Cc6d39a1B53d0d92068443009eE7410807158',
|
||||
ETHERSCAN_URL: 'https://ropsten.etherscan.io',
|
||||
tsConfig: 'tsconfig.json',
|
||||
TAGS: 'not @todo and not @ignore and not @manual',
|
||||
TRADING_TEST_VEGA_WALLET_PASSPHRASE: '123',
|
||||
ETH_WALLET_MNEMONIC:
|
||||
'ugly gallery notice network true range brave clarify flat logic someone chunk',
|
||||
},
|
||||
});
|
@ -1,31 +0,0 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:4200",
|
||||
"fileServerFolder": ".",
|
||||
"fixturesFolder": false,
|
||||
"pluginsFile": "./src/plugins/index.js",
|
||||
"testFiles": "*.{ts,feature,features}",
|
||||
"ignoreTestFiles": "**/*.js",
|
||||
"integrationFolder": "./src/integration",
|
||||
"modifyObstructiveCode": false,
|
||||
"supportFile": "./src/support/index.ts",
|
||||
"video": true,
|
||||
"videosFolder": "../../dist/cypress/apps/trading-e2e/videos",
|
||||
"screenshotsFolder": "../../dist/cypress/apps/trading-e2e/screenshots",
|
||||
"chromeWebSecurity": false,
|
||||
"projectId": "et4snf",
|
||||
"defaultCommandTimeout": 10000,
|
||||
"env": {
|
||||
"TRADING_TEST_VEGA_WALLET_NAME": "UI_Trading_Test",
|
||||
"ETHEREUM_PROVIDER_URL": "https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8",
|
||||
"VEGA_PUBLIC_KEY": "47836c253520d2661bf5bed6339c0de08fd02cf5d4db0efee3b4373f20c7d278",
|
||||
"VEGA_PUBLIC_KEY2": "1a18cdcaaa4f44a57b35a4e9b77e0701c17a476f2b407620f8c17371740cf2e4",
|
||||
"TRUNCATED_VEGA_PUBLIC_KEY": "47836c…c7d278",
|
||||
"TRUNCATED_VEGA_PUBLIC_KEY2": "1a18cd…0cf2e4",
|
||||
"ETHEREUM_WALLET_ADDRESS": "0x265Cc6d39a1B53d0d92068443009eE7410807158",
|
||||
"ETHERSCAN_URL": "https://ropsten.etherscan.io",
|
||||
"tsConfig": "tsconfig.json",
|
||||
"TAGS": "not @todo and not @ignore and not @manual",
|
||||
"TRADING_TEST_VEGA_WALLET_PASSPHRASE": "123",
|
||||
"ETH_WALLET_MNEMONIC": "ugly gallery notice network true range brave clarify flat logic someone chunk"
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
"e2e": {
|
||||
"executor": "@nrwl/cypress:cypress",
|
||||
"options": {
|
||||
"cypressConfig": "apps/trading-e2e/cypress.json",
|
||||
"cypressConfig": "apps/trading-e2e/cypress.config.js",
|
||||
"devServerTarget": "trading:serve"
|
||||
},
|
||||
"configurations": {
|
||||
|
@ -10,6 +10,7 @@ describe('vega wallet', () => {
|
||||
beforeEach(() => {
|
||||
// Using portfolio page as it requires vega wallet connection
|
||||
cy.visit('/portfolio');
|
||||
cy.get('main[data-testid="portfolio"]').should('exist');
|
||||
});
|
||||
|
||||
it('can connect', () => {
|
||||
@ -64,8 +65,10 @@ describe('vega wallet', () => {
|
||||
describe('ethereum wallet', () => {
|
||||
beforeEach(() => {
|
||||
cy.mockWeb3Provider();
|
||||
// Using portfolio is it requires Ethereum wallet connection
|
||||
// Using portfolio withdrawals tab is it requires Ethereum wallet connection
|
||||
cy.visit('/portfolio');
|
||||
cy.get('main[data-testid="portfolio"]').should('exist');
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
});
|
||||
|
||||
it('can connect', () => {
|
||||
@ -73,6 +76,6 @@ describe('ethereum wallet', () => {
|
||||
cy.getByTestId('web3-connector-list').should('exist');
|
||||
cy.getByTestId('web3-connector-MetaMask').click();
|
||||
cy.getByTestId('web3-connector-list').should('not.exist');
|
||||
cy.getByTestId('portfolio-grid').should('exist');
|
||||
cy.getByTestId('tab-withdrawals').should('not.be.empty');
|
||||
});
|
||||
});
|
@ -71,6 +71,8 @@ describe('markets table', () => {
|
||||
cy.wait('@Market');
|
||||
cy.contains('ACTIVE MARKET');
|
||||
cy.url().should('include', '/markets/market-0');
|
||||
|
||||
verifyMarketSummaryDisplayed('Active');
|
||||
});
|
||||
|
||||
it('can select a suspended market', () => {
|
||||
@ -88,5 +90,28 @@ describe('markets table', () => {
|
||||
cy.wait('@Market');
|
||||
cy.contains('SUSPENDED MARKET');
|
||||
cy.url().should('include', '/markets/market-1');
|
||||
|
||||
verifyMarketSummaryDisplayed('Suspended');
|
||||
});
|
||||
|
||||
function verifyMarketSummaryDisplayed(expectedMarketState: string) {
|
||||
const marketSummaryBlock = 'market-summary';
|
||||
const percentageValue = 'price-change-percentage';
|
||||
const priceChangeValue = 'price-change';
|
||||
const tradingVolume = 'trading-volume';
|
||||
const tradingMode = 'trading-mode';
|
||||
const marketState = 'market-state';
|
||||
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.contains('Change (24h)');
|
||||
cy.getByTestId(percentageValue).should('not.be.empty');
|
||||
cy.getByTestId(priceChangeValue).should('not.be.empty');
|
||||
cy.contains('Volume');
|
||||
cy.getByTestId(tradingVolume).should('not.be.empty');
|
||||
cy.contains('Trading mode');
|
||||
cy.getByTestId(tradingMode).should('not.be.empty');
|
||||
cy.contains('State');
|
||||
cy.getByTestId(marketState).should('have.text', expectedMarketState);
|
||||
});
|
||||
}
|
||||
});
|
120
apps/trading-e2e/src/integration/portfolio-fills.cy.ts
Normal file
120
apps/trading-e2e/src/integration/portfolio-fills.cy.ts
Normal file
@ -0,0 +1,120 @@
|
||||
import { aliasQuery } from '@vegaprotocol/cypress';
|
||||
import { generateFill, generateFills } from '../support/mocks/generate-fills';
|
||||
import { Side } from '@vegaprotocol/types';
|
||||
import { connectVegaWallet } from '../support/vega-wallet';
|
||||
|
||||
describe('fills', () => {
|
||||
before(() => {
|
||||
const fills = [
|
||||
generateFill({
|
||||
buyer: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
},
|
||||
}),
|
||||
generateFill({
|
||||
id: '1',
|
||||
seller: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
},
|
||||
aggressor: Side.Sell,
|
||||
buyerFee: {
|
||||
infrastructureFee: '5000',
|
||||
},
|
||||
market: {
|
||||
name: 'Apples Daily v3',
|
||||
positionDecimalPlaces: 2,
|
||||
},
|
||||
}),
|
||||
generateFill({
|
||||
id: '2',
|
||||
seller: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
},
|
||||
aggressor: Side.Buy,
|
||||
}),
|
||||
generateFill({
|
||||
id: '3',
|
||||
aggressor: Side.Sell,
|
||||
market: {
|
||||
name: 'ETHBTC Quarterly (30 Jun 2022)',
|
||||
},
|
||||
buyer: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
},
|
||||
}),
|
||||
];
|
||||
const result = generateFills({
|
||||
party: {
|
||||
tradesPaged: {
|
||||
edges: fills.map((f, i) => {
|
||||
return {
|
||||
__typename: 'TradeEdge',
|
||||
node: f,
|
||||
cursor: i.toString(),
|
||||
};
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
cy.mockGQL((req) => {
|
||||
aliasQuery(req, 'Fills', result);
|
||||
});
|
||||
cy.visit('/portfolio');
|
||||
cy.get('main[data-testid="portfolio"]').should('exist');
|
||||
});
|
||||
|
||||
it('renders fills', () => {
|
||||
cy.getByTestId('Fills').click();
|
||||
cy.getByTestId('tab-fills').contains('Please connect Vega wallet');
|
||||
|
||||
connectVegaWallet();
|
||||
|
||||
cy.getByTestId('tab-fills').should('be.visible');
|
||||
|
||||
cy.getByTestId('tab-fills')
|
||||
.get('[role="gridcell"][col-id="market.name"]')
|
||||
.each(($marketSymbol) => {
|
||||
cy.wrap($marketSymbol).invoke('text').should('not.be.empty');
|
||||
});
|
||||
cy.getByTestId('tab-fills')
|
||||
.get('[role="gridcell"][col-id="size"]')
|
||||
.each(($amount) => {
|
||||
cy.wrap($amount).invoke('text').should('not.be.empty');
|
||||
});
|
||||
cy.getByTestId('tab-positions')
|
||||
.get('[role="gridcell"][col-id="price"]')
|
||||
.each(($prices) => {
|
||||
cy.wrap($prices).invoke('text').should('not.be.empty');
|
||||
});
|
||||
cy.getByTestId('tab-positions')
|
||||
.get('[role="gridcell"][col-id="price_1"]')
|
||||
.each(($total) => {
|
||||
cy.wrap($total).invoke('text').should('not.be.empty');
|
||||
});
|
||||
cy.getByTestId('tab-positions')
|
||||
.get('[role="gridcell"][col-id="aggressor"]')
|
||||
.each(($role) => {
|
||||
cy.wrap($role)
|
||||
.invoke('text')
|
||||
.then((text) => {
|
||||
const roles = ['Maker', 'Taker'];
|
||||
expect(roles.indexOf(text.trim())).to.be.greaterThan(-1);
|
||||
});
|
||||
});
|
||||
cy.getByTestId('tab-positions')
|
||||
.get(
|
||||
'[role="gridcell"][col-id="market.tradableInstrument.instrument.product"]'
|
||||
)
|
||||
.each(($fees) => {
|
||||
cy.wrap($fees).invoke('text').should('not.be.empty');
|
||||
});
|
||||
const dateTimeRegex =
|
||||
/(\d{1,2})\/(\d{1,2})\/(\d{4}), (\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
|
||||
cy.get('[col-id="createdAt"]').each(($tradeDateTime, index) => {
|
||||
if (index != 0) {
|
||||
//ignore header
|
||||
cy.wrap($tradeDateTime).invoke('text').should('match', dateTimeRegex);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
@ -1,6 +0,0 @@
|
||||
describe('portfolio', () => {
|
||||
it('requires connecting', () => {
|
||||
cy.visit('/portfolio');
|
||||
cy.get('main[data-testid="portfolio"]').should('exist');
|
||||
});
|
||||
});
|
@ -144,15 +144,15 @@ describe('deal ticket orders', () => {
|
||||
'Awaiting network confirmation'
|
||||
);
|
||||
cy.getByTestId(orderTransactionHash)
|
||||
.invoke('text')
|
||||
.should('contain', 'Tx hash: test-tx-hash');
|
||||
.invoke('attr', 'href')
|
||||
.should('include', 'https://explorer.fairground.wtf/txs/0xtest-tx-hash');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
};
|
||||
|
||||
it.skip('cannot place an order if market is suspended');
|
||||
it.skip('cannot place an order if size is 0');
|
||||
it.skip('cannot place an order expiry date is invalid');
|
||||
it.skip('unsuccessfull order due to no collateral');
|
||||
it.skip('unsuccessful order due to no collateral');
|
||||
});
|
||||
|
||||
describe('deal ticket validation', () => {
|
@ -1,75 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
const webpackPreprocessor = require('@cypress/webpack-preprocessor');
|
||||
const webpack = require('webpack');
|
||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
const nodeExternals = require('webpack-node-externals');
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
on(
|
||||
'file:preprocessor',
|
||||
webpackPreprocessor({
|
||||
webpackOptions: {
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'],
|
||||
plugins: [
|
||||
new TsconfigPathsPlugin({
|
||||
configFile: config.env.tsConfig,
|
||||
extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'],
|
||||
}),
|
||||
],
|
||||
fallback: {
|
||||
path: require.resolve('path-browserify'),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.([jt])sx?$/,
|
||||
loader: 'ts-loader',
|
||||
exclude: [/node_modules/],
|
||||
options: {
|
||||
configFile: config.env.tsConfig,
|
||||
// https://github.com/TypeStrong/ts-loader/pull/685
|
||||
experimentalWatchApi: true,
|
||||
transpileOnly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.feature$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'cypress-cucumber-preprocessor/loader',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.features$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'cypress-cucumber-preprocessor/lib/featuresLoader',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new ForkTsCheckerWebpackPlugin({
|
||||
typescript: {
|
||||
enabled: true,
|
||||
configFile: config.env.tsConfig,
|
||||
},
|
||||
}),
|
||||
new webpack.ProvidePlugin({
|
||||
process: 'process/browser',
|
||||
}),
|
||||
],
|
||||
externals: [nodeExternals()],
|
||||
},
|
||||
})
|
||||
);
|
||||
};
|
134
apps/trading-e2e/src/support/mocks/generate-fills.ts
Normal file
134
apps/trading-e2e/src/support/mocks/generate-fills.ts
Normal file
@ -0,0 +1,134 @@
|
||||
import type {
|
||||
Fills,
|
||||
Fills_party_tradesPaged_edges_node,
|
||||
} from '@vegaprotocol/fills';
|
||||
import { Side } from '@vegaprotocol/types';
|
||||
import merge from 'lodash/merge';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
|
||||
export const generateFills = (override?: PartialDeep<Fills>): Fills => {
|
||||
const fills: Fills_party_tradesPaged_edges_node[] = [
|
||||
generateFill({
|
||||
buyer: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
},
|
||||
}),
|
||||
generateFill({
|
||||
id: '1',
|
||||
seller: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
},
|
||||
aggressor: Side.Sell,
|
||||
buyerFee: {
|
||||
infrastructureFee: '5000',
|
||||
},
|
||||
market: {
|
||||
name: 'Apples Daily v3',
|
||||
positionDecimalPlaces: 2,
|
||||
},
|
||||
}),
|
||||
generateFill({
|
||||
id: '2',
|
||||
seller: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
},
|
||||
aggressor: Side.Buy,
|
||||
}),
|
||||
generateFill({
|
||||
id: '3',
|
||||
aggressor: Side.Sell,
|
||||
market: {
|
||||
name: 'ETHBTC Quarterly (30 Jun 2022)',
|
||||
},
|
||||
buyer: {
|
||||
id: Cypress.env('VEGA_PUBLIC_KEY'),
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
const defaultResult: Fills = {
|
||||
party: {
|
||||
id: 'buyer-id',
|
||||
tradesPaged: {
|
||||
__typename: 'TradeConnection',
|
||||
totalCount: 1,
|
||||
edges: fills.map((f) => {
|
||||
return {
|
||||
__typename: 'TradeEdge',
|
||||
node: f,
|
||||
cursor: '3',
|
||||
};
|
||||
}),
|
||||
pageInfo: {
|
||||
__typename: 'PageInfo',
|
||||
startCursor: '1',
|
||||
endCursor: '2',
|
||||
},
|
||||
},
|
||||
__typename: 'Party',
|
||||
},
|
||||
};
|
||||
|
||||
return merge(defaultResult, override);
|
||||
};
|
||||
|
||||
export const generateFill = (
|
||||
override?: PartialDeep<Fills_party_tradesPaged_edges_node>
|
||||
) => {
|
||||
const defaultFill: Fills_party_tradesPaged_edges_node = {
|
||||
__typename: 'Trade',
|
||||
id: '0',
|
||||
createdAt: new Date().toISOString(),
|
||||
price: '10000000',
|
||||
size: '50000',
|
||||
buyOrder: 'buy-order',
|
||||
sellOrder: 'sell-order',
|
||||
aggressor: Side.Buy,
|
||||
buyer: {
|
||||
__typename: 'Party',
|
||||
id: 'buyer-id',
|
||||
},
|
||||
seller: {
|
||||
__typename: 'Party',
|
||||
id: 'seller-id',
|
||||
},
|
||||
buyerFee: {
|
||||
__typename: 'TradeFee',
|
||||
makerFee: '100',
|
||||
infrastructureFee: '100',
|
||||
liquidityFee: '100',
|
||||
},
|
||||
sellerFee: {
|
||||
__typename: 'TradeFee',
|
||||
makerFee: '200',
|
||||
infrastructureFee: '200',
|
||||
liquidityFee: '200',
|
||||
},
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'market-id',
|
||||
name: 'UNIDAI Monthly (30 Jun 2022)',
|
||||
positionDecimalPlaces: 0,
|
||||
decimalPlaces: 5,
|
||||
tradableInstrument: {
|
||||
__typename: 'TradableInstrument',
|
||||
instrument: {
|
||||
__typename: 'Instrument',
|
||||
id: 'instrument-id',
|
||||
code: 'instrument-code',
|
||||
product: {
|
||||
__typename: 'Future',
|
||||
settlementAsset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-id',
|
||||
symbol: 'SYM',
|
||||
decimals: 18,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return merge(defaultFill, override);
|
||||
};
|
@ -1,21 +1,68 @@
|
||||
import merge from 'lodash/merge';
|
||||
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
|
||||
export interface Market_market {
|
||||
__typename: 'Market';
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Market {
|
||||
market: Market_market | null;
|
||||
}
|
||||
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
|
||||
import type { Market } from '../../../../trading/pages/markets/__generated__/Market';
|
||||
|
||||
export const generateMarket = (override?: PartialDeep<Market>): Market => {
|
||||
const defaultResult = {
|
||||
const defaultResult: Market = {
|
||||
market: {
|
||||
id: 'market-0',
|
||||
name: 'MARKET NAME',
|
||||
name: 'ACTIVE MARKET',
|
||||
tradingMode: MarketTradingMode.Continuous,
|
||||
state: MarketState.Active,
|
||||
decimalPlaces: 5,
|
||||
data: {
|
||||
market: {
|
||||
id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35',
|
||||
__typename: 'Market',
|
||||
},
|
||||
markPrice: '13739109',
|
||||
indicativeVolume: '0',
|
||||
bestBidVolume: '244',
|
||||
bestOfferVolume: '100',
|
||||
bestStaticBidVolume: '482',
|
||||
bestStaticOfferVolume: '2188',
|
||||
__typename: 'MarketData',
|
||||
},
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
name: 'BTCUSD Monthly',
|
||||
code: 'BTCUSD.MF21',
|
||||
metadata: {
|
||||
tags: [
|
||||
'formerly:076BB86A5AA41E3E',
|
||||
'base:BTC',
|
||||
'quote:USD',
|
||||
'class:fx/crypto',
|
||||
'monthly',
|
||||
'sector:crypto',
|
||||
],
|
||||
__typename: 'InstrumentMetadata',
|
||||
},
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
__typename: 'TradableInstrument',
|
||||
},
|
||||
marketTimestamps: {
|
||||
open: '2022-06-21T17:18:43.484055236Z',
|
||||
close: null,
|
||||
__typename: 'MarketTimestamps',
|
||||
},
|
||||
candles: [
|
||||
{
|
||||
open: '2095312844',
|
||||
close: '2090090607',
|
||||
volume: '4847',
|
||||
__typename: 'Candle',
|
||||
},
|
||||
{
|
||||
open: '2090090000',
|
||||
close: '2090090607',
|
||||
volume: '4847',
|
||||
__typename: 'Candle',
|
||||
},
|
||||
],
|
||||
__typename: 'Market',
|
||||
},
|
||||
};
|
||||
|
@ -21,6 +21,7 @@ export const mockTradingPage = (
|
||||
generateMarket({
|
||||
market: {
|
||||
name: `${state.toUpperCase()} MARKET`,
|
||||
state: state,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user