Chore/1653 full asset details (#1700)

* chore: full list of asset details for dialog

* chore: show full asset details in market info and dialog (1653)

* fixed lint errors
This commit is contained in:
Art 2022-10-11 14:22:55 +02:00 committed by GitHub
parent 503c831018
commit 64c85b2b4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1036 additions and 438 deletions

View File

@ -16,9 +16,36 @@ export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
source: {
__typename: 'ERC20',
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
lifetimeLimit: '1',
withdrawThreshold: '2',
},
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '1',
__typename: 'Account',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'Account',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'Account',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'Account',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'Account',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'Account',
},
__typename: 'Asset',
},
},
{
@ -30,9 +57,36 @@ export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
source: {
__typename: 'ERC20',
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
lifetimeLimit: '1',
withdrawThreshold: '2',
},
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '1',
__typename: 'Account',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'Account',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'Account',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'Account',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'Account',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'Account',
},
__typename: 'Asset',
},
},
{
@ -43,9 +97,20 @@ export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
name: 'Asto',
source: {
__typename: 'BuiltinAsset',
maxFaucetAmountMint: '3',
},
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '0',
__typename: 'Account',
},
globalRewardPoolAccount: null,
takerFeeRewardAccount: null,
makerFeeRewardAccount: null,
lpFeeRewardAccount: null,
marketProposerRewardAccount: null,
__typename: 'Asset',
},
},
],

View File

