Test/expand explorer tests to include parties page (#1530)
* test: parties test suite * test: lint * test: improve error handling * test: lint * test: extra error handling and deletion of redundant curl params * test: lint * test: lint * test: update * test: skip test * test: tweaks * test: lint * test: lint
This commit is contained in:
parent
f743828cb5
commit
edb31e0f46
@ -27,9 +27,14 @@ module.exports = defineConfig({
|
||||
networkQueryUrl: 'http://localhost:3028/query',
|
||||
ethUrl: 'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
|
||||
commitHash: 'dev',
|
||||
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: true,
|
||||
tsConfig: 'tsconfig.json',
|
||||
grepTags: '@regression @smoke @slow',
|
||||
grepFilterSpecs: true,
|
||||
grepOmitFiltered: true,
|
||||
vegaWalletName: 'capsule_wallet',
|
||||
vegaWalletLocation: '~/.vegacapsule/testnet/wallet',
|
||||
vegaWalletPublicKey:
|
||||
'02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65',
|
||||
},
|
||||
});
|
||||
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io"
|
||||
}
|
1
apps/explorer-e2e/src/fixtures/wallet/passphrase
Normal file
1
apps/explorer-e2e/src/fixtures/wallet/passphrase
Normal file
@ -0,0 +1 @@
|
||||
123
|
1
apps/explorer-e2e/src/fixtures/wallet/recovery
Normal file
1
apps/explorer-e2e/src/fixtures/wallet/recovery
Normal file
@ -0,0 +1 @@
|
||||
ozone access unlock valid olympic save include omit supply green clown session
|
@ -1,5 +1,3 @@
|
||||
import '../support/common.functions';
|
||||
|
||||
context('Asset page', { tags: '@regression' }, function () {
|
||||
describe('Verify elements on page', function () {
|
||||
const assetsNavigation = 'a[href="/assets"]';
|
||||
|
@ -1,5 +1,3 @@
|
||||
import '../support/common.functions';
|
||||
|
||||
context('Blocks page', { tags: '@regression' }, function () {
|
||||
before('visit token home page', function () {
|
||||
cy.visit('/');
|
||||
|
@ -1,5 +1,3 @@
|
||||
import '../support/common.functions';
|
||||
|
||||
//Tests set to skip until market bug for capsule checkpoint is fixed
|
||||
context.skip('Market page', { tags: '@regression' }, function () {
|
||||
describe('Verify elements on page', function () {
|
||||
|
@ -1,5 +1,3 @@
|
||||
import '../support/common.functions';
|
||||
|
||||
context('Network parameters page', { tags: '@smoke' }, function () {
|
||||
before('visit token home page', function () {
|
||||
cy.visit('/');
|
||||
|
154
apps/explorer-e2e/src/integration/parties.cy.js
Normal file
154
apps/explorer-e2e/src/integration/parties.cy.js
Normal file
@ -0,0 +1,154 @@
|
||||
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
|
||||
const partiesMenuHeader = 'a[href="/parties"]';
|
||||
const partiesSearchBox = '[data-testid="party-input"]';
|
||||
const partiesSearchAction = '[data-testid="go-submit"]';
|
||||
const partiesJsonSection = '[data-testid="parties-json"]';
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
|
||||
let assetData = {
|
||||
fUSDC: { id: 'fUSDC', name: 'USDC (fake)', amount: '10' },
|
||||
fBTC: { id: 'fBTC', name: 'BTC (fake)', amount: '6' },
|
||||
fEURO: { id: 'fEURO', name: 'EURO (fake)', amount: '8' },
|
||||
fDAI: { id: 'fDAI', name: 'DAI (fake)', amount: '2' },
|
||||
};
|
||||
|
||||
const assetsInTest = Object.keys(assetData);
|
||||
|
||||
context('Parties page', { tags: '@regression' }, function () {
|
||||
before('send-faucet assets to connected vega wallet', function () {
|
||||
cy.vega_wallet_import();
|
||||
assetsInTest.forEach((asset) => {
|
||||
cy.vega_wallet_receive_fauceted_asset(
|
||||
assetData[asset].name,
|
||||
assetData[asset].amount,
|
||||
vegaWalletPublicKey
|
||||
);
|
||||
});
|
||||
cy.visit('/');
|
||||
});
|
||||
|
||||
describe('Verify parties page content', function () {
|
||||
before('navigate to parties page and search for party', function () {
|
||||
cy.get(partiesMenuHeader).click();
|
||||
// Deliberate slow entry of party id/key - enabling transactions to sync
|
||||
cy.get(partiesSearchBox).type(vegaWalletPublicKey, { delay: 120 });
|
||||
cy.get(partiesSearchAction).click();
|
||||
});
|
||||
|
||||
it('should see party address id - having searched', function () {
|
||||
cy.contains('Address')
|
||||
.siblings()
|
||||
.contains(vegaWalletPublicKey)
|
||||
.should('be.visible');
|
||||
});
|
||||
|
||||
it('should see each asset - within asset data section', function () {
|
||||
assetsInTest.forEach((asset) => {
|
||||
cy.contains(assetData[asset].name, txTimeout).should('be.visible');
|
||||
cy.contains(assetData[asset].name)
|
||||
.siblings()
|
||||
.contains(assetData[asset].id)
|
||||
.should('be.visible');
|
||||
cy.contains(assetData[asset].name, txTimeout)
|
||||
.parent()
|
||||
.siblings()
|
||||
.within(() => {
|
||||
cy.get_asset_decimals(asset).then((assetDecimals) => {
|
||||
cy.contains_exactly(
|
||||
assetData[asset].amount + '.' + assetDecimals
|
||||
).should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to copy the party address id', function () {
|
||||
cy.monitor_clipboard().as('clipboard');
|
||||
cy.contains('Address').siblings().last().click();
|
||||
cy.get('@clipboard')
|
||||
.get_copied_text_from_clipboard()
|
||||
.should('equal', vegaWalletPublicKey);
|
||||
});
|
||||
|
||||
it('should be able to copy an asset id', function () {
|
||||
cy.monitor_clipboard().as('clipboard');
|
||||
|
||||
cy.contains(assetData.fDAI.name, txTimeout).should('be.visible');
|
||||
cy.contains(assetData.fDAI.name)
|
||||
.siblings()
|
||||
.within(() => {
|
||||
cy.get('[data-state="closed"]').last().click({ force: true });
|
||||
});
|
||||
|
||||
cy.get('@clipboard')
|
||||
.get_copied_text_from_clipboard()
|
||||
.should('equal', assetData.fDAI.id);
|
||||
});
|
||||
|
||||
it('should be able to see JSON of each asset containing correct balance and decimals', function () {
|
||||
cy.get(partiesJsonSection).should('be.visible');
|
||||
|
||||
assetsInTest.forEach((asset) => {
|
||||
cy.get(partiesJsonSection)
|
||||
.invoke('text')
|
||||
.convert_string_json_to_js_object()
|
||||
.get_party_accounts_data()
|
||||
.then((accounts) => {
|
||||
cy.get_asset_decimals(asset).then((assetDecimals) => {
|
||||
assert.equal(
|
||||
accounts[asset].balance,
|
||||
assetData[asset].amount + assetDecimals
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
after(
|
||||
'teardown environment to prevent test data bleeding into other tests',
|
||||
function () {
|
||||
if (Cypress.env('CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS')) {
|
||||
cy.restart_vegacapsule_network();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Cypress.Commands.add('get_asset_decimals', (assetID) => {
|
||||
cy.get_asset_information().then((assetsInfo) => {
|
||||
const assetDecimals = assetsInfo[assetData[assetID].name].decimals;
|
||||
let decimals = '';
|
||||
for (let i = 0; i < assetDecimals; i++) decimals += '0';
|
||||
return decimals;
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
'convert_string_json_to_js_object',
|
||||
{ prevSubject: true },
|
||||
(jsonBlobString) => {
|
||||
return JSON.parse(jsonBlobString);
|
||||
}
|
||||
);
|
||||
|
||||
Cypress.Commands.add(
|
||||
'get_party_accounts_data',
|
||||
{ prevSubject: true },
|
||||
(jsObject) => {
|
||||
const accounts = jsObject.party.accounts.reduce(function (
|
||||
account,
|
||||
entry
|
||||
) {
|
||||
account[entry.asset.id] = {
|
||||
balance: entry.balance,
|
||||
id: entry.asset.id,
|
||||
decimals: entry.asset.decimals,
|
||||
name: entry.asset.name,
|
||||
};
|
||||
return account;
|
||||
},
|
||||
{});
|
||||
return accounts;
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
@ -1,5 +1,3 @@
|
||||
import '../support/common.functions';
|
||||
|
||||
context('Validator page', { tags: '@smoke' }, function () {
|
||||
describe('Verify elements on page', function () {
|
||||
const validatorNavigation = 'a[href="/validators"]';
|
||||
|
@ -51,3 +51,19 @@ Cypress.Commands.add('common_verify_json_int_values', function (expectedNum) {
|
||||
cy.wrap($paramValue).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('monitor_clipboard', () => {
|
||||
cy.window().then((win) => {
|
||||
return cy.stub(win, 'prompt').returns(win.prompt);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
'get_copied_text_from_clipboard',
|
||||
{ prevSubject: true },
|
||||
(clipboard) => {
|
||||
// Must first setup with cy.monitor_clipboard().as('clipboard')
|
||||
// This function then chained off a cy.get('@clipboard')
|
||||
return clipboard.args[0][1];
|
||||
}
|
||||
);
|
||||
|
@ -14,5 +14,6 @@
|
||||
// ***********************************************************
|
||||
|
||||
import '@vegaprotocol/cypress';
|
||||
import './common.functions.js';
|
||||
import registerCypressGrep from 'cypress-grep';
|
||||
registerCypressGrep();
|
||||
|
@ -150,7 +150,9 @@ const Party = () => {
|
||||
<SubHeading>{t('Staking')}</SubHeading>
|
||||
{staking}
|
||||
<SubHeading>{t('JSON')}</SubHeading>
|
||||
<SyntaxHighlighter data={data} />
|
||||
<section data-testid="parties-json">
|
||||
<SyntaxHighlighter data={data} />
|
||||
</section>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
|
@ -1156,8 +1156,8 @@ context(
|
||||
after(
|
||||
'teardown environment to prevent test data bleeding into other tests',
|
||||
function () {
|
||||
if (Cypress.env('TEARDOWN_NETWORK_AFTER_FLOWS')) {
|
||||
cy.restartVegacapsuleNetwork();
|
||||
if (Cypress.env('CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS')) {
|
||||
cy.restart_vegacapsule_network();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -868,8 +868,8 @@ context(
|
||||
after(
|
||||
'teardown environment to prevent test data bleeding into other tests',
|
||||
function () {
|
||||
if (Cypress.env('TEARDOWN_NETWORK_AFTER_FLOWS')) {
|
||||
cy.restartVegacapsuleNetwork();
|
||||
if (Cypress.env('CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS')) {
|
||||
cy.restart_vegacapsule_network();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -280,8 +280,8 @@ context(
|
||||
after(
|
||||
'teardown environment to prevent test data bleeding into other tests',
|
||||
function () {
|
||||
if (Cypress.env('TEARDOWN_NETWORK_AFTER_FLOWS')) {
|
||||
cy.restartVegacapsuleNetwork();
|
||||
if (Cypress.env('CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS')) {
|
||||
cy.restart_vegacapsule_network();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -410,8 +410,8 @@ context(
|
||||
after(
|
||||
'teardown environment to prevent test data bleeding into other tests',
|
||||
function () {
|
||||
if (Cypress.env('TEARDOWN_NETWORK_AFTER_FLOWS')) {
|
||||
cy.restartVegacapsuleNetwork();
|
||||
if (Cypress.env('CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS')) {
|
||||
cy.restart_vegacapsule_network();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -17,10 +17,6 @@ const navigation = {
|
||||
pageSpinner: '[data-testid="splash-loader"]',
|
||||
};
|
||||
|
||||
Cypress.Commands.add('contains_exactly', (expected_result) => {
|
||||
return cy.contains(new RegExp('^' + expected_result + '$', 'g'));
|
||||
});
|
||||
|
||||
Cypress.Commands.add('navigate_to', (page) => {
|
||||
return cy.get(navigation.section, { timeout: 10000 }).within(() => {
|
||||
cy.get(navigation[page]).click({ force: true });
|
||||
@ -40,36 +36,3 @@ Cypress.Commands.add('verify_page_header', (text) => {
|
||||
Cypress.Commands.add('wait_for_spinner', () => {
|
||||
cy.get(navigation.pageSpinner, { timeout: 20000 }).should('not.exist');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('restartVegacapsuleNetwork', () => {
|
||||
Cypress.on('uncaught:exception', () => {
|
||||
// stopping the network causes errors with pending transactions
|
||||
// This stops those errors from preventing the teardown
|
||||
return false;
|
||||
});
|
||||
// We stop the network twice - since it does not always shutdown correctly on first attempt
|
||||
cy.exec('vegacapsule network destroy', { failOnNonZeroExit: false });
|
||||
cy.exec('vegacapsule network destroy', { failOnNonZeroExit: false })
|
||||
.its('stderr')
|
||||
.should('contain', 'network cleaning up success');
|
||||
|
||||
cy.exec(
|
||||
'vegacapsule network bootstrap --config-path=../../vegacapsule/config.hcl --force',
|
||||
{ failOnNonZeroExit: false, timeout: 100000 }
|
||||
)
|
||||
.its('stderr')
|
||||
.then((response) => {
|
||||
if (!response.includes('starting network success')) {
|
||||
cy.exec('vegacapsule network destroy', { failOnNonZeroExit: false });
|
||||
cy.exec(
|
||||
'vegacapsule network bootstrap --config-path=../../vegacapsule/config.hcl --force',
|
||||
{ failOnNonZeroExit: false, timeout: 100000 }
|
||||
)
|
||||
.its('stderr')
|
||||
.then((response) => {
|
||||
return response;
|
||||
});
|
||||
}
|
||||
})
|
||||
.should('contain', 'starting network success');
|
||||
});
|
||||
|
@ -2,21 +2,8 @@ const vegaWalletContainer = '[data-testid="vega-wallet"]';
|
||||
const restConnectorForm = '[data-testid="rest-connector-form"]';
|
||||
const vegaWalletNameElement = '[data-testid="wallet-name"]';
|
||||
const vegaWalletName = Cypress.env('vegaWalletName');
|
||||
const vegaWalletLocation = Cypress.env('vegaWalletLocation');
|
||||
const vegaWalletPassphrase = Cypress.env('vegaWalletPassphrase');
|
||||
|
||||
Cypress.Commands.add('vega_wallet_import', () => {
|
||||
cy.highlight(`Importing Vega Wallet ${vegaWalletName}`);
|
||||
cy.exec(`vega wallet init -f --home ${vegaWalletLocation}`);
|
||||
cy.exec(
|
||||
`vega wallet import -w ${vegaWalletName} --recovery-phrase-file ./src/fixtures/wallet/recovery -p ./src/fixtures/wallet/passphrase --home ~/.vegacapsule/testnet/wallet`,
|
||||
{ failOnNonZeroExit: false }
|
||||
);
|
||||
cy.exec(
|
||||
`vega wallet service run --network DV --automatic-consent --home ${vegaWalletLocation}`
|
||||
);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('vega_wallet_connect', () => {
|
||||
cy.highlight('Connecting Vega Wallet');
|
||||
cy.get(vegaWalletContainer).within(() => {
|
||||
|
@ -9,6 +9,9 @@ import { addSlackCommand } from './lib/commands/slack';
|
||||
import { addHighlightLog } from './lib/commands/highlight-log';
|
||||
import { addGetAssetInformation } from './lib/commands/get-asset-information';
|
||||
import { addVegaWalletReceiveFaucetedAsset } from './lib/commands/vega-wallet-receive-fauceted-asset';
|
||||
import { addVegaWalletImport } from './lib/commands/vega-wallet-import';
|
||||
import { addContainsExactly } from './lib/commands/contains-exactly';
|
||||
import { addRestartVegacapsuleNetwork } from './lib/commands/restart-vegacapsule-network';
|
||||
|
||||
addGetTestIdcommand();
|
||||
addSlackCommand();
|
||||
@ -19,6 +22,9 @@ addMockWeb3ProviderCommand();
|
||||
addHighlightLog();
|
||||
addVegaWalletReceiveFaucetedAsset();
|
||||
addGetAssetInformation();
|
||||
addVegaWalletImport();
|
||||
addContainsExactly();
|
||||
addRestartVegacapsuleNetwork();
|
||||
|
||||
export * from './lib/graphql-test-utils';
|
||||
export type { onMessage } from './lib/commands/mock-gql';
|
||||
|
15
libs/cypress/src/lib/commands/contains-exactly.ts
Normal file
15
libs/cypress/src/lib/commands/contains-exactly.ts
Normal file
@ -0,0 +1,15 @@
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
interface Chainable<Subject> {
|
||||
contains_exactly(expected_result: string): void;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function addContainsExactly() {
|
||||
Cypress.Commands.add('contains_exactly', (expected_result) => {
|
||||
return cy.contains(new RegExp('^' + expected_result + '$', 'g'));
|
||||
});
|
||||
}
|
44
libs/cypress/src/lib/commands/restart-vegacapsule-network.ts
Normal file
44
libs/cypress/src/lib/commands/restart-vegacapsule-network.ts
Normal file
@ -0,0 +1,44 @@
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
interface Chainable<Subject> {
|
||||
restart_vegacapsule_network(): void;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function addRestartVegacapsuleNetwork() {
|
||||
Cypress.Commands.add('restart_vegacapsule_network', () => {
|
||||
Cypress.on('uncaught:exception', () => {
|
||||
// stopping the network causes errors with pending transactions
|
||||
// This stops those errors from preventing the teardown
|
||||
return false;
|
||||
});
|
||||
// We stop the network twice - since it does not always shutdown correctly on first attempt
|
||||
cy.exec('vegacapsule network destroy', { failOnNonZeroExit: false });
|
||||
cy.exec('vegacapsule network destroy', { failOnNonZeroExit: false })
|
||||
.its('stderr')
|
||||
.should('contain', 'network cleaning up success');
|
||||
|
||||
cy.exec(
|
||||
'vegacapsule network bootstrap --config-path=../../vegacapsule/config.hcl --force',
|
||||
{ failOnNonZeroExit: false, timeout: 100000 }
|
||||
)
|
||||
.its('stderr')
|
||||
.then((response) => {
|
||||
if (!response.includes('starting network success')) {
|
||||
cy.exec('vegacapsule network destroy', { failOnNonZeroExit: false });
|
||||
cy.exec(
|
||||
'vegacapsule network bootstrap --config-path=../../vegacapsule/config.hcl --force',
|
||||
{ failOnNonZeroExit: false, timeout: 100000 }
|
||||
)
|
||||
.its('stderr')
|
||||
.then((response) => {
|
||||
return response;
|
||||
});
|
||||
}
|
||||
})
|
||||
.should('contain', 'starting network success');
|
||||
});
|
||||
}
|
30
libs/cypress/src/lib/commands/vega-wallet-import.ts
Normal file
30
libs/cypress/src/lib/commands/vega-wallet-import.ts
Normal file
@ -0,0 +1,30 @@
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
interface Chainable<Subject> {
|
||||
vega_wallet_import(): void;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function addVegaWalletImport() {
|
||||
// @ts-ignore - ignoring Cypress type error which gets resolved when Cypress uses the command
|
||||
Cypress.Commands.add('vega_wallet_import', () => {
|
||||
cy.highlight(`Importing Vega Wallet ${Cypress.env('vegaWalletName')}`);
|
||||
cy.exec(`vega wallet init -f --home ${Cypress.env('vegaWalletLocation')}`);
|
||||
cy.exec(
|
||||
`vega wallet import -w ${Cypress.env(
|
||||
'vegaWalletName'
|
||||
)} --recovery-phrase-file ./src/fixtures/wallet/recovery -p ./src/fixtures/wallet/passphrase --home ${Cypress.env(
|
||||
'vegaWalletLocation'
|
||||
)}`,
|
||||
{ failOnNonZeroExit: false }
|
||||
);
|
||||
cy.exec(
|
||||
`vega wallet service run --network DV --automatic-consent --home ${Cypress.env(
|
||||
'vegaWalletLocation'
|
||||
)}`
|
||||
);
|
||||
});
|
||||
}
|
@ -23,10 +23,34 @@ export function addVegaWalletReceiveFaucetedAsset() {
|
||||
// @ts-ignore - ignoring Cypress type error which gets resolved when Cypress uses the command
|
||||
cy.get_asset_information().then((assets) => {
|
||||
const asset = assets[assetName];
|
||||
for (let i = 0; i < asset.decimals; i++) amount += '0';
|
||||
cy.exec(
|
||||
`curl -X POST -d '{"amount": "${amount}", "asset": "${asset.id}", "party": "${vegaWalletPublicKey}"}' -u "hedgehogandvega:hiccup" http://localhost:1790/api/v1/mint`
|
||||
);
|
||||
if (assets[assetName] !== undefined) {
|
||||
for (let i = 0; i < asset.decimals; i++) amount += '0';
|
||||
cy.exec(
|
||||
`curl -X POST -d '{"amount": "${amount}", "asset": "${asset.id}", "party": "${vegaWalletPublicKey}"}' http://localhost:1790/api/v1/mint`
|
||||
)
|
||||
.its('stdout')
|
||||
.then((response) => {
|
||||
assert.include(
|
||||
response,
|
||||
`"success":true`,
|
||||
'Ensuring curl command was succesfully undertaken'
|
||||
);
|
||||
});
|
||||
} else {
|
||||
const validAssets = Object.keys(assets)
|
||||
.filter((key) => key.includes('fake'))
|
||||
.reduce((obj, key) => {
|
||||
return Object.assign(obj, {
|
||||
[key]: assets[key],
|
||||
});
|
||||
}, {});
|
||||
assert.exists(
|
||||
assets[assetName],
|
||||
`${assetName} is not a faucetable asset, only the following assets can be faucted: ${Object.keys(
|
||||
validAssets
|
||||
)}`
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user