@ -17,6 +17,7 @@ import type {
} from './__generated__/Delegations';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useContracts } from '../../contexts/contracts/contracts-context';
import type { ERC20Asset } from '@vegaprotocol/assets';
import { isAssetTypeERC20 } from '@vegaprotocol/assets';
import { AccountType } from '@vegaprotocol/types';
@ -118,8 +119,9 @@ export const usePollForDelegations = () => {
.filter((a) => a.type === AccountType.ACCOUNT_TYPE_GENERAL)
.map((a) => {
const isVega =
isAssetTypeERC20(a.asset) &&
a.asset.source.contractAddress === vegaToken.address;
isAssetTypeERC20(a.asset as ERC20Asset) &&
(a.asset as ERC20Asset).source.contractAddress ===
vegaToken.address;
return {
isVega,
@ -132,8 +134,8 @@ export const usePollForDelegations = () => {
),
image: isVega ? vegaBlack : noIcon,
border: isVega,
address: isAssetTypeERC20(a.asset)
? a.asset.source.contractAddress
address: isAssetTypeERC20(a.asset as ERC20Asset)
? (a.asset as ERC20Asset).source.contractAddress
: undefined,
};
})

View File

@ -71,10 +71,20 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
it('settlement asset displayed', () => {
cy.getByTestId(marketTitle).contains('Settlement asset').click();
validateMarketDataRow(0, 'Name', 'tBTC TEST');
validateMarketDataRow(1, 'Symbol', 'tBTC');
validateMarketDataRow(2, 'Asset ID', 'market-0');
validateMarketDataRow(0, 'ID', 'asset-id');
validateMarketDataRow(1, 'Type', 'ERC20');
validateMarketDataRow(2, 'Name', 'Euro');
validateMarketDataRow(3, 'Symbol', 'tEURO');
validateMarketDataRow(4, 'Decimals', '5');
validateMarketDataRow(5, 'Quantum', '1');
validateMarketDataRow(6, 'Status', 'Enabled');
validateMarketDataRow(
7,
'Contract address',
'0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4'
);
validateMarketDataRow(8, 'Withdrawal threshold', '0.00050');
validateMarketDataRow(9, 'Lifetime limit', '1,230.00000');
});
it('metadata displayed', () => {
@ -173,7 +183,9 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
});
afterEach('close toggle', () => {
cy.get('[data-state="open"]').find('button').click();
cy.get('[data-state="open"]').then((tab) => {
if (tab) tab.find('button').trigger('click');
});
});
function validateMarketDataRow(

View File

@ -1,8 +1,59 @@
import merge from 'lodash/merge';
import type { AssetsQuery } from '@vegaprotocol/assets';
import type { AssetQuery, AssetsQuery } from '@vegaprotocol/assets';
import { Schema as Types } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
export const generateAsset = (override?: PartialDeep<AssetQuery>) => {
const defaultAssets: AssetsQuery = {
assetsConnection: {
edges: [
{
node: {
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
name: 'Euro',
source: {
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
lifetimeLimit: '123000000',
withdrawThreshold: '50',
__typename: 'ERC20',
},
quantum: '1',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '1',
__typename: 'Account',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'Account',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'Account',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'Account',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'Account',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'Account',
},
__typename: 'Asset',
},
},
],
},
};
return merge(defaultAssets, override);
};
export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
const defaultAssets: AssetsQuery = {
assetsConnection: {
@ -14,11 +65,38 @@ export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
decimals: 5,
name: 'Euro',
source: {
__typename: 'ERC20',
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
lifetimeLimit: '123000000',
withdrawThreshold: '50',
__typename: 'ERC20',
},
quantum: '1',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '1',
__typename: 'Account',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'Account',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'Account',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'Account',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'Account',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'Account',
},
__typename: 'Asset',
},
},
{
@ -28,11 +106,38 @@ export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
decimals: 5,
name: 'DAI',
source: {
__typename: 'ERC20',
contractAddress: '0x26223f9C67871CFcEa329975f7BC0C9cB8FBDb9b',
lifetimeLimit: '123000000',
withdrawThreshold: '50',
__typename: 'ERC20',
},
quantum: '1',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '1',
__typename: 'Account',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'Account',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'Account',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'Account',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'Account',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'Account',
},
__typename: 'Asset',
},
},
{
@ -42,10 +147,21 @@ export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
decimals: 5,
name: 'Asto',
source: {
maxFaucetAmountMint: '5000000000',
__typename: 'BuiltinAsset',
},
quantum: '1',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '0',
__typename: 'Account',
},
globalRewardPoolAccount: null,
takerFeeRewardAccount: null,
makerFeeRewardAccount: null,
lpFeeRewardAccount: null,
marketProposerRewardAccount: null,
__typename: 'Asset',
},
},
// NOTE: These assets ids and contract addresses are real assets on Sepolia, this is needed
@ -59,10 +175,36 @@ export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
decimals: 5,
status: Types.AssetStatus.STATUS_ENABLED,
source: {
__typename: 'ERC20',
contractAddress: '0x1d525fB145Af5c51766a89706C09fE07E6058D1D',
lifetimeLimit: '123000000',
withdrawThreshold: '50',
__typename: 'ERC20',
},
quantum: '1',
infrastructureFeeAccount: {
balance: '1',
__typename: 'Account',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'Account',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'Account',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'Account',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'Account',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'Account',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
@ -75,10 +217,36 @@ export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
decimals: 5,
status: Types.AssetStatus.STATUS_ENABLED,
source: {
__typename: 'ERC20',
contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d81',
lifetimeLimit: '123000000',
withdrawThreshold: '50',
__typename: 'ERC20',
},
quantum: '1',
infrastructureFeeAccount: {
balance: '1',
__typename: 'Account',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'Account',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'Account',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'Account',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'Account',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'Account',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',

View File

@ -2,7 +2,7 @@ import { aliasQuery } from '@vegaprotocol/cypress';
import type { MarketState } from '@vegaprotocol/types';
import type { CyHttpMessages } from 'cypress/types/net-stubbing';
import { generateAccounts } from './mocks/generate-accounts';
import { generateAssets } from './mocks/generate-assets';
import { generateAsset, generateAssets } from './mocks/generate-assets';
import { generateCandles } from './mocks/generate-candles';
import { generateChart } from './mocks/generate-chart';
import { generateDealTicketQuery } from './mocks/generate-deal-ticket-query';
@ -47,6 +47,7 @@ export const mockTradingPage = (
aliasQuery(req, 'Margins', generateMargins());
aliasQuery(req, 'DealTicket', generateDealTicketQuery({ market: { state } }));
aliasQuery(req, 'Assets', generateAssets());
aliasQuery(req, 'Asset', generateAsset());
aliasQuery(
req,

View File

@ -16,8 +16,9 @@ import {
import { AccountType } from '@vegaprotocol/types';
import type { Market } from '@vegaprotocol/market-list';
import { marketsProvider } from '@vegaprotocol/market-list';
import type { AssetsFieldsFragment } from '@vegaprotocol/assets';
import { assetsProvider } from '@vegaprotocol/assets';
import type { Asset } from '@vegaprotocol/assets';
function isAccount(
account:
@ -41,7 +42,7 @@ export const getId = (
export type Account = Omit<AccountFieldsFragment, 'market' | 'asset'> & {
market?: Market | null;
asset: AssetsFieldsFragment;
asset: Asset;
};
const update = (
@ -167,7 +168,7 @@ export const accountsDataProvider = makeDerivedDataProvider<Account[], never>(
(market: Market) => market.id === account.market?.id
);
const asset = assets.find(
(asset: AssetsFieldsFragment) => asset.id === account.asset?.id
(asset: Asset) => asset.id === account.asset?.id
);
if (asset) {
return {

View File

@ -0,0 +1,47 @@
fragment AssetFields on Asset {
id
name
symbol
decimals
quantum
source {
__typename
... on ERC20 {
contractAddress
lifetimeLimit
withdrawThreshold
}
... on BuiltinAsset {
maxFaucetAmountMint
}
}
status
infrastructureFeeAccount {
balance
}
globalRewardPoolAccount {
balance
}
takerFeeRewardAccount {
balance
}
makerFeeRewardAccount {
balance
}
lpFeeRewardAccount {
balance
}
marketProposerRewardAccount {
balance
}
}
query Asset($assetId: ID!) {
assetsConnection(id: $assetId) {
edges {
node {
...AssetFields
}
}
}
}

View File

@ -1,22 +1,8 @@
fragment AssetsFields on Asset {
id
name
symbol
decimals
quantum
status
source {
... on ERC20 {
contractAddress
}
}
}
query Assets {
assetsConnection {
edges {
node {
...AssetsFields
...AssetFields
}
}
}

View File

@ -0,0 +1,92 @@
import { Schema as Types } from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type AssetFieldsFragment = { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus, source: { __typename: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string }, infrastructureFeeAccount: { __typename?: 'Account', balance: string }, globalRewardPoolAccount?: { __typename?: 'Account', balance: string } | null, takerFeeRewardAccount?: { __typename?: 'Account', balance: string } | null, makerFeeRewardAccount?: { __typename?: 'Account', balance: string } | null, lpFeeRewardAccount?: { __typename?: 'Account', balance: string } | null, marketProposerRewardAccount?: { __typename?: 'Account', balance: string } | null };
export type AssetQueryVariables = Types.Exact<{
assetId: Types.Scalars['ID'];
}>;
export type AssetQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus, source: { __typename: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string }, infrastructureFeeAccount: { __typename?: 'Account', balance: string }, globalRewardPoolAccount?: { __typename?: 'Account', balance: string } | null, takerFeeRewardAccount?: { __typename?: 'Account', balance: string } | null, makerFeeRewardAccount?: { __typename?: 'Account', balance: string } | null, lpFeeRewardAccount?: { __typename?: 'Account', balance: string } | null, marketProposerRewardAccount?: { __typename?: 'Account', balance: string } | null } } | null> | null } | null };
export const AssetFieldsFragmentDoc = gql`
fragment AssetFields on Asset {
id
name
symbol
decimals
quantum
source {
__typename
... on ERC20 {
contractAddress
lifetimeLimit
withdrawThreshold
}
... on BuiltinAsset {
maxFaucetAmountMint
}
}
status
infrastructureFeeAccount {
balance
}
globalRewardPoolAccount {
balance
}
takerFeeRewardAccount {
balance
}
makerFeeRewardAccount {
balance
}
lpFeeRewardAccount {
balance
}
marketProposerRewardAccount {
balance
}
}
`;
export const AssetDocument = gql`
query Asset($assetId: ID!) {
assetsConnection(id: $assetId) {
edges {
node {
...AssetFields
}
}
}
}
${AssetFieldsFragmentDoc}`;
/**
* __useAssetQuery__
*
* To run a query within a React component, call `useAssetQuery` and pass it any options that fit your needs.
* When your component renders, `useAssetQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useAssetQuery({
* variables: {
* assetId: // value for 'assetId'
* },
* });
*/
export function useAssetQuery(baseOptions: Apollo.QueryHookOptions<AssetQuery, AssetQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<AssetQuery, AssetQueryVariables>(AssetDocument, options);
}
export function useAssetLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AssetQuery, AssetQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<AssetQuery, AssetQueryVariables>(AssetDocument, options);
}
export type AssetQueryHookResult = ReturnType<typeof useAssetQuery>;
export type AssetLazyQueryHookResult = ReturnType<typeof useAssetLazyQuery>;
export type AssetQueryResult = Apollo.QueryResult<AssetQuery, AssetQueryVariables>;

View File

@ -1,41 +1,26 @@
import { Schema as Types } from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import { AssetFieldsFragmentDoc } from './Asset';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type AssetsFieldsFragment = { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string } };
export type AssetsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type AssetsQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string } } } | null> | null } | null };
export type AssetsQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus, source: { __typename: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string }, infrastructureFeeAccount: { __typename?: 'Account', balance: string }, globalRewardPoolAccount?: { __typename?: 'Account', balance: string } | null, takerFeeRewardAccount?: { __typename?: 'Account', balance: string } | null, makerFeeRewardAccount?: { __typename?: 'Account', balance: string } | null, lpFeeRewardAccount?: { __typename?: 'Account', balance: string } | null, marketProposerRewardAccount?: { __typename?: 'Account', balance: string } | null } } | null> | null } | null };
export const AssetsFieldsFragmentDoc = gql`
fragment AssetsFields on Asset {
id
name
symbol
decimals
quantum
status
source {
... on ERC20 {
contractAddress
}
}
}
`;
export const AssetsDocument = gql`
query Assets {
assetsConnection {
edges {
node {
...AssetsFields
...AssetFields
}
}
}
}
${AssetsFieldsFragmentDoc}`;
${AssetFieldsFragmentDoc}`;
/**
* __useAssetsQuery__

View File

@ -0,0 +1,39 @@
import { makeDataProvider, useDataProvider } from '@vegaprotocol/react-helpers';
import { useMemo } from 'react';
import type { AssetQuery, AssetFieldsFragment } from './__generated___/Asset';
import { AssetDocument } from './__generated___/Asset';
export type Asset = AssetFieldsFragment;
const getData = (responseData: AssetQuery) => {
const foundAssets = responseData.assetsConnection?.edges
?.filter((e) => Boolean(e?.node))
.map((e) => e?.node as Asset);
if (foundAssets && foundAssets?.length > 0) return foundAssets[0];
return null;
};
export const assetProvider = makeDataProvider<
AssetQuery,
Asset | null,
never,
never
>({
query: AssetDocument,
getData,
});
export const useAssetDataProvider = (assetId: string) => {
const variables = useMemo(
() => ({
assetId,
}),
[assetId]
);
return useDataProvider({
dataProvider: assetProvider,
variables,
skip: !assetId,
});
};

View File

@ -1,267 +1,33 @@
import { MockedProvider } from '@apollo/react-testing';
import { render, screen } from '@testing-library/react';
import { AssetStatus } from '@vegaprotocol/types';
import { AssetDetailsDialog } from './asset-details-dialog';
import { AssetDetail, testId } from './asset-details-table';
import { AssetsDocument } from './__generated___/Assets';
import { generateBuiltinAsset, generateERC20Asset } from './test-helpers';
const mockedData = {
data: {
assetsConnection: {
edges: [
{
node: {
id: 'XYZalpha',
name: 'XYZ (α alpha)',
symbol: 'XYZalpha',
decimals: 5,
quantum: '1',
source: {
__typename: 'BuiltinAsset',
},
__typename: 'Asset',
},
node: generateERC20Asset(1, AssetStatus.STATUS_ENABLED),
__typename: 'AssetEdge',
},
{
node: {
id: 'XYZbeta',
name: 'XYZ (β beta)',
symbol: 'XYZbeta',
decimals: 5,
quantum: '1',
source: {
__typename: 'BuiltinAsset',
},
__typename: 'Asset',
},
node: generateBuiltinAsset(1, AssetStatus.STATUS_ENABLED),
__typename: 'AssetEdge',
},
{
node: {
id: 'XYZdelta',
name: 'XYZ (δ delta)',
symbol: 'XYZdelta',
decimals: 5,
quantum: '1',
source: {
__typename: 'BuiltinAsset',
},
__typename: 'Asset',
},
node: generateBuiltinAsset(2, AssetStatus.STATUS_PENDING_LISTING),
__typename: 'AssetEdge',
},
{
node: {
id: 'XYZepsilon',
name: 'XYZ (ε epsilon)',
symbol: 'XYZepsilon',
decimals: 5,
quantum: '1',
source: {
__typename: 'BuiltinAsset',
},
__typename: 'Asset',
},
node: generateBuiltinAsset(3, AssetStatus.STATUS_PROPOSED),
__typename: 'AssetEdge',
},
{
node: {
id: 'XYZgamma',
name: 'XYZ (γ gamma)',
symbol: 'XYZgamma',
decimals: 5,
quantum: '1',
source: {
__typename: 'BuiltinAsset',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: '2282ffc06a557173d297739305cc69f6444cdbbb1089df7d9aef32bbfd735ba1',
name: 'Tim Token (Vega)',
symbol: 'TIM',
decimals: 18,
quantum: '1',
source: {
contractAddress: '0x920B2375BCAC8cCDfDEFD74426c55C48e0304e4F',
lifetimeLimit: '0',
withdrawThreshold: '0',
__typename: 'ERC20',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: '449dbfb66e7a444c485b4fdc77ddc6bbf81abbf7c8e247ac299c25e9557b99cf',
name: 'Taker Reward Token (Vega)',
symbol: 'TAK',
decimals: 18,
quantum: '1',
source: {
contractAddress: '0xf700Ce952B6EA11c01b43e5579C6D63286ff8CF0',
lifetimeLimit: '0',
withdrawThreshold: '0',
__typename: 'ERC20',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
name: 'tBTC TEST',
symbol: 'tBTC',
decimals: 5,
quantum: '1',
source: {
contractAddress: '0xC912F059b4eCCEF6C969B2E0e2544A1A2581C094',
lifetimeLimit: '0',
withdrawThreshold: '0',
__typename: 'ERC20',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
name: 'tDAI TEST',
symbol: 'tDAI',
decimals: 5,
quantum: '1',
source: {
contractAddress: '0xF4A2bcC43D24D14C4189Ef45fCf681E870675333',
lifetimeLimit: '0',
withdrawThreshold: '0',
__typename: 'ERC20',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
name: 'tEURO TEST',
symbol: 'tEURO',
decimals: 5,
quantum: '1',
source: {
contractAddress: '0xD52b6C949E35A6E4C64b987B1B192A8608931a7b',
lifetimeLimit: '0',
withdrawThreshold: '0',
__typename: 'ERC20',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: '98032ba34576f8012de9b822e1da3ed4b6223a4f4e05f573002d441ffb4bf314',
name: 'Liquidity Reward Token (Vega)',
symbol: 'LIQ',
decimals: 18,
quantum: '1',
source: {
contractAddress: '0xD2f21E37e78dD91b60FE3dD74A112e1a53b33057',
lifetimeLimit: '0',
withdrawThreshold: '0',
__typename: 'ERC20',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: '993ed98f4f770d91a796faab1738551193ba45c62341d20597df70fea6704ede',
name: 'tUSDC TEST',
symbol: 'tUSDC',
decimals: 5,
quantum: '1',
source: {
contractAddress: '0x3773A5c7aFF77e014cBF067dd31801b4C6dc4136',
lifetimeLimit: '0',
withdrawThreshold: '0',
__typename: 'ERC20',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: 'ba98cdeeec849a053e60cc03808e91e90d9d2e62425c76a590617b95ad41a066',
name: 'Steve Token (Vega)',
symbol: 'STE',
decimals: 18,
quantum: '1',
source: {
contractAddress: '0x5a16941cca2Db4AcdFC28Ac77a3e9652Fdf102e1',
lifetimeLimit: '0',
withdrawThreshold: '0',
__typename: 'ERC20',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: 'ce3fb1ab0717f0adbce019d7aef53aacdbadefe2d30ad1647b55f134d4072c90',
name: 'Woz Token (Vega)',
symbol: 'WOZ',
decimals: 18,
quantum: '1',
source: {
contractAddress: '0x5E4b9aDA947130Fc320a144cd22bC1641e5c9d81',
lifetimeLimit: '0',
withdrawThreshold: '0',
__typename: 'ERC20',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: 'ebcd94151ae1f0d39a4bde3b21a9c7ae81a80ea4352fb075a92e07608d9c953d',
name: 'Maker Reward Token (Vega)',
symbol: 'MAK',
decimals: 18,
quantum: '1',
source: {
contractAddress: '0x8ec701DA58394F5d2c8C2873D31039454D5845C1',
lifetimeLimit: '1000000000000',
withdrawThreshold: '0',
__typename: 'ERC20',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: 'fc7fd956078fb1fc9db5c19b88f0874c4299b2a7639ad05a47a28c0aef291b55',
name: 'Vega (testnet)',
symbol: 'VEGA',
decimals: 18,
quantum: '1',
source: {
contractAddress: '0xDc335304979D378255015c33AbFf09B60c31EBAb',
lifetimeLimit: '0',
withdrawThreshold: '100000000',
__typename: 'ERC20',
},
__typename: 'Asset',
},
node: generateBuiltinAsset(4, AssetStatus.STATUS_REJECTED),
__typename: 'AssetEdge',
},
],
@ -295,26 +61,122 @@ const WrappedAssetDetailsDialog = ({
);
describe('AssetDetailsDialog', () => {
it('should show no data message given unknown asset symbol', () => {
it('should show no data message given unknown asset symbol', async () => {
render(<WrappedAssetDetailsDialog assetSymbol={'UNKNOWN_FOR_SURE'} />);
expect(screen.getByText('No data')).toBeInTheDocument();
expect((await screen.findByTestId('splash')).textContent).toContain(
'No data'
);
});
const cases = [
['tDAI', 'tDAI', 'tDAI TEST', '21,000,000'],
['VEGA', 'VEGA', 'Vega (testnet)', '64,999,723,000,000,000,000,000,000'],
['tUSDC', 'tUSDC', 'tUSDC TEST', '21,000,000'],
const cases: [string, { key: AssetDetail; value: string }[]][] = [
[
'EA01',
[
{ key: AssetDetail.ID, value: 'E-01' },
{ key: AssetDetail.TYPE, value: 'ERC20' },
{ key: AssetDetail.NAME, value: 'ERC20 01' },
{ key: AssetDetail.SYMBOL, value: 'EA01' },
{ key: AssetDetail.DECIMALS, value: '3' },
{ key: AssetDetail.QUANTUM, value: '1' },
{ key: AssetDetail.STATUS, value: 'Enabled' },
{ key: AssetDetail.CONTRACT_ADDRESS, value: '0x123' },
{ key: AssetDetail.WITHDRAWAL_THRESHOLD, value: '0.050' },
{ key: AssetDetail.LIFETIME_LIMIT, value: '123,000.000' },
{
key: AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
value: '0.001',
},
{
key: AssetDetail.GLOBAL_REWARD_POOL_ACCOUNT_BALANCE,
value: '0.002',
},
{ key: AssetDetail.TAKER_FEE_REWARD_ACCOUNT_BALANCE, value: '0.003' },
{ key: AssetDetail.MAKER_FEE_REWARD_ACCOUNT_BALANCE, value: '0.004' },
{ key: AssetDetail.LP_FEE_REWARD_ACCOUNT_BALANCE, value: '0.005' },
{
key: AssetDetail.MARKET_PROPOSER_REWARD_ACCOUNT_BALANCE,
value: '0.006',
},
],
],
[
'BIA01',
[
{ key: AssetDetail.ID, value: 'B-01' },
{ key: AssetDetail.TYPE, value: 'Builtin asset' },
{ key: AssetDetail.NAME, value: 'Builtin 01' },
{ key: AssetDetail.SYMBOL, value: 'BIA01' },
{ key: AssetDetail.DECIMALS, value: '5' },
{ key: AssetDetail.QUANTUM, value: '1' },
{ key: AssetDetail.STATUS, value: 'Enabled' },
{ key: AssetDetail.MAX_FAUCET_AMOUNT_MINT, value: '50,000.00000' },
{
key: AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
value: '0.00000',
},
],
],
[
'BIA02',
[
{ key: AssetDetail.ID, value: 'B-02' },
{ key: AssetDetail.TYPE, value: 'Builtin asset' },
{ key: AssetDetail.NAME, value: 'Builtin 02' },
{ key: AssetDetail.SYMBOL, value: 'BIA02' },
{ key: AssetDetail.DECIMALS, value: '5' },
{ key: AssetDetail.QUANTUM, value: '1' },
{ key: AssetDetail.STATUS, value: 'Pending listing' },
{ key: AssetDetail.MAX_FAUCET_AMOUNT_MINT, value: '50,000.00000' },
{
key: AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
value: '0.00000',
},
],
],
[
'BIA03',
[
{ key: AssetDetail.ID, value: 'B-03' },
{ key: AssetDetail.TYPE, value: 'Builtin asset' },
{ key: AssetDetail.NAME, value: 'Builtin 03' },
{ key: AssetDetail.SYMBOL, value: 'BIA03' },
{ key: AssetDetail.DECIMALS, value: '5' },
{ key: AssetDetail.QUANTUM, value: '1' },
{ key: AssetDetail.STATUS, value: 'Proposed' },
{ key: AssetDetail.MAX_FAUCET_AMOUNT_MINT, value: '50,000.00000' },
{
key: AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
value: '0.00000',
},
],
],
[
'BIA04',
[
{ key: AssetDetail.ID, value: 'B-04' },
{ key: AssetDetail.TYPE, value: 'Builtin asset' },
{ key: AssetDetail.NAME, value: 'Builtin 04' },
{ key: AssetDetail.SYMBOL, value: 'BIA04' },
{ key: AssetDetail.DECIMALS, value: '5' },
{ key: AssetDetail.QUANTUM, value: '1' },
{ key: AssetDetail.STATUS, value: 'Rejected' },
{ key: AssetDetail.MAX_FAUCET_AMOUNT_MINT, value: '50,000.00000' },
{
key: AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
value: '0.00000',
},
],
],
];
it.each(cases)(
'should show correct data given %p symbol',
async (requestedSymbol, symbol, name, totalSupply) => {
render(<WrappedAssetDetailsDialog assetSymbol={requestedSymbol} />);
expect((await screen.findByTestId('symbol_value')).textContent).toContain(
symbol
);
expect((await screen.findByTestId('name_value')).textContent).toContain(
name
);
async (symbol, details) => {
render(<WrappedAssetDetailsDialog assetSymbol={symbol} />);
for (const detail of details) {
expect(
(await screen.findByTestId(testId(detail.key, 'value'))).textContent
).toContain(detail.value);
}
}
);
});

View File

@ -1,21 +1,9 @@
import {
addDecimalsFormatNumber,
t,
useDataProvider,
} from '@vegaprotocol/react-helpers';
import type { Asset } from './assets-data-provider';
import {
Button,
Dialog,
Icon,
KeyValueTable,
KeyValueTableRow,
Splash,
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import { assetsProvider } from './assets-data-provider';
import type { Schema } from '@vegaprotocol/types';
import { t } from '@vegaprotocol/react-helpers';
import { useAssetsDataProvider } from './assets-data-provider';
import { Button, Dialog, Icon, Splash } from '@vegaprotocol/ui-toolkit';
import create from 'zustand';
import { AssetDetailsTable } from './asset-details-table';
import type { Asset } from './asset-data-provider';
export type AssetDetailsDialogStore = {
isOpen: boolean;
@ -43,117 +31,30 @@ export const useAssetDetailsDialogStore = create<AssetDetailsDialogStore>(
})
);
type AssetDetails = {
key: string;
label: string;
value: string;
tooltip: string;
}[];
export interface AssetDetailsDialogProps {
assetSymbol: string | Asset;
trigger?: HTMLElement | null;
open: boolean;
onChange: (open: boolean) => void;
}
export const AssetDetailsDialog = ({
assetSymbol,
trigger,
open,
onChange,
}: AssetDetailsDialogProps) => {
const { data } = useDataProvider({ dataProvider: assetsProvider });
const { data } = useAssetsDataProvider();
const symbol =
typeof assetSymbol === 'string' ? assetSymbol : assetSymbol.symbol;
const asset = data?.find((a) => a?.symbol === symbol);
let details: AssetDetails = [];
if (asset != null) {
details = [
{
key: 'name',
label: t('Name'),
value: asset.name,
tooltip: '', // t('Name of the asset (e.g: Great British Pound)')
},
{
key: 'symbol',
label: t('Symbol'),
value: asset.symbol,
tooltip: '', // t('Symbol of the asset (e.g: GBP)')
},
{
key: 'decimals',
label: t('Decimals'),
value: asset.decimals.toString(),
tooltip: t('Number of decimal / precision handled by this asset'),
},
{
key: 'quantum',
label: t('Quantum'),
value: asset.quantum,
tooltip: t('The minimum economically meaningful amount in the asset'),
},
{
key: 'contractaddress',
label: t('Contract address'),
value: (asset.source as Schema.ERC20).contractAddress,
tooltip: t(
'The address of the contract for the token, on the ethereum network'
),
},
{
key: 'withdrawalthreshold',
label: t('Withdrawal threshold'),
value: addDecimalsFormatNumber(
(asset.source as Schema.ERC20).withdrawThreshold,
asset.decimals
),
tooltip: t(
'The maximum allowed per withdraw note: this is a temporary measure for restricted mainnet'
),
},
{
key: 'lifetimelimit',
label: t('Lifetime limit'),
value: addDecimalsFormatNumber(
(asset.source as Schema.ERC20).lifetimeLimit,
asset.decimals
),
tooltip: t(
'The lifetime limits deposit per address note: this is a temporary measure for restricted mainnet'
),
},
];
}
const content = asset ? (
<div className="my-2">
<KeyValueTable>
{details
.filter(({ value }) => value && value.length > 0)
.map(({ key, label, value, tooltip }) => (
<KeyValueTableRow key={key}>
<div
data-testid={`${key}_label`}
className="first-letter:uppercase"
>
{tooltip.length > 0 ? (
<Tooltip description={tooltip}>
<span>{label}</span>
</Tooltip>
) : (
<span>{label}</span>
)}
</div>
<div data-testid={`${key}_value`}>{value}</div>
</KeyValueTableRow>
))}
</KeyValueTable>
<AssetDetailsTable asset={asset} />
</div>
) : (
<div className="py-12">
<div className="py-12" data-testid="splash">
<Splash>{t('No data')}</Splash>
</div>
);
@ -183,7 +84,7 @@ export const AssetDetailsDialog = ({
size="sm"
onClick={() => onChange(false)}
>
Close
{t('Close')}
</Button>
</div>
</Dialog>

View File

@ -0,0 +1,80 @@
import { render, screen } from '@testing-library/react';
import { AssetStatus } from '@vegaprotocol/types';
import type { Asset } from './asset-data-provider';
import {
AssetDetail,
AssetDetailsTable,
rows,
testId,
} from './asset-details-table';
import { generateBuiltinAsset, generateERC20Asset } from './test-helpers';
describe('AssetDetailsTable', () => {
const cases: [string, Asset, { key: AssetDetail; value: string }[]][] = [
[
'ERC20 asset',
generateERC20Asset(1, AssetStatus.STATUS_ENABLED),
[
{ key: AssetDetail.ID, value: 'E-01' },
{ key: AssetDetail.TYPE, value: 'ERC20' },
{ key: AssetDetail.NAME, value: 'ERC20 01' },
{ key: AssetDetail.SYMBOL, value: 'EA01' },
{ key: AssetDetail.DECIMALS, value: '3' },
{ key: AssetDetail.QUANTUM, value: '1' },
{ key: AssetDetail.STATUS, value: 'Enabled' },
{ key: AssetDetail.CONTRACT_ADDRESS, value: '0x123' },
{ key: AssetDetail.WITHDRAWAL_THRESHOLD, value: '0.050' },
{ key: AssetDetail.LIFETIME_LIMIT, value: '123,000.000' },
{
key: AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
value: '0.001',
},
{
key: AssetDetail.GLOBAL_REWARD_POOL_ACCOUNT_BALANCE,
value: '0.002',
},
{ key: AssetDetail.TAKER_FEE_REWARD_ACCOUNT_BALANCE, value: '0.003' },
{ key: AssetDetail.MAKER_FEE_REWARD_ACCOUNT_BALANCE, value: '0.004' },
{ key: AssetDetail.LP_FEE_REWARD_ACCOUNT_BALANCE, value: '0.005' },
{
key: AssetDetail.MARKET_PROPOSER_REWARD_ACCOUNT_BALANCE,
value: '0.006',
},
],
],
[
'Builtin asset',
generateBuiltinAsset(1, AssetStatus.STATUS_ENABLED),
[
{ key: AssetDetail.ID, value: 'B-01' },
{ key: AssetDetail.TYPE, value: 'Builtin asset' },
{ key: AssetDetail.NAME, value: 'Builtin 01' },
{ key: AssetDetail.SYMBOL, value: 'BIA01' },
{ key: AssetDetail.DECIMALS, value: '5' },
{ key: AssetDetail.QUANTUM, value: '1' },
{ key: AssetDetail.STATUS, value: 'Enabled' },
{ key: AssetDetail.MAX_FAUCET_AMOUNT_MINT, value: '50,000.00000' },
{
key: AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
value: '0.00000',
},
],
],
];
it.each(cases)(
"displays the available asset's data of %p with correct labels",
async (_type, asset, details) => {
render(<AssetDetailsTable asset={asset} />);
for (const detail of details) {
expect(
await (
await screen.findByTestId(testId(detail.key, 'label'))
).textContent
).toContain(rows.find((r) => r.key === detail.key)?.label);
expect(
(await screen.findByTestId(testId(detail.key, 'value'))).textContent
).toContain(detail.value);
}
}
);
});

View File

@ -0,0 +1,251 @@
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
import type { Schema } from '@vegaprotocol/types';
import type { KeyValueTableRowProps } from '@vegaprotocol/ui-toolkit';
import {
KeyValueTable,
KeyValueTableRow,
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import type { Asset } from './asset-data-provider';
type Rows = {
key: AssetDetail;
label: string;
tooltip: string;
value: (asset: Asset) => string | null | undefined;
valueTooltip?: (asset: Asset) => string | null | undefined;
}[];
export enum AssetDetail {
ID,
TYPE,
NAME,
SYMBOL,
DECIMALS,
QUANTUM,
STATUS,
// erc20 details:
CONTRACT_ADDRESS,
WITHDRAWAL_THRESHOLD,
LIFETIME_LIMIT,
// builtin details:
MAX_FAUCET_AMOUNT_MINT,
// balances:
INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
GLOBAL_REWARD_POOL_ACCOUNT_BALANCE,
TAKER_FEE_REWARD_ACCOUNT_BALANCE,
MAKER_FEE_REWARD_ACCOUNT_BALANCE,
LP_FEE_REWARD_ACCOUNT_BALANCE,
MARKET_PROPOSER_REWARD_ACCOUNT_BALANCE,
}
type Mapping = { [key in string]: { value: string; tooltip: string } };
const num = (asset: Asset, n: string | undefined | null) => {
if (typeof n === 'undefined' || n == null) return '';
return addDecimalsFormatNumber(n, asset.decimals);
};
export const rows: Rows = [
{
key: AssetDetail.ID,
label: t('ID'),
tooltip: '',
value: (asset) => asset.id,
},
{
key: AssetDetail.TYPE,
label: t('Type'),
tooltip: '',
value: (asset) => AssetTypeMapping[asset.source.__typename].value,
valueTooltip: (asset) => AssetTypeMapping[asset.source.__typename].tooltip,
},
{
key: AssetDetail.NAME,
label: t('Name'),
tooltip: '',
value: (asset) => asset.name,
},
{
key: AssetDetail.SYMBOL,
label: t('Symbol'),
tooltip: '',
value: (asset) => asset.symbol,
},
{
key: AssetDetail.DECIMALS,
label: t('Decimals'),
tooltip: t('Number of decimal / precision handled by this asset'),
value: (asset) => asset.decimals.toString(),
},
{
key: AssetDetail.QUANTUM,
label: t('Quantum'),
tooltip: t('The minimum economically meaningful amount in the asset'),
value: (asset) => asset.quantum,
},
{
key: AssetDetail.STATUS,
label: t('Status'),
tooltip: t('The status of the asset in the Vega network'),
value: (asset) => AssetStatusMapping[asset.status].value,
valueTooltip: (asset) => AssetStatusMapping[asset.status].tooltip,
},
{
key: AssetDetail.CONTRACT_ADDRESS,
label: t('Contract address'),
tooltip: t(
'The address of the contract for the token, on the ethereum network'
),
value: (asset) => (asset.source as Schema.ERC20).contractAddress,
},
{
key: AssetDetail.WITHDRAWAL_THRESHOLD,
label: t('Withdrawal threshold'),
tooltip: t(
'The maximum allowed per withdraw note: this is a temporary measure for restricted mainnet'
),
value: (asset) =>
num(asset, (asset.source as Schema.ERC20).withdrawThreshold),
},
{
key: AssetDetail.LIFETIME_LIMIT,
label: t('Lifetime limit'),
tooltip: t(
'The lifetime limits deposit per address note: this is a temporary measure for restricted mainnet'
),
value: (asset) => num(asset, (asset.source as Schema.ERC20).lifetimeLimit),
},
{
key: AssetDetail.MAX_FAUCET_AMOUNT_MINT,
label: t('Max faucet amount'),
tooltip: t(
'Maximum amount that can be requested by a party through the built-in asset faucet at a time'
),
value: (asset) =>
num(asset, (asset.source as Schema.BuiltinAsset).maxFaucetAmountMint),
},
{
key: AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
label: t('Infrastructure fee account balance'),
tooltip: t('The infrastructure fee account for this asset'),
value: (asset) => num(asset, asset.infrastructureFeeAccount.balance),
},
{
key: AssetDetail.GLOBAL_REWARD_POOL_ACCOUNT_BALANCE,
label: t('Global reward pool account balance'),
tooltip: t('The global reward pool account for this asset'),
value: (asset) => num(asset, asset.globalRewardPoolAccount?.balance),
},
{
key: AssetDetail.TAKER_FEE_REWARD_ACCOUNT_BALANCE,
label: t('Taker fee reward account balance'),
tooltip: t('The taker fee reward account for this asset'),
value: (asset) => num(asset, asset.takerFeeRewardAccount?.balance),
},
{
key: AssetDetail.MAKER_FEE_REWARD_ACCOUNT_BALANCE,
label: t('Maker fee reward account balance'),
tooltip: t('The maker fee reward account for this asset'),
value: (asset) => num(asset, asset.makerFeeRewardAccount?.balance),
},
{
key: AssetDetail.LP_FEE_REWARD_ACCOUNT_BALANCE,
label: t('Liquidity provision fee reward account balance'),
tooltip: t('The liquidity provision reward account for this asset'),
value: (asset) => num(asset, asset.lpFeeRewardAccount?.balance),
},
{
key: AssetDetail.MARKET_PROPOSER_REWARD_ACCOUNT_BALANCE,
label: t('Market proposer reward account balance'),
tooltip: t('The market proposer reward account for this asset'),
value: (asset) => num(asset, asset.marketProposerRewardAccount?.balance),
},
];
const AssetStatusMapping: Mapping = {
STATUS_ENABLED: {
value: t('Enabled'),
tooltip: t('Asset can be used on the Vega network'),
},
STATUS_PENDING_LISTING: {
value: t('Pending listing'),
tooltip: t('Asset is pending listing on the ethereum bridge'),
},
STATUS_PROPOSED: {
value: t('Proposed'),
tooltip: t('Asset is proposed to be added to the network'),
},
STATUS_REJECTED: {
value: t('Rejected'),
tooltip: t('Asset has been rejected'),
},
};
const AssetTypeMapping: Mapping = {
BuiltinAsset: {
value: 'Builtin asset',
tooltip: t('A Vega builtin asset'),
},
ERC20: {
value: 'ERC20',
tooltip: t('An asset originated from an Ethereum ERC20 Token'),
},
};
export const testId = (detail: AssetDetail, field: 'label' | 'value') =>
`${detail}_${field}`;
export type AssetDetailsTableProps = {
asset: Asset;
} & Omit<KeyValueTableRowProps, 'children'>;
export const AssetDetailsTable = ({
asset,
...props
}: AssetDetailsTableProps) => {
const longStringModifiers = (key: AssetDetail, value: string) =>
(value && key === AssetDetail.CONTRACT_ADDRESS) || key === AssetDetail.ID
? { className: 'truncate', title: value }
: {};
const details = rows.map((r) => ({
...r,
value: r.value(asset),
valueTooltip: r.valueTooltip?.(asset),
}));
return (
<KeyValueTable>
{details
.filter(({ value }) => value && value.length > 0)
.map(({ key, label, value, tooltip, valueTooltip }) => (
<KeyValueTableRow key={key} {...props}>
<div
data-testid={testId(key, 'label')}
className="first-letter:uppercase"
>
{tooltip.length > 0 ? (
<Tooltip description={tooltip}>
<span>{label}</span>
</Tooltip>
) : (
<span>{label}</span>
)}
</div>
<div
data-testid={testId(key, 'value')}
{...longStringModifiers(key, value as string)}
>
{valueTooltip && valueTooltip?.length > 0 ? (
<Tooltip description={valueTooltip}>
<span>{value}</span>
</Tooltip>
) : (
value
)}
</div>
</KeyValueTableRow>
))}
</KeyValueTable>
);
};

View File

@ -1,19 +1,18 @@
import {
makeDataProvider,
makeDerivedDataProvider,
useDataProvider,
} from '@vegaprotocol/react-helpers';
import { AssetsDocument } from './__generated___/Assets';
import { AssetStatus } from '@vegaprotocol/types';
import type {
AssetsQuery,
AssetsFieldsFragment,
} from './__generated___/Assets';
export type Asset = AssetsFieldsFragment;
import type { AssetsQuery } from './__generated___/Assets';
import type { Asset } from './asset-data-provider';
export interface ERC20AssetSource {
__typename: 'ERC20';
contractAddress: string;
lifetimeLimit: string;
withdrawThreshold: string;
}
export interface BuiltinAssetSource {
@ -58,3 +57,8 @@ export const enabledAssetsProvider = makeDerivedDataProvider<
(a) => a.status === AssetStatus.STATUS_ENABLED
)
);
export const useAssetsDataProvider = () =>
useDataProvider({
dataProvider: assetsProvider,
});

View File

@ -1,3 +1,6 @@
export * from './__generated___/Asset';
export * from './__generated___/Assets';
export * from './asset-data-provider';
export * from './assets-data-provider';
export * from './asset-details-dialog';
export * from './asset-details-table';

View File

@ -0,0 +1,68 @@
import type { AssetStatus } from '@vegaprotocol/types';
import type { Asset } from './asset-data-provider';
export const generateERC20Asset = (i: number, status: AssetStatus): Asset => ({
id: `E-0${i}`,
name: `ERC20 0${i}`,
symbol: `EA0${i}`,
decimals: 3,
quantum: '1',
source: {
contractAddress: '0x123',
lifetimeLimit: '123000000',
withdrawThreshold: '50',
__typename: 'ERC20',
},
status: status,
infrastructureFeeAccount: {
balance: '1',
__typename: 'Account',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'Account',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'Account',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'Account',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'Account',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'Account',
},
__typename: 'Asset',
});
export const generateBuiltinAsset = (
i: number,
status: AssetStatus
): Asset => ({
id: `B-0${i}`,
name: `Builtin 0${i}`,
symbol: `BIA0${i}`,
decimals: 5,
quantum: '1',
source: {
maxFaucetAmountMint: '5000000000',
__typename: 'BuiltinAsset',
},
status: status,
infrastructureFeeAccount: {
balance: '0',
__typename: 'Account',
},
globalRewardPoolAccount: null,
takerFeeRewardAccount: null,
makerFeeRewardAccount: null,
lpFeeRewardAccount: null,
marketProposerRewardAccount: null,
__typename: 'Asset',
});

View File

@ -23,6 +23,7 @@ import { generatePath } from 'react-router-dom';
import { useEnvironment } from '@vegaprotocol/environment';
import { Link as UiToolkitLink } from '@vegaprotocol/ui-toolkit';
import Link from 'next/link';
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
const Links = {
PROPOSAL_PAGE: ':tokenUrl/governance/:proposalId',
@ -92,6 +93,11 @@ export const Info = ({ market, onSelect }: InfoProps) => {
const dayVolume = calcCandleVolume(market);
const assetSymbol =
market.tradableInstrument.instrument.product?.settlementAsset.symbol;
const assetId = useMemo(
() => market.tradableInstrument.instrument.product?.settlementAsset.id,
[market]
);
const { data: asset } = useAssetDataProvider(assetId);
const marketDataPanels = [
{
title: t('Current fees'),
@ -201,18 +207,16 @@ export const Info = ({ market, onSelect }: InfoProps) => {
},
{
title: t('Settlement asset'),
content: (
<MarketInfoTable
data={{
name: market.tradableInstrument.instrument.product?.settlementAsset
.name,
symbol:
market.tradableInstrument.instrument.product?.settlementAsset
.symbol,
assetID:
market.tradableInstrument.instrument.product?.settlementAsset.id,
}}
content: asset ? (
<AssetDetailsTable
asset={asset}
inline={true}
noBorder={true}
dtClassName="text-black dark:text-white text-ui !px-0 !font-normal"
ddClassName="text-black dark:text-white text-ui !px-0 !font-normal max-w-full"
/>
) : (
<Splash>{t('No data')}</Splash>
),
},
{

View File

@ -11,7 +11,6 @@ import type { Withdrawals_party_withdrawalsConnection_edges_node } from './__gen
export const generateAsset = (override?: PartialDeep<Asset>) => {
const defaultAsset: Asset = {
__typename: 'Asset',
id: 'asset-id',
symbol: 'asset-symbol',
name: 'asset-name',
@ -19,9 +18,36 @@ export const generateAsset = (override?: PartialDeep<Asset>) => {
decimals: 5,
status: AssetStatus.STATUS_ENABLED,
source: {
__typename: 'ERC20',
contractAddress: 'contract-address',
lifetimeLimit: '123000000',
withdrawThreshold: '50',
__typename: 'ERC20',
},
infrastructureFeeAccount: {
balance: '1',
__typename: 'Account',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'Account',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'Account',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'Account',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'Account',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'Account',
},
__typename: 'Asset',
};
return merge(defaultAsset, override);
};

View File

@ -11,6 +11,7 @@ import type {
Erc20ApprovalVariables,
} from './__generated__/Erc20Approval';
import { useApolloClient } from '@apollo/client';
import type { ERC20Asset } from '@vegaprotocol/assets';
export enum ApprovalStatus {
Idle = 'Idle',
@ -80,7 +81,7 @@ export const useVerifyWithdrawal = () => {
addDecimal(withdrawal.amount, withdrawal.asset.decimals)
);
const threshold = await getThreshold(withdrawal.asset);
const threshold = await getThreshold(withdrawal.asset as ERC20Asset);
if (threshold && amount.isGreaterThan(threshold)) {
const delaySecs = await getDelay();