From 9eee4ff8c421dfb921a454ec89da3b5de1a49729 Mon Sep 17 00:00:00 2001 From: "m.ray" <16125548+MadalinaRaicu@users.noreply.github.com> Date: Mon, 10 Oct 2022 10:57:18 +0100 Subject: [PATCH] Merge develop in release/testnet (#1688) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: update tranches Signed-off-by: github-actions[bot] * chore: remove old type gen in positions (#1619) * chore: remove old type gen * chore: remove old type gen - small fixes Co-authored-by: maciek * chore: replace duplicated assets queries with assetsProvider (#1617) * chore: update tranches Signed-off-by: github-actions[bot] * Feat/1446: Add UpdateAsset proposal form (#1558) * Feat/1446: Add UpdateAsset proposal form * Feat/1446: Formatting fix * Feat/1446: changes from PR comments * Feat/1446: Fix for mockWalletContext shape and lint fix * Feat/1446: Fix more tests reliant on the updated mockPubkey shape change * Feat/1446: Adding the update asset proposal terms interface into the new location Co-authored-by: Bartłomiej Głownia Co-authored-by: Dexter * Test/1574 governance proposal forms (#1629) * chore: remove repeated code from existing test * test: update parameters added * test: new proposals added * chore: tidy forms flow * test: governance acs added * chore: revert change in asset json * chore: remove only tag * chore: update tranches Signed-off-by: github-actions[bot] * chore: move generateAccounts to seerate file (#1623) * chore: rename wallet label to match app, add more user friendly fetch failed message (#1650) * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * Adjust workflow to new wallet (#1668) * chore: change wallet import and fix test * chore: fix wallet run * chore: fix wallet run * chore: update capsule config * housekeeping: fixes wallet tests (#1669) * chore: added useYesterday hook (#1635) * chore: added useYesteday hook * chore: added useYesterday hook * fix: remove setting up viewport height to derived from grid element (#1673) * feat: updated withdrawal tab (849) (#1579) * feat: updated withdrawal tab (849) * added pending table to the token app, added pending completed filtering to the data provider * amended and added unit tests * amended time formats * added units * fixes errors * addressed comments * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * feat(explorer): add txs infinite scroll list (#1625) * chore: update tranches Signed-off-by: github-actions[bot] * fix: deal ticket estimated uncrossing (#1636) * fix: invalid uncrossing price * chore: align estimated uncrossing price with size label * fix: 0 used balance on margin and bond accounts should not be displayed * fix: small tweaks and bugfixes * fix: filter empty acounts * fix: fix unit test * fix: fix unit test Co-authored-by: Matthew Russell * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * chore: update tranches Signed-off-by: github-actions[bot] * Test/1633 governance flows (#1683) * test: refactor most existing tests to use raw proposal * chore: remove unnecessary waits * chore: acs updated for token association (#1687) * Test/block exp network params (#1681) * test: network parameter tests * test: lint * test: add comments * test: more guidance notes * test: disable theme check whilst investigating * test: fix failing test for console lite * test: attempt 2 to fix console lite error only in CI * test: lint * test: remove check * test: update conflict function Signed-off-by: github-actions[bot] Co-authored-by: mattrussell36 Co-authored-by: macqbat Co-authored-by: maciek Co-authored-by: Bartłomiej Głownia Co-authored-by: Sam Keen Co-authored-by: Dexter Co-authored-by: Joe Tsang <30622993+jtsang586@users.noreply.github.com> Co-authored-by: Matthew Russell Co-authored-by: Radosław Szpiech Co-authored-by: Art Co-authored-by: Elmar <102954831+elmar-vega@users.noreply.github.com> Co-authored-by: AndyWhiteVega <106072061+AndyWhiteVega@users.noreply.github.com> --- .github/actions/setup-vegawallet/action.yml | 6 +- .../src/integration/market-trade.test.ts | 6 +- .../src/integration/portfolio-page.test.ts | 6 +- .../src/support/mocks/generate-accounts.ts | 44 +- .../src/support/mocks/generate-assets.ts | 55 ++ .../src/support/mocks/generate-positions.ts | 19 +- .../src/app/components/deposits/deposits.tsx | 43 +- .../simple-market-list/simple-market-list.tsx | 7 +- .../simple-market-percent-change.tsx | 6 +- apps/explorer-e2e/cypress.config.js | 2 +- .../fixtures/net_parameter_format_lookup.json | 121 ++++ .../src/integration/network.cy.js | 258 +++++++- .../src/support/common.functions.js | 56 +- apps/explorer/.env | 1 + apps/explorer/.env.devnet | 1 + apps/explorer/.env.mainnet | 1 + apps/explorer/.env.stagnet3 | 1 + apps/explorer/.env.testnet | 1 + apps/explorer/.env.vegacapsule | 1 + .../txs/txs-infinite-list-item.spec.tsx | 96 ++- .../components/txs/txs-infinite-list-item.tsx | 75 +-- .../components/txs/txs-infinite-list.spec.tsx | 40 +- .../app/components/txs/txs-infinite-list.tsx | 29 +- apps/explorer/src/app/config/env.ts | 1 + apps/explorer/src/app/routes/assets/index.tsx | 12 +- .../explorer/src/app/routes/router-config.tsx | 4 +- .../src/app/routes/txs/home/index.tsx | 133 ++-- .../routes/types/block-explorer-response.d.ts | 14 + apps/static/src/assets/mainnet-tranches.json | 342 ++++++++-- apps/token-e2e/cypress.config.js | 3 + .../src/fixtures/proposals/new-asset.json | 13 + .../src/fixtures/proposals/new-market.json | 80 +++ .../proposals/{freeform.json => raw.json} | 2 +- .../src/fixtures/proposals/update-market.json | 69 ++ .../integration/flow/governance-flow.cy.js | 603 ++++-------------- .../flow/governance-forms-flow.cy.js | 177 +++++ .../flow/token-association-flow.cy.js | 40 +- .../src/integration/view/governance.cy.js | 1 + .../src/support/governance.functions.js | 57 +- .../src/support/staking.functions.js | 10 +- .../token/src/components/vega-wallet/hooks.ts | 2 +- apps/token/src/i18n/translations/dev.json | 2 + .../proposals-list-item-details.spec.tsx | 6 +- .../freeform/propose-freeform.spec.tsx | 12 +- .../propose/freeform/propose-freeform.tsx | 6 +- .../propose-network-parameter.spec.tsx | 22 +- .../propose-network-parameter.tsx | 6 +- .../new-asset/propose-new-asset.spec.tsx | 10 +- .../propose/new-asset/propose-new-asset.tsx | 20 +- .../new-market/propose-new-market.spec.tsx | 6 +- .../propose/new-market/propose-new-market.tsx | 20 +- .../governance/propose/propose.spec.tsx | 1 + .../src/routes/governance/propose/propose.tsx | 10 + .../governance/propose/raw/propose-raw.tsx | 12 +- .../governance/propose/update-asset/index.tsx | 4 + .../propose-update-asset.spec.tsx | 102 +++ .../update-asset/propose-update-asset.tsx | 182 ++++++ .../propose-update-market.spec.tsx | 12 +- .../update-market/propose-update-market.tsx | 20 +- .../routes/governance/test-helpers/mocks.ts | 8 +- apps/token/src/routes/router-config.tsx | 11 + apps/token/src/routes/withdrawals/index.tsx | 9 +- .../trading-e2e/src/integration/deposit.cy.ts | 8 +- .../trading-e2e/src/integration/markets.cy.ts | 2 +- .../src/integration/trading-orders.cy.ts | 1 - .../src/integration/withdraw.cy.ts | 9 +- .../src/support/mocks/generate-accounts.ts | 55 +- .../src/support/mocks/generate-assets.ts | 90 +++ .../support/mocks/generate-deposit-page.ts | 93 --- .../src/support/mocks/generate-positions.ts | 16 +- .../mocks/generate-withdraw-page-query.ts | 77 --- apps/trading-e2e/src/support/trading.ts | 3 +- .../select-market/select-market.tsx | 4 +- apps/trading/lib/query-fragments.ts | 16 - .../trading/pages/markets/[marketId].page.tsx | 7 +- .../pages/portfolio/deposit/Deposit.graphql | 17 - .../deposit/__generated__/DepositPage.ts | 75 --- .../deposit/__generated___/Deposit.ts | 57 -- .../portfolio/deposit/deposit-container.tsx | 37 +- .../pages/portfolio/withdrawals-container.tsx | 25 +- libs/accounts/src/lib/Accounts.graphql | 19 - .../src/lib/__generated___/Accounts.ts | 57 +- .../src/lib/accounts-data-provider.ts | 21 +- libs/accounts/src/lib/accounts-manager.tsx | 2 +- libs/accounts/src/lib/accounts-table.spec.tsx | 2 +- libs/accounts/src/lib/accounts-table.tsx | 11 +- libs/accounts/src/lib/asset-data-provider.ts | 21 - .../accounts/src/lib/breakdown-table.spec.tsx | 4 +- libs/accounts/src/lib/breakdown-table.tsx | 15 - libs/assets/src/lib/Asset.graphql | 16 - libs/assets/src/lib/Assets.graphql | 29 +- libs/assets/src/lib/__generated___/Asset.ts | 59 -- libs/assets/src/lib/__generated___/Assets.ts | 69 +- .../src/lib/asset-details-dialog.spec.tsx | 4 +- libs/assets/src/lib/asset-details-dialog.tsx | 34 +- libs/assets/src/lib/assets-data-provider.ts | 60 ++ libs/assets/src/lib/index.ts | 1 + libs/assets/tsconfig.spec.json | 2 +- libs/cypress/src/index.ts | 2 + .../lib/commands/get-network-parameters.ts | 33 + .../src/lib/commands/vega-wallet-import.ts | 20 +- .../deal-ticket/deal-ticket-market-amount.tsx | 10 +- .../components/deal-ticket/deal-ticket.tsx | 25 +- .../compile-grid-data.tsx | 2 +- .../deposits/src/lib/__generated__/Deposit.ts | 112 ---- .../src/lib/__generated__/DepositAsset.ts | 72 --- libs/deposits/src/lib/__generated__/index.ts | 2 - libs/deposits/src/lib/deposit-container.tsx | 42 +- libs/deposits/src/lib/deposit-form.tsx | 4 +- libs/deposits/src/lib/deposit-manager.tsx | 2 +- libs/deposits/src/lib/deposit-store.ts | 2 +- libs/deposits/src/lib/deposits-table.tsx | 2 +- libs/deposits/src/lib/index.ts | 2 +- libs/deposits/src/lib/use-deposit-balances.ts | 2 +- libs/deposits/src/lib/use-deposits.ts | 4 +- libs/deposits/src/lib/use-get-allowance.ts | 2 +- .../src/lib/use-get-balance-of-erc20-token.ts | 2 +- .../src/lib/use-get-deposit-maximum.ts | 2 +- .../src/lib/use-get-deposited-amount.ts | 2 +- libs/deposits/src/lib/use-submit-approval.ts | 3 +- libs/deposits/src/lib/use-submit-deposit.tsx | 11 +- libs/deposits/src/lib/use-submit-faucet.ts | 2 +- .../src/lib/market-depth-provider.ts | 12 - libs/market-depth/src/lib/orderbook.tsx | 3 +- .../components/market-info/info-market.tsx | 8 +- libs/market-list/src/lib/markets-provider.ts | 7 +- libs/positions/src/index.ts | 5 +- libs/positions/src/lib/Positions.graphql | 69 +- .../src/lib/__generated__/Margins.ts | 89 --- .../lib/__generated__/MarginsSubscription.ts | 56 -- .../src/lib/__generated__/PositionFields.ts | 44 -- .../src/lib/__generated__/Positions.ts | 83 --- .../__generated__/PositionsSubscription.ts | 47 -- .../src/lib/__generated___/Positions.ts | 143 ++++- .../positions/src/lib/margin-data-provider.ts | 74 +-- .../src/lib/positions-data-providers.spec.ts | 9 +- .../src/lib/positions-data-providers.ts | 131 ++-- libs/react-helpers/src/hooks/index.ts | 7 +- .../src/hooks/use-network-params.ts | 10 + .../src/hooks/use-yesterday.spec.ts | 57 ++ libs/react-helpers/src/hooks/use-yesterday.ts | 22 + libs/react-helpers/src/index.ts | 1 - libs/react-helpers/src/lib/assets.ts | 65 -- libs/react-helpers/src/lib/validate/index.ts | 9 + libs/types/.env | 2 +- .../src/components/ag-grid/index.tsx | 16 + .../connect-dialog/connect-dialog.spec.tsx | 4 +- .../connect-dialog/rest-connector-form.tsx | 4 +- libs/wallet/src/connectors/rest-connector.ts | 2 +- libs/wallet/src/connectors/vega-connector.ts | 18 +- libs/web3/src/lib/use-token-contract.ts | 2 +- libs/withdraws/src/index.ts | 2 +- .../lib/__generated__/WithdrawFormQuery.ts | 139 ---- .../lib/pending-withdrawals-table.spec.tsx | 65 ++ .../src/lib/pending-withdrawals-table.tsx | 201 ++++++ libs/withdraws/src/lib/test-helpers.ts | 14 +- libs/withdraws/src/lib/types.ts | 10 - .../src/lib/use-get-withdraw-threshold.tsx | 4 +- libs/withdraws/src/lib/use-withdraw-asset.tsx | 6 +- libs/withdraws/src/lib/use-withdrawals.ts | 22 + .../src/lib/withdraw-form-container.tsx | 106 +-- libs/withdraws/src/lib/withdraw-form.spec.tsx | 2 +- libs/withdraws/src/lib/withdraw-form.tsx | 4 +- .../src/lib/withdraw-manager.spec.tsx | 6 +- libs/withdraws/src/lib/withdraw-manager.tsx | 6 +- libs/withdraws/src/lib/withdraw-store.ts | 2 +- .../src/lib/withdrawals-table.spec.tsx | 75 +-- libs/withdraws/src/lib/withdrawals-table.tsx | 292 +++------ vegacapsule/config.hcl | 14 +- vegacapsule/genesis.tmpl | 146 +++-- 170 files changed, 3254 insertions(+), 3160 deletions(-) create mode 100644 apps/console-lite-e2e/src/support/mocks/generate-assets.ts create mode 100644 apps/explorer-e2e/src/fixtures/net_parameter_format_lookup.json create mode 100644 apps/explorer/src/app/routes/types/block-explorer-response.d.ts create mode 100644 apps/token-e2e/src/fixtures/proposals/new-asset.json create mode 100644 apps/token-e2e/src/fixtures/proposals/new-market.json rename apps/token-e2e/src/fixtures/proposals/{freeform.json => raw.json} (83%) create mode 100644 apps/token-e2e/src/fixtures/proposals/update-market.json create mode 100644 apps/token-e2e/src/integration/flow/governance-forms-flow.cy.js create mode 100644 apps/token/src/routes/governance/propose/update-asset/index.tsx create mode 100644 apps/token/src/routes/governance/propose/update-asset/propose-update-asset.spec.tsx create mode 100644 apps/token/src/routes/governance/propose/update-asset/propose-update-asset.tsx create mode 100644 apps/trading-e2e/src/support/mocks/generate-assets.ts delete mode 100644 apps/trading-e2e/src/support/mocks/generate-deposit-page.ts delete mode 100644 apps/trading-e2e/src/support/mocks/generate-withdraw-page-query.ts delete mode 100644 apps/trading/lib/query-fragments.ts delete mode 100644 apps/trading/pages/portfolio/deposit/Deposit.graphql delete mode 100644 apps/trading/pages/portfolio/deposit/__generated__/DepositPage.ts delete mode 100644 apps/trading/pages/portfolio/deposit/__generated___/Deposit.ts delete mode 100644 libs/accounts/src/lib/asset-data-provider.ts delete mode 100644 libs/assets/src/lib/Asset.graphql delete mode 100644 libs/assets/src/lib/__generated___/Asset.ts create mode 100644 libs/assets/src/lib/assets-data-provider.ts create mode 100644 libs/cypress/src/lib/commands/get-network-parameters.ts delete mode 100644 libs/deposits/src/lib/__generated__/Deposit.ts delete mode 100644 libs/deposits/src/lib/__generated__/DepositAsset.ts delete mode 100644 libs/deposits/src/lib/__generated__/index.ts delete mode 100644 libs/positions/src/lib/__generated__/Margins.ts delete mode 100644 libs/positions/src/lib/__generated__/MarginsSubscription.ts delete mode 100644 libs/positions/src/lib/__generated__/PositionFields.ts delete mode 100644 libs/positions/src/lib/__generated__/Positions.ts delete mode 100644 libs/positions/src/lib/__generated__/PositionsSubscription.ts create mode 100644 libs/react-helpers/src/hooks/use-yesterday.spec.ts create mode 100644 libs/react-helpers/src/hooks/use-yesterday.ts delete mode 100644 libs/react-helpers/src/lib/assets.ts delete mode 100644 libs/withdraws/src/lib/__generated__/WithdrawFormQuery.ts create mode 100644 libs/withdraws/src/lib/pending-withdrawals-table.spec.tsx create mode 100644 libs/withdraws/src/lib/pending-withdrawals-table.tsx delete mode 100644 libs/withdraws/src/lib/types.ts diff --git a/.github/actions/setup-vegawallet/action.yml b/.github/actions/setup-vegawallet/action.yml index 88eb93500..dcb92bfd3 100644 --- a/.github/actions/setup-vegawallet/action.yml +++ b/.github/actions/setup-vegawallet/action.yml @@ -32,14 +32,14 @@ runs: - name: Import fairground network shell: bash if: ${{ inputs.capsule==false }} - run: vegawallet network import --from-url="https://raw.githubusercontent.com/vegaprotocol/networks/master/fairground/fairground.toml" --force --home ~/.vegacapsule/testnet/wallet + run: vegawallet network import --from-url="https://raw.githubusercontent.com/vegaprotocol/networks-internal/master/fairground/vegawallet-fairground.toml" --force --home ~/.vegacapsule/testnet/wallet - name: Start service using fairground network shell: bash if: ${{ inputs.capsule==false }} - run: vegawallet service run --network fairground --automatic-consent --home ~/.vegacapsule/testnet/wallet & + run: vegawallet service run --network fairground --automatic-consent --no-version-check --home ~/.vegacapsule/testnet/wallet & - name: Start service using capsule network shell: bash - if: ${{ inputs.capsule }} + if: ${{ inputs.capsule==true }} run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet & diff --git a/apps/console-lite-e2e/src/integration/market-trade.test.ts b/apps/console-lite-e2e/src/integration/market-trade.test.ts index 0ac725b17..492a5e444 100644 --- a/apps/console-lite-e2e/src/integration/market-trade.test.ts +++ b/apps/console-lite-e2e/src/integration/market-trade.test.ts @@ -296,11 +296,7 @@ describe('Market trade', { tags: '@smoke' }, () => { cy.get('#step-3-panel').find('dd').eq(4).should('have.text', ' - '); - cy.getByTestId('place-order').click(); - cy.getByTestId('dialog-title').should( - 'have.text', - 'Awaiting network confirmation' - ); + cy.getByTestId('place-order').should('be.enabled').click(); } }); diff --git a/apps/console-lite-e2e/src/integration/portfolio-page.test.ts b/apps/console-lite-e2e/src/integration/portfolio-page.test.ts index 70ee696aa..8b4ca89af 100644 --- a/apps/console-lite-e2e/src/integration/portfolio-page.test.ts +++ b/apps/console-lite-e2e/src/integration/portfolio-page.test.ts @@ -8,10 +8,8 @@ import { emptyPositions, generateMargins, } from '../support/mocks/generate-positions'; -import { - generateAccounts, - generateAssets, -} from '../support/mocks/generate-accounts'; +import { generateAccounts } from '../support/mocks/generate-accounts'; +import { generateAssets } from '../support/mocks/generate-assets'; import { generateOrders } from '../support/mocks/generate-orders'; import { generateFills } from '../support/mocks/generate-fills'; import { diff --git a/apps/console-lite-e2e/src/support/mocks/generate-accounts.ts b/apps/console-lite-e2e/src/support/mocks/generate-accounts.ts index 2c9d457c8..5cf9bdf95 100644 --- a/apps/console-lite-e2e/src/support/mocks/generate-accounts.ts +++ b/apps/console-lite-e2e/src/support/mocks/generate-accounts.ts @@ -1,6 +1,6 @@ import merge from 'lodash/merge'; -import type { AccountsQuery, AssetsQuery } from '@vegaprotocol/accounts'; -import { AccountType, Schema as Types } from '@vegaprotocol/types'; +import type { AccountsQuery } from '@vegaprotocol/accounts'; +import { AccountType } from '@vegaprotocol/types'; import type { PartialDeep } from 'type-fest'; export const generateAccounts = ( @@ -75,43 +75,3 @@ export const generateAccounts = ( }; return merge(defaultAccounts, override); }; - -export const generateAssets = (override?: PartialDeep) => { - const defaultAssets: AssetsQuery = { - assetsConnection: { - edges: [ - { - node: { - id: 'asset-id', - symbol: 'tEURO', - decimals: 5, - name: 'Euro', - quantum: '', - status: Types.AssetStatus.STATUS_ENABLED, - }, - }, - { - node: { - id: 'asset-id-2', - symbol: 'tDAI', - decimals: 5, - name: 'DAI', - quantum: '', - status: Types.AssetStatus.STATUS_ENABLED, - }, - }, - { - node: { - id: 'asset-0', - symbol: 'AST0', - decimals: 5, - name: 'Asto', - quantum: '', - status: Types.AssetStatus.STATUS_ENABLED, - }, - }, - ], - }, - }; - return merge(defaultAssets, override); -}; diff --git a/apps/console-lite-e2e/src/support/mocks/generate-assets.ts b/apps/console-lite-e2e/src/support/mocks/generate-assets.ts new file mode 100644 index 000000000..dfee971f3 --- /dev/null +++ b/apps/console-lite-e2e/src/support/mocks/generate-assets.ts @@ -0,0 +1,55 @@ +import merge from 'lodash/merge'; +import type { AssetsQuery } from '@vegaprotocol/assets'; +import { Schema as Types } from '@vegaprotocol/types'; +import type { PartialDeep } from 'type-fest'; + +export const generateAssets = (override?: PartialDeep) => { + const defaultAssets: AssetsQuery = { + assetsConnection: { + edges: [ + { + node: { + id: 'asset-id', + symbol: 'tEURO', + decimals: 5, + name: 'Euro', + source: { + __typename: 'ERC20', + contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4', + }, + quantum: '', + status: Types.AssetStatus.STATUS_ENABLED, + }, + }, + { + node: { + id: 'asset-id-2', + symbol: 'tDAI', + decimals: 5, + name: 'DAI', + source: { + __typename: 'ERC20', + contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4', + }, + quantum: '', + status: Types.AssetStatus.STATUS_ENABLED, + }, + }, + { + node: { + id: 'asset-0', + symbol: 'AST0', + decimals: 5, + name: 'Asto', + source: { + __typename: 'BuiltinAsset', + }, + quantum: '', + status: Types.AssetStatus.STATUS_ENABLED, + }, + }, + ], + }, + }; + return merge(defaultAssets, override); +}; diff --git a/apps/console-lite-e2e/src/support/mocks/generate-positions.ts b/apps/console-lite-e2e/src/support/mocks/generate-positions.ts index 912bd5a79..4e327b901 100644 --- a/apps/console-lite-e2e/src/support/mocks/generate-positions.ts +++ b/apps/console-lite-e2e/src/support/mocks/generate-positions.ts @@ -1,14 +1,15 @@ import merge from 'lodash/merge'; import type { PartialDeep } from 'type-fest'; import type { - Positions, - Positions_party_positionsConnection_edges_node, + PositionsQuery, + PositionFieldsFragment, + MarginsQuery, } from '@vegaprotocol/positions'; export const generatePositions = ( - override?: PartialDeep -): Positions => { - const nodes: Positions_party_positionsConnection_edges_node[] = [ + override?: PartialDeep +): PositionsQuery => { + const nodes: PositionFieldsFragment[] = [ { __typename: 'Position', realisedPNL: '0', @@ -47,7 +48,7 @@ export const generatePositions = ( }, ]; - const defaultResult: Positions = { + const defaultResult: PositionsQuery = { party: { __typename: 'Party', id: Cypress.env('VEGA_PUBLIC_KEY'), @@ -66,7 +67,7 @@ export const generatePositions = ( return merge(defaultResult, override); }; -export const emptyPositions = () => { +export const emptyPositions = (): PositionsQuery => { return { party: { id: Cypress.env('VEGA_PUBLIC_KEY'), @@ -76,7 +77,7 @@ export const emptyPositions = () => { }; }; -export const generateMargins = () => { +export const generateMargins = (): MarginsQuery => { return { party: { id: Cypress.env('VEGA_PUBLIC_KEY'), @@ -119,7 +120,7 @@ export const generateMargins = () => { }, { node: { - m_typename: 'MarginLevels', + __typename: 'MarginLevels', maintenanceLevel: '0', searchLevel: '0', initialLevel: '0', diff --git a/apps/console-lite/src/app/components/deposits/deposits.tsx b/apps/console-lite/src/app/components/deposits/deposits.tsx index 3bc4b3cd2..b2ecfa4af 100644 --- a/apps/console-lite/src/app/components/deposits/deposits.tsx +++ b/apps/console-lite/src/app/components/deposits/deposits.tsx @@ -1,32 +1,12 @@ -import { gql, useQuery } from '@apollo/client'; +import { useMemo } from 'react'; import { DepositManager } from '@vegaprotocol/deposits'; -import { getEnabledAssets, t } from '@vegaprotocol/react-helpers'; +import { t } from '@vegaprotocol/react-helpers'; +import { enabledAssetsProvider } from '@vegaprotocol/assets'; +import { useDataProvider } from '@vegaprotocol/react-helpers'; import { Networks, useEnvironment } from '@vegaprotocol/environment'; import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit'; import { useVegaWallet } from '@vegaprotocol/wallet'; import { Web3Container } from '@vegaprotocol/web3'; -import type { DepositAssets } from './__generated__/DepositAssets'; - -const DEPOSITS_QUERY = gql` - query DepositAssets { - assetsConnection { - edges { - node { - id - name - symbol - decimals - status - source { - ... on ERC20 { - contractAddress - } - } - } - } - } - } -`; /** * Fetches data required for the Deposit page @@ -34,20 +14,19 @@ const DEPOSITS_QUERY = gql` export const DepositContainer = () => { const { VEGA_ENV } = useEnvironment(); const { pubKey } = useVegaWallet(); - - const { data, loading, error } = useQuery(DEPOSITS_QUERY, { - variables: { partyId: pubKey }, + const variables = useMemo(() => ({ partyId: pubKey }), [pubKey]); + const { data, loading, error } = useDataProvider({ + dataProvider: enabledAssetsProvider, + variables, skip: !pubKey, }); - const assets = getEnabledAssets(data); - return ( - data={data} loading={loading} error={error}> - {assets.length ? ( + + {data && data.length ? ( diff --git a/apps/console-lite/src/app/components/simple-market-list/simple-market-list.tsx b/apps/console-lite/src/app/components/simple-market-list/simple-market-list.tsx index 4fbd9cb6b..98c857fb3 100644 --- a/apps/console-lite/src/app/components/simple-market-list/simple-market-list.tsx +++ b/apps/console-lite/src/app/components/simple-market-list/simple-market-list.tsx @@ -4,6 +4,7 @@ import type { AgGridReact } from 'ag-grid-react'; import { useScreenDimensions, useDataProvider, + useYesterday, } from '@vegaprotocol/react-helpers'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import type { MarketState } from '@vegaprotocol/types'; @@ -33,13 +34,13 @@ const SimpleMarketList = () => { const statusesRef = useRef>({}); const gridRef = useRef(null); + const yesterday = useYesterday(); const variables = useMemo(() => { - const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600; return { - since: new Date(yesterday * 1000).toISOString(), + since: new Date(yesterday).toISOString(), interval: Interval.INTERVAL_I1H, }; - }, []); + }, [yesterday]); const { data, error, loading } = useDataProvider({ dataProvider: marketsWithCandlesProvider, variables, diff --git a/apps/console-lite/src/app/components/simple-market-list/simple-market-percent-change.tsx b/apps/console-lite/src/app/components/simple-market-list/simple-market-percent-change.tsx index b437aee8f..754391af1 100644 --- a/apps/console-lite/src/app/components/simple-market-list/simple-market-percent-change.tsx +++ b/apps/console-lite/src/app/components/simple-market-list/simple-market-percent-change.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import classNames from 'classnames'; import { InView } from 'react-intersection-observer'; -import { useDataProvider } from '@vegaprotocol/react-helpers'; +import { useDataProvider, useYesterday } from '@vegaprotocol/react-helpers'; import type { Candle } from '@vegaprotocol/market-list'; import { marketCandlesProvider } from '@vegaprotocol/market-list'; import { Interval } from '@vegaprotocol/types'; @@ -68,13 +68,13 @@ const SimpleMarketPercentChangeWrapper = (props: Props) => { }; const SimpleMarketPercentChange = ({ candles, marketId, setValue }: Props) => { - const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600; + const yesterday = useYesterday(); const { data } = useDataProvider({ dataProvider: marketCandlesProvider, variables: { marketId, interval: Interval.INTERVAL_I1D, - since: new Date(yesterday * 1000).toISOString(), + since: new Date(yesterday).toISOString(), }, }); diff --git a/apps/explorer-e2e/cypress.config.js b/apps/explorer-e2e/cypress.config.js index 70a5a9970..007eaa048 100644 --- a/apps/explorer-e2e/cypress.config.js +++ b/apps/explorer-e2e/cypress.config.js @@ -10,7 +10,7 @@ module.exports = defineConfig({ }, baseUrl: 'http://localhost:3000', fileServerFolder: '.', - fixturesFolder: false, + fixturesFolder: './src/fixtures', specPattern: '**/*.cy.{js,jsx,ts,tsx}', modifyObstructiveCode: false, supportFile: './src/support/index.js', diff --git a/apps/explorer-e2e/src/fixtures/net_parameter_format_lookup.json b/apps/explorer-e2e/src/fixtures/net_parameter_format_lookup.json new file mode 100644 index 000000000..856a16184 --- /dev/null +++ b/apps/explorer-e2e/src/fixtures/net_parameter_format_lookup.json @@ -0,0 +1,121 @@ +{ + "eighteenDecimal": [ + "governance.proposal.asset.minProposerBalance", + "governance.proposal.asset.minVoterBalance", + "governance.proposal.freeform.minProposerBalance", + "governance.proposal.freeform.minVoterBalance", + "governance.proposal.market.minProposerBalance", + "governance.proposal.market.minVoterBalance", + "governance.proposal.updateMarket.minProposerBalance", + "governance.proposal.updateMarket.minVoterBalance", + "governance.proposal.updateNetParam.minProposerBalance", + "governance.proposal.updateNetParam.minVoterBalance", + "reward.staking.delegation.maxPayoutPerEpoch", + "reward.staking.delegation.maxPayoutPerParticipant", + "reward.staking.delegation.minimumValidatorStake", + "spam.protection.delegation.min.tokens", + "spam.protection.proposal.min.tokens", + "spam.protection.voting.min.tokens", + "validators.delegation.minAmount" + ], + "fiveDecimal": [ + "governance.proposal.updateAsset.minProposerBalance", + "governance.proposal.updateAsset.minVoterBalance", + "governance.proposal.updateAsset.requiredParticipation", + "governance.proposal.updateMarket.minProposerEquityLikeShare", + "market.fee.factors.infrastructureFee", + "market.fee.factors.makerFee", + "market.liquidity.bondPenaltyParameter", + "market.liquidity.maximumLiquidityFeeFactorLevel", + "market.liquidity.minimum.probabilityOfTrading.lpOrders", + "market.liquidity.probabilityOfTrading.tau.scaling", + "market.liquidity.stakeToCcySiskas", + "market.liquidity.targetstake.triggering.ratio", + "market.liquidityProvision.minLpStakeQuantumMultiple", + "market.liquidityProvision.shapes.maxSize", + "market.stake.target.scalingFactor", + "network.validators.ersatz.multipleOfTendermintValidators", + "network.validators.ersatz.rewardFactor", + "network.validators.incumbentBonus", + "network.validators.minimumEthereumEventsForNewValidator", + "network.validators.multisig.numberOfSigners", + "network.validators.tendermint.number", + "reward.staking.delegation.competitionLevel", + "reward.staking.delegation.delegatorShare", + "reward.staking.delegation.minValidators", + "reward.staking.delegation.optimalStakeMultiplier", + "reward.staking.delegation.payoutFraction", + "rewards.marketCreationQuantumMultiple", + "spam.pow.difficulty", + "spam.pow.increaseDifficulty", + "spam.pow.numberOfPastBlocks", + "spam.pow.numberOfTxPerBlock", + "spam.protection.max.batchSize", + "spam.protection.max.delegations", + "spam.protection.max.proposals", + "spam.protection.max.votes", + "spam.protection.maxUserTransfersPerEpoch", + "transfer.fee.factor", + "transfer.minTransferQuantumMultiple", + "snapshot.interval.length" + ], + "json": [ + "blockchains.ethereumConfig", + "market.margin.scalingFactors", + "market.monitor.price.defaultParameters" + ], + "percentage": [ + "governance.proposal.asset.requiredMajority", + "governance.proposal.asset.requiredParticipation", + "governance.proposal.freeform.requiredMajority", + "governance.proposal.freeform.requiredParticipation", + "governance.proposal.market.requiredMajority", + "governance.proposal.market.requiredParticipation", + "governance.proposal.updateMarket.requiredMajority", + "governance.proposal.updateMarket.requiredMajorityLP", + "governance.proposal.updateMarket.requiredParticipation", + "governance.proposal.updateMarket.requiredParticipationLP", + "governance.proposal.updateNetParam.requiredMajority", + "governance.proposal.updateNetParam.requiredParticipation", + "validators.vote.required" + ], + "duration": [ + "governance.proposal.asset.maxClose", + "governance.proposal.asset.maxEnact", + "governance.proposal.asset.minClose", + "governance.proposal.asset.minEnact", + "governance.proposal.freeform.maxClose", + "governance.proposal.freeform.minClose", + "governance.proposal.market.maxClose", + "governance.proposal.market.maxEnact", + "governance.proposal.market.minClose", + "governance.proposal.market.minEnact", + "governance.proposal.updateAsset.maxClose", + "governance.proposal.updateAsset.maxEnact", + "governance.proposal.updateAsset.minClose", + "governance.proposal.updateAsset.minEnact", + "governance.proposal.updateMarket.maxClose", + "governance.proposal.updateMarket.maxEnact", + "governance.proposal.updateMarket.minClose", + "governance.proposal.updateMarket.minEnact", + "governance.proposal.updateNetParam.maxClose", + "governance.proposal.updateNetParam.maxEnact", + "governance.proposal.updateNetParam.minClose", + "governance.proposal.updateNetParam.minEnact", + "market.auction.maximumDuration", + "market.auction.minimumDuration", + "market.liquidity.providers.fee.distributionTimeStep", + "market.stake.target.timeWindow", + "market.value.windowLength", + "network.checkpoint.timeElapsedBetweenCheckpoints", + "network.floatingPointUpdates.delay", + "reward.staking.delegation.payoutDelay", + "spam.pow.hashFunction", + "validators.epoch.length" + ], + "date": [ + "limits.assets.proposeEnabledFrom", + "limits.markets.proposeEnabledFrom" + ], + "id": ["reward.asset"] +} diff --git a/apps/explorer-e2e/src/integration/network.cy.js b/apps/explorer-e2e/src/integration/network.cy.js index 7beb0498a..5fdd3f742 100644 --- a/apps/explorer-e2e/src/integration/network.cy.js +++ b/apps/explorer-e2e/src/integration/network.cy.js @@ -1,33 +1,257 @@ context('Network parameters page', { tags: '@smoke' }, function () { - before('visit token home page', function () { - cy.visit('/'); + before('navigate to network parameter page', function () { + cy.fixture('net_parameter_format_lookup').as('networkParameterFormat'); }); describe('Verify elements on page', function () { const networkParametersNavigation = 'a[href="/network-parameters"]'; + const networkParametersHeader = '[data-testid="network-param-header"]'; + const tableRows = '[data-testid="key-value-table-row"]'; - beforeEach('Navigate to network parameter page', function () { + before('navigate to network parameter page', function () { + cy.visit('/'); cy.get(networkParametersNavigation).click(); }); - it('Network paremeter page is displayed', function () { - verifyNetworkParametersPageDisplayed(); + it('should show network parameter heading at top of page', function () { + cy.get(networkParametersHeader) + .should('have.text', 'Network Parameters') + .and('be.visible'); }); - it('Network parameter page displayed on mobile', function () { + it('should list each of the network parameters available', function () { + cy.get_network_parameters().then((network_parameters) => { + const numberOfNetworkParametersInSystem = + Object.keys(network_parameters).length; + cy.get(tableRows).should( + 'have.length', + numberOfNetworkParametersInSystem + ); + }); + }); + + it('should list each network parameter displayed with json - in the correct format', function () { + cy.get_network_parameters().then((network_parameters) => { + network_parameters = Object.entries(network_parameters); + network_parameters.forEach((network_parameter) => { + const parameterName = network_parameter[0]; + const parameterValue = network_parameter[1]; + if (this.networkParameterFormat.json.includes(parameterName)) { + cy.get(tableRows) + .contains(parameterName) + .should('be.visible') + .next() + .invoke('text') + .convert_string_json_to_js_object() + .then((jsonOnPage) => { + cy.wrap(parameterValue, { log: false }) + .convert_string_json_to_js_object() + .then((jsonInSystem) => + assert.deepEqual( + jsonOnPage, + jsonInSystem, + `Checking ${parameterName} has the correct value of ${jsonInSystem}` + ) + ); + }); + } + }); + }); + }); + + it('should list each network parameter displayed as a percentage - in the correct format', function () { + cy.get_network_parameters().then((network_parameters) => { + network_parameters = Object.entries(network_parameters); + network_parameters.forEach((network_parameter) => { + const parameterName = network_parameter[0]; + const parameterValue = network_parameter[1]; + if (this.networkParameterFormat.percentage.includes(parameterName)) { + const formattedPercentageParameter = + (parseFloat(parameterValue) * 100).toFixed(0) + '%'; + cy.get(tableRows) + .contains(parameterName) + .should('be.visible') + .next() + .invoke('text') + .then((parameterValueOnPage) => { + assert.equal( + parameterValueOnPage, + formattedPercentageParameter, + `Checking ${parameterName} has the correct value of ${formattedPercentageParameter}` + ); + cy.contains(parameterValueOnPage).should('be.visible'); + }); + } + }); + }); + }); + + it('should list each network parameter displayed as an id - in the correct format', function () { + cy.get_network_parameters().then((network_parameters) => { + network_parameters = Object.entries(network_parameters); + network_parameters.forEach((network_parameter) => { + const parameterName = network_parameter[0]; + const parameterValue = network_parameter[1]; + if (this.networkParameterFormat.id.includes(parameterName)) { + cy.get(tableRows) + .contains(parameterName) + .should('be.visible') + .next() + .should('contain', parameterValue) + .and('be.visible') + .invoke('text'); + } + }); + }); + }); + + it('should list each network parameter displayed as a date - in the correct format', function () { + cy.get_network_parameters().then((network_parameters) => { + network_parameters = Object.entries(network_parameters); + network_parameters.forEach((network_parameter) => { + const parameterName = network_parameter[0]; + const parameterValue = network_parameter[1]; + if (this.networkParameterFormat.date.includes(parameterName)) { + cy.get(tableRows) + .contains(parameterName) + .should('be.visible') + .next() + .should('contain', parameterValue) + .and('be.visible'); + } + }); + }); + }); + + it('should list each network parameter displayed as a duration - in the correct format', function () { + cy.get_network_parameters().then((network_parameters) => { + network_parameters = Object.entries(network_parameters); + network_parameters.forEach((network_parameter) => { + const parameterName = network_parameter[0]; + const parameterValue = network_parameter[1]; + if (this.networkParameterFormat.duration.includes(parameterName)) { + cy.get(tableRows) + .contains(parameterName) + .should('be.visible') + .next() + .should('contain', parameterValue) + .and('be.visible'); + } + }); + }); + }); + + it('should list each network parameter displayed as a currency value with four decimals - in the correct format', function () { + cy.get_network_parameters().then((network_parameters) => { + network_parameters = Object.entries(network_parameters); + network_parameters.forEach((network_parameter) => { + const parameterName = network_parameter[0]; + const parameterValue = network_parameter[1]; + if (this.networkParameterFormat.fiveDecimal.includes(parameterName)) { + cy.convert_number_to_four_decimal(parameterValue) + .add_commas_to_number_if_large_enough() + .then((parameterValueFormatted) => { + cy.get(tableRows) + .contains(parameterName) + .should('be.visible') + .next() + .invoke('text') + .then((parameterValueOnPage) => { + assert.equal( + parameterValueOnPage, + parameterValueFormatted, + `Checking ${parameterName} has the correct value of ${parameterValueFormatted}` + ); + cy.contains(parameterValueOnPage).should('be.visible'); + }); + }); + } + }); + }); + }); + + it('should list each network parameter displayed as a currency value with eighteen decimals - in the correct format', function () { + cy.get_network_parameters().then((network_parameters) => { + network_parameters = Object.entries(network_parameters); + network_parameters.forEach((network_parameter) => { + const parameterName = network_parameter[0]; + const parameterValue = network_parameter[1]; + if ( + this.networkParameterFormat.eighteenDecimal.includes(parameterName) + ) { + cy.convert_number_to_eighteen_decimal(parameterValue) + .add_commas_to_number_if_large_enough() + .then((parameterValueFormatted) => { + cy.get(tableRows) + .contains(parameterName) + .should('be.visible') + .next() + .invoke('text') + .then((parameterValueOnPage) => { + assert.equal( + parameterValueOnPage, + parameterValueFormatted, + `Checking ${parameterName} has the correct value of ${parameterValueFormatted}` + ); + cy.contains(parameterValueOnPage).should('be.visible'); + }); + }); + } + }); + }); + }); + + it.skip('should be able to switch network parameter page - between light and dark mode', function () { + const whiteThemeSelectedMenuOptionColor = 'rgb(255, 7, 127)'; + const whiteThemeJsonFieldBackColor = 'rgb(255, 255, 255)'; + const whiteThemeSideMenuBackgroundColor = 'rgb(255, 255, 255)'; + const blackThemeSelectedMenuOptionColor = 'rgb(223, 255, 11)'; + const blackThemeJsonFieldBackColor = 'rgb(38, 38, 38)'; + const blackThemeSideMenuBackgroundColor = 'rgb(0, 0, 0)'; + const themeSwitcher = '[data-testid="theme-switcher"]'; + const jsonFields = '.hljs'; + const sideMenuBackground = '.absolute'; + + // White Mode + cy.get(themeSwitcher).click(); + cy.get(networkParametersNavigation) + .should('have.css', 'background-color') + .and('include', whiteThemeSelectedMenuOptionColor); + cy.get(jsonFields) + .should('have.css', 'background-color') + .and('include', whiteThemeJsonFieldBackColor); + cy.get(sideMenuBackground) + .should('have.css', 'background-color') + .and('include', whiteThemeSideMenuBackgroundColor); + + // Dark Mode + cy.get(themeSwitcher).click(); + cy.get(networkParametersNavigation) + .should('have.css', 'background-color') + .and('include', blackThemeSelectedMenuOptionColor); + cy.get(jsonFields) + .should('have.css', 'background-color') + .and('include', blackThemeJsonFieldBackColor); + cy.get(sideMenuBackground) + .should('have.css', 'background-color') + .and('include', blackThemeSideMenuBackgroundColor); + }); + + it('should be able to see network parameters - on mobile', function () { cy.common_switch_to_mobile_and_click_toggle(); cy.get(networkParametersNavigation).click(); - verifyNetworkParametersPageDisplayed(); + cy.get_network_parameters().then((network_parameters) => { + network_parameters = Object.entries(network_parameters); + network_parameters.forEach((network_parameter) => { + const parameterName = network_parameter[0]; + cy.get(tableRows) + .contains(parameterName) + .should('be.visible') + .next() + .should('not.be.empty') + .and('be.visible'); + }); + }); }); }); - - function verifyNetworkParametersPageDisplayed() { - cy.get('[data-testid="network-param-header"]').should( - 'have.text', - 'Network Parameters' - ); - cy.common_verify_json_parameters(18); - cy.common_verify_json_string_values(6); - cy.common_verify_json_int_values(7); - } }); diff --git a/apps/explorer-e2e/src/support/common.functions.js b/apps/explorer-e2e/src/support/common.functions.js index eb2c941b5..40b324305 100644 --- a/apps/explorer-e2e/src/support/common.functions.js +++ b/apps/explorer-e2e/src/support/common.functions.js @@ -1,3 +1,5 @@ +import { BigNumber } from 'bignumber.js'; + Cypress.Commands.add( 'common_validate_blocks_data_displayed', function (headerTestId) { @@ -25,33 +27,6 @@ Cypress.Commands.add('common_switch_to_mobile_and_click_toggle', function () { cy.get('[data-testid="open-menu"]').click(); }); -Cypress.Commands.add('common_verify_json_parameters', function (expectedNum) { - cy.get('.hljs-attr') - .should('have.length.at.least', expectedNum) - .each(($paramName) => { - cy.wrap($paramName).should('not.be.empty'); - }); -}); - -Cypress.Commands.add( - 'common_verify_json_string_values', - function (expectedNum) { - cy.get('.hljs-string') - .should('have.length.at.least', expectedNum) - .each(($paramValue) => { - cy.wrap($paramValue).should('not.be.empty'); - }); - } -); - -Cypress.Commands.add('common_verify_json_int_values', function (expectedNum) { - cy.get('.hljs-number') - .should('have.length.at.least', expectedNum) - .each(($paramValue) => { - cy.wrap($paramValue).should('not.be.empty'); - }); -}); - Cypress.Commands.add('monitor_clipboard', () => { cy.window().then((win) => { return cy.stub(win, 'prompt').returns(win.prompt); @@ -72,6 +47,33 @@ Cypress.Commands.add( 'convert_string_json_to_js_object', { prevSubject: true }, (jsonBlobString) => { + // Note: this is a chaining function return JSON.parse(jsonBlobString); } ); + +Cypress.Commands.add( + 'add_commas_to_number_if_large_enough', + { prevSubject: true }, + (number) => { + // This will turn 10000000.0000 into 10,000,000.000 + // Note: this is a chaining function + const beforeDecimal = number.split('.')[0]; + const afterDecimal = number.split('.')[1]; + const beforeDecimalWithCommas = beforeDecimal + .toString() + .replace(/\B(?=(\d{3})+(?!\d))/g, ','); + const formattedValue = beforeDecimalWithCommas + '.' + afterDecimal; + return formattedValue; + } +); + +Cypress.Commands.add('convert_number_to_eighteen_decimal', (number) => { + // this will take a number like this : 700000000000000000000 + // and convert it to a number like this: 700.000000000000000000 + return BigNumber((number / 1000000000000000000).toString()).toFixed(18); +}); + +Cypress.Commands.add('convert_number_to_four_decimal', (number) => { + return parseFloat(number).toFixed(4); +}); diff --git a/apps/explorer/.env b/apps/explorer/.env index b06a37b5c..0a312cb52 100644 --- a/apps/explorer/.env +++ b/apps/explorer/.env @@ -6,6 +6,7 @@ NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https: NX_VEGA_ENV=STAGNET3 NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz +NX_BLOCK_EXPLORER= # App flags NX_EXPLORER_ASSETS=1 diff --git a/apps/explorer/.env.devnet b/apps/explorer/.env.devnet index 0953fb115..fb55fa69f 100644 --- a/apps/explorer/.env.devnet +++ b/apps/explorer/.env.devnet @@ -7,3 +7,4 @@ NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}' NX_VEGA_ENV=DEVNET NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions +NX_BLOCK_EXPLORER= diff --git a/apps/explorer/.env.mainnet b/apps/explorer/.env.mainnet index 13281de02..ed6207bc9 100644 --- a/apps/explorer/.env.mainnet +++ b/apps/explorer/.env.mainnet @@ -7,3 +7,4 @@ NX_VEGA_URL=https://api.vega.xyz/query NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}' NX_VEGA_ENV=MAINNET NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions +NX_BLOCK_EXPLORER= diff --git a/apps/explorer/.env.stagnet3 b/apps/explorer/.env.stagnet3 index 3cb62f060..3ef8df81f 100644 --- a/apps/explorer/.env.stagnet3 +++ b/apps/explorer/.env.stagnet3 @@ -7,3 +7,4 @@ NX_VEGA_URL=https://api.n01.stagnet3.vega.xyz/graphql NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}' NX_VEGA_ENV=STAGNET3 NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions +NX_BLOCK_EXPLORER= diff --git a/apps/explorer/.env.testnet b/apps/explorer/.env.testnet index 394e0a07b..9a249d2bd 100644 --- a/apps/explorer/.env.testnet +++ b/apps/explorer/.env.testnet @@ -1,6 +1,7 @@ # App configuration variables NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz +NX_BLOCK_EXPLORER=https://n13.testnet.vega.xyz/rest NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n07.testnet.vega.xyz/websocket NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}' diff --git a/apps/explorer/.env.vegacapsule b/apps/explorer/.env.vegacapsule index cc49be5cb..a0b854c9a 100644 --- a/apps/explorer/.env.vegacapsule +++ b/apps/explorer/.env.vegacapsule @@ -5,3 +5,4 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket NX_VEGA_URL=http://localhost:3003/query NX_VEGA_ENV=CUSTOM NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions +NX_BLOCK_EXPLORER= diff --git a/apps/explorer/src/app/components/txs/txs-infinite-list-item.spec.tsx b/apps/explorer/src/app/components/txs/txs-infinite-list-item.spec.tsx index 2673042e9..9222baa62 100644 --- a/apps/explorer/src/app/components/txs/txs-infinite-list-item.spec.tsx +++ b/apps/explorer/src/app/components/txs/txs-infinite-list-item.spec.tsx @@ -1,92 +1,90 @@ import { TxsInfiniteListItem } from './txs-infinite-list-item'; -import { render, screen, fireEvent, act } from '@testing-library/react'; +import { render, screen } 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', () => { + it('should display "missing vital data" if "type" data missing', () => { render( ); expect(screen.getByText('Missing vital data')).toBeInTheDocument(); }); - it('should display "missing vital data" if "Command" data missing', () => { + it('should display "missing vital data" if "hash" data missing', () => { render( ); expect(screen.getByText('Missing vital data')).toBeInTheDocument(); }); - it('should display "missing vital data" if "Pubkey" data missing', () => { + it('should display "missing vital data" if "submitter" data missing', () => { render( ); expect(screen.getByText('Missing vital data')).toBeInTheDocument(); }); - it('should display "missing vital data" if "TxHash" data missing', () => { + it('should display "missing vital data" if "block" data missing', () => { render( + ); + expect(screen.getByText('Missing vital data')).toBeInTheDocument(); + }); + + it('should display "missing vital data" if "index" data missing', () => { + render( + ); expect(screen.getByText('Missing vital data')).toBeInTheDocument(); }); it('renders data correctly', () => { - const testCommandData = JSON.stringify({ - test: 'test of command data', - }); - render( ); 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(); + expect(screen.getByTestId('tx-type')).toHaveTextContent('testType'); + expect(screen.getByTestId('tx-block')).toHaveTextContent( + 'Block 1 (index 1)' + ); }); }); diff --git a/apps/explorer/src/app/components/txs/txs-infinite-list-item.tsx b/apps/explorer/src/app/components/txs/txs-infinite-list-item.tsx index 17c545efe..8dedfddec 100644 --- a/apps/explorer/src/app/components/txs/txs-infinite-list-item.tsx +++ b/apps/explorer/src/app/components/txs/txs-infinite-list-item.tsx @@ -1,69 +1,60 @@ -import React, { useState } from 'react'; -import { - Dialog, - Icon, - Intent, - SyntaxHighlighter, -} from '@vegaprotocol/ui-toolkit'; +import React from 'react'; 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'; +import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response'; +import { toHex } from '../search/detect-search'; const TRUNCATE_LENGTH = 14; export const TxsInfiniteListItem = ({ - TxHash, - PubKey, - Type, - Command, -}: ChainExplorerTxResponse) => { - const [open, setOpen] = useState(false); - - if (!TxHash || !PubKey || !Type || !Command) { + hash, + submitter, + type, + block, + index, +}: Partial) => { + if ( + !hash || + !submitter || + !type || + block === undefined || + index === undefined + ) { return
Missing vital data
; } return (
-
+
+ +
+
-
+
-
- - - setOpen(false)} - intent={Intent.None} - > - - +
+
); diff --git a/apps/explorer/src/app/components/txs/txs-infinite-list.spec.tsx b/apps/explorer/src/app/components/txs/txs-infinite-list.spec.tsx index 97e100cd5..9031496e8 100644 --- a/apps/explorer/src/app/components/txs/txs-infinite-list.spec.tsx +++ b/apps/explorer/src/app/components/txs/txs-infinite-list.spec.tsx @@ -1,18 +1,34 @@ import { TxsInfiniteList } from './txs-infinite-list'; import { render, screen, fireEvent, act } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; +import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response'; -const generateTxs = (number: number) => { +const generateTxs = (number: number): BlockExplorerTransaction[] => { 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', + block: '87901', + index: 2, + hash: '0F8B98DA0923A50786B852D9CA11E051CACC4C733E1DB93D535C7D81DBD10F6F', + submitter: + '4b782482f587d291e8614219eb9a5ee9280fa2c58982dee71d976782a9be1964', + type: 'Submit Order', + code: 0, + cursor: '87901.2', + command: { + nonce: '4214037379192575529', + blockHeight: '87898', + orderSubmission: { + marketId: + 'b4d0a070f5cc73a7d53b23d6f63f8cb52e937ed65d2469a3af4cc1e80e155fcf', + price: '14525946', + size: '54', + side: 'SIDE_SELL', + timeInForce: 'TIME_IN_FORCE_GTT', + expiresAt: '1664966445481288736', + type: 'TYPE_LIMIT', + reference: 'traderbot', + peggedOrder: null, + }, + }, })); }; @@ -41,7 +57,9 @@ describe('Txs infinite list', () => { error={Error('test error!')} /> ); - expect(screen.getByText('Error: test error!')).toBeInTheDocument(); + expect( + screen.getByText('Cannot fetch transaction: Error: test error!') + ).toBeInTheDocument(); }); it('item renders data of n length into list of n length', () => { diff --git a/apps/explorer/src/app/components/txs/txs-infinite-list.tsx b/apps/explorer/src/app/components/txs/txs-infinite-list.tsx index 5a7bc9182..055412cb3 100644 --- a/apps/explorer/src/app/components/txs/txs-infinite-list.tsx +++ b/apps/explorer/src/app/components/txs/txs-infinite-list.tsx @@ -3,19 +3,19 @@ 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'; +import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response'; interface TxsInfiniteListProps { hasMoreTxs: boolean; areTxsLoading: boolean | undefined; - txs: ChainExplorerTxResponse[] | undefined; + txs: BlockExplorerTransaction[] | undefined; loadMoreTxs: () => void; error: Error | undefined; className?: string; } interface ItemProps { - index: ChainExplorerTxResponse; + index: BlockExplorerTransaction; style: React.CSSProperties; isLoading: boolean; error: Error | undefined; @@ -27,19 +27,19 @@ const NOOP = () => {}; const Item = ({ index, style, isLoading, error }: ItemProps) => { let content; if (error) { - content = t(`${error}`); + content = t(`Cannot fetch transaction: ${error}`); } else if (isLoading) { content = t('Loading...'); } else { - const { TxHash, PubKey, Type, Command, Sig, Nonce } = index; + const { hash, submitter, type, command, block, index: blockIndex } = index; content = ( ); } @@ -71,10 +71,11 @@ export const TxsInfiniteList = ({ return (
-
-
Txn hash
-
Party
+
Type
+
Submitted By
+
Transaction ID
+
Block
{ const { data } = useQuery(ASSETS_QUERY); - const assets = getAssets(data); + const assets = + data?.assetsConnection?.edges + ?.filter((e) => e && e?.node) + .map((e) => e?.node as AssetsQuery_assetsConnection_edges_node) || []; return (
diff --git a/apps/explorer/src/app/routes/router-config.tsx b/apps/explorer/src/app/routes/router-config.tsx index b8602ff31..68a5e9183 100644 --- a/apps/explorer/src/app/routes/router-config.tsx +++ b/apps/explorer/src/app/routes/router-config.tsx @@ -13,7 +13,7 @@ import Genesis from './genesis'; import { Block } from './blocks/id'; import { Blocks } from './blocks/home'; import { Tx } from './txs/id'; -import { TxsHome, TxsHomeFallback } from './txs/home'; +import { TxsList } from './txs/home'; import { PendingTxs } from './pending'; import flags from '../config/flags'; import { t } from '@vegaprotocol/react-helpers'; @@ -141,7 +141,7 @@ const routerConfig = [ }, { index: true, - element: flags.txsList ? : , + element: , }, ], }, diff --git a/apps/explorer/src/app/routes/txs/home/index.tsx b/apps/explorer/src/app/routes/txs/home/index.tsx index 17bad9184..d2ae19b1c 100644 --- a/apps/explorer/src/app/routes/txs/home/index.tsx +++ b/apps/explorer/src/app/routes/txs/home/index.tsx @@ -1,86 +1,73 @@ import { DATA_SOURCES } from '../../../config'; -import { useCallback, useState, useMemo } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { t, useFetch } from '@vegaprotocol/react-helpers'; import { RouteTitle } from '../../../components/route-title'; import { BlocksRefetch } from '../../../components/blocks'; -import { JumpToBlock } from '../../../components/jump-to-block'; 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'; - -interface TxsProps { - latestBlockHeight: string; -} +import type { + BlockExplorerTransaction, + BlockExplorerTransactions, +} from '../../../routes/types/block-explorer-response'; interface TxsStateProps { - txsData: ChainExplorerTxResponse[]; + txsData: BlockExplorerTransaction[]; hasMoreTxs: boolean; - nextPage: number; + lastCursor: string; } -const Txs = ({ latestBlockHeight }: TxsProps) => { - const [{ txsData, hasMoreTxs, nextPage }, setTxsState] = +const BE_TXS_PER_REQUEST = 100; + +export const TxsList = () => { + const [{ txsData, hasMoreTxs, lastCursor }, setTxsState] = useState({ txsData: [], hasMoreTxs: true, - nextPage: 1, + lastCursor: '', }); - const reusedBodyParams = useMemo( - () => ({ - node_url: DATA_SOURCES.tendermintUrl, - transaction_height: parseInt(latestBlockHeight), - page_size: 30, - }), - [latestBlockHeight] - ); - const { - state: { error, loading }, + state: { data, error, loading }, refetch, - } = useFetch( - DATA_SOURCES.chainExplorerUrl, - { - method: 'POST', - body: JSON.stringify(reusedBodyParams), - }, + } = useFetch( + `${DATA_SOURCES.blockExplorerUrl}/transactions?` + + new URLSearchParams({ + limit: BE_TXS_PER_REQUEST.toString(10), + }), + {}, false ); - const loadTxs = useCallback(async () => { - const data = await refetch( - undefined, - JSON.stringify({ - ...reusedBodyParams, - page_number: nextPage, - }) - ); - - if (data) { + useEffect(() => { + if (data?.transactions?.length) { setTxsState((prev) => ({ - ...prev, - nextPage: prev.nextPage + 1, + txsData: [...prev.txsData, ...data.transactions], hasMoreTxs: true, - txsData: [...prev.txsData, ...(data as ChainExplorerTxResponse[])], + lastCursor: + data.transactions[data.transactions.length - 1].cursor || '', })); } - }, [nextPage, refetch, reusedBodyParams]); + }, [data?.transactions]); + + const loadTxs = useCallback(() => { + return refetch({ + limit: BE_TXS_PER_REQUEST, + before: lastCursor, + }); + }, [lastCursor, refetch]); + + const refreshTxs = useCallback(async () => { + setTxsState((prev) => ({ + ...prev, + lastCursor: '', + hasMoreTxs: true, + txsData: [], + })); + }, [setTxsState]); return (
{t('Transactions')} - - refetch( - undefined, - JSON.stringify({ - ...reusedBodyParams, - page_number: 1, - }) - ) - } - /> + { error={error} className="mb-28" /> -
); }; - -export const TxsHome = () => { - const { - state: { data, error, loading }, - } = useFetch( - `${DATA_SOURCES.tendermintUrl}/blockchain` - ); - - return ( - ( - - )} - /> - ); -}; - -export const TxsHomeFallback = () => ( - <> - {t('Transactions')} -
- The transactions list is currently disabled. Please use the search bar to - discover transaction data -
- -); diff --git a/apps/explorer/src/app/routes/types/block-explorer-response.d.ts b/apps/explorer/src/app/routes/types/block-explorer-response.d.ts new file mode 100644 index 000000000..d0c381fdc --- /dev/null +++ b/apps/explorer/src/app/routes/types/block-explorer-response.d.ts @@ -0,0 +1,14 @@ +export interface BlockExplorerTransaction { + block: string; + index: number; + hash: string; + submitter: string; + type: string; + code: number; + cursor: string; + command: Record; +} + +export interface BlockExplorerTransactions { + transactions: BlockExplorerTransaction[]; +} diff --git a/apps/static/src/assets/mainnet-tranches.json b/apps/static/src/assets/mainnet-tranches.json index 886c0cd21..66b3f7798 100644 --- a/apps/static/src/assets/mainnet-tranches.json +++ b/apps/static/src/assets/mainnet-tranches.json @@ -232,7 +232,7 @@ "tranche_end": "2023-12-05T00:00:00.000Z", "total_added": "129999.45", "total_removed": "0", - "locked_amount": "101055.803023481857846155", + "locked_amount": "99808.964557038223180575", "deposits": [ { "amount": "129999.45", @@ -298,7 +298,7 @@ "tranche_end": "2023-09-03T00:00:00.000Z", "total_added": "52600", "total_removed": "0", - "locked_amount": "47987.1788178589567", + "locked_amount": "47229.74949264333032", "deposits": [ { "amount": "2600", @@ -471,7 +471,7 @@ "tranche_end": "2023-09-17T00:00:00.000Z", "total_added": "5000", "total_removed": "0", - "locked_amount": "4753.299720953831", + "locked_amount": "4681.3007356671745", "deposits": [ { "amount": "5000", @@ -682,7 +682,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "97499.58", "total_removed": "0", - "locked_amount": "42348.530615082211097964", + "locked_amount": "41125.4982277578856557894", "deposits": [ { "amount": "97499.58", @@ -715,7 +715,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "135173.4239508", "total_removed": "0", - "locked_amount": "57883.13018201161087005483132", + "locked_amount": "56211.456056272351055479479", "deposits": [ { "amount": "135173.4239508", @@ -748,7 +748,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "32499.86", "total_removed": "0", - "locked_amount": "17815.295509758479255574", + "locked_amount": "17300.786905050761868906", "deposits": [ { "amount": "32499.86", @@ -781,7 +781,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "10833.29", "total_removed": "0", - "locked_amount": "5798.705812890794772696", + "locked_amount": "5631.238254731752483847", "deposits": [ { "amount": "10833.29", @@ -814,7 +814,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "22749.93", "total_removed": "0", - "locked_amount": "21676.857446138743511523", + "locked_amount": "21050.826310536649083198", "deposits": [ { "amount": "6500", @@ -889,7 +889,7 @@ "tranche_end": "2022-11-01T00:00:00.000Z", "total_added": "30000", "total_removed": "0", - "locked_amount": "4400.6868961352664", + "locked_amount": "3543.74245169082", "deposits": [ { "amount": "7500", @@ -1006,7 +1006,7 @@ "tranche_end": "2023-06-02T00:00:00.000Z", "total_added": "1939928.38", "total_removed": "626880.6921411330574", - "locked_amount": "1275520.872149814893848934", + "locked_amount": "1247586.29717205741791664", "deposits": [ { "amount": "1852091.69", @@ -1303,7 +1303,7 @@ "tranche_end": "2023-02-01T00:00:00.000Z", "total_added": "42500", "total_removed": "0", - "locked_amount": "27484.30643619162825", + "locked_amount": "26270.30180656199925", "deposits": [ { "amount": "12500", @@ -2181,7 +2181,7 @@ "tranche_start": "2021-09-05T00:00:00.000Z", "tranche_end": "2022-09-30T00:00:00.000Z", "total_added": "60916.66666633337", - "total_removed": "22679.59090768217556896", + "total_removed": "22920.80703869967556896", "locked_amount": "0", "deposits": [ { @@ -2281,6 +2281,11 @@ } ], "withdrawals": [ + { + "amount": "241.2161310175", + "user": "0x1887D97F9C875108Aa6bE109B282f87A666472f2", + "tx": "0xeb4604db9ecd236bfe8a3481989577fd57b942e9900342c23497dedfdf85a0ef" + }, { "amount": "1983.33333333333", "user": "0xED5847639328EDd38E7CE934442FF4eE8e714f7C", @@ -2989,6 +2994,12 @@ } ], "withdrawals": [ + { + "amount": "241.2161310175", + "user": "0x1887D97F9C875108Aa6bE109B282f87A666472f2", + "tranche_id": 13, + "tx": "0xeb4604db9ecd236bfe8a3481989577fd57b942e9900342c23497dedfdf85a0ef" + }, { "amount": "339.9854953025", "user": "0x1887D97F9C875108Aa6bE109B282f87A666472f2", @@ -3075,8 +3086,8 @@ } ], "total_tokens": "4250", - "withdrawn_tokens": "4008.7838689825", - "remaining_tokens": "241.2161310175" + "withdrawn_tokens": "4250", + "remaining_tokens": "0" }, { "address": "0x9fd50776F133751E8Ae6abE1Be124638Bb917E05", @@ -5940,7 +5951,7 @@ "tranche_start": "2021-09-03T00:00:00.000Z", "tranche_end": "2022-09-03T00:00:00.000Z", "total_added": "39600.000000000000000003", - "total_removed": "23868.97808024224", + "total_removed": "23872.84141180056", "locked_amount": "0", "deposits": [ { @@ -12560,6 +12571,11 @@ } ], "withdrawals": [ + { + "amount": "3.86333155832", + "user": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2", + "tx": "0x068081c78445c62a22f68a81cbfd73d1c906b35c31882e5dcbd95b158485b227" + }, { "amount": "505", "user": "0x2f28F3Be9315cD7F2475F6500020262bd8505fA1", @@ -19110,6 +19126,12 @@ } ], "withdrawals": [ + { + "amount": "3.86333155832", + "user": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2", + "tranche_id": 11, + "tx": "0x068081c78445c62a22f68a81cbfd73d1c906b35c31882e5dcbd95b158485b227" + }, { "amount": "41.64068004762", "user": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2", @@ -19124,8 +19146,8 @@ } ], "total_tokens": "104", - "withdrawn_tokens": "100.13666844168", - "remaining_tokens": "3.86333155832" + "withdrawn_tokens": "104", + "remaining_tokens": "0" }, { "address": "0xd996efF75E43357F04E3f37D61EF6A6851A0b8f1", @@ -24352,8 +24374,8 @@ "tranche_start": "2022-03-05T00:00:00.000Z", "tranche_end": "2023-06-05T00:00:00.000Z", "total_added": "3732368.4671", - "total_removed": "212048.9552173080602", - "locked_amount": "1984532.81602302279885050992", + "total_removed": "216488.8190253099792", + "locked_amount": "1941607.10006823176798276368", "deposits": [ { "amount": "1998.95815", @@ -24522,6 +24544,11 @@ } ], "withdrawals": [ + { + "amount": "4439.863808001919", + "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", + "tx": "0x0036b66c9129b9c96b3e456e7958216ed7a9d4e9f2ad548bb8b4e8a036bd70d6" + }, { "amount": "3087.2670009465625", "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", @@ -24696,6 +24723,12 @@ } ], "withdrawals": [ + { + "amount": "4439.863808001919", + "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", + "tranche_id": 1, + "tx": "0x0036b66c9129b9c96b3e456e7958216ed7a9d4e9f2ad548bb8b4e8a036bd70d6" + }, { "amount": "3087.2670009465625", "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", @@ -24782,8 +24815,8 @@ } ], "total_tokens": "187637.95", - "withdrawn_tokens": "84806.4863872416465", - "remaining_tokens": "102831.4636127583535" + "withdrawn_tokens": "89246.3501952435655", + "remaining_tokens": "98391.5998047564345" }, { "address": "0x1A71e3ED1996CAbB91bB043f880CE963D601707e", @@ -25264,8 +25297,8 @@ "tranche_start": "2022-06-05T00:00:00.000Z", "tranche_end": "2023-12-05T00:00:00.000Z", "total_added": "15870102.715470999700000001", - "total_removed": "222408.2894258465985744", - "locked_amount": "12336713.5320731118005870614596262497620979", + "total_removed": "224997.4571492768169494", + "locked_amount": "12184501.6993918133532141480489084640578535", "deposits": [ { "amount": "16249.93", @@ -25769,6 +25802,21 @@ } ], "withdrawals": [ + { + "amount": "243.932422174205", + "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", + "tx": "0x9962e848bcc9ec1ee7db91bafe00948c766bf7184d20f39bfe08539928844213" + }, + { + "amount": "981.32183505687375", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0xdc3bc277d041e6dff7fb11e0be0a500fadda69ab829b0c6d5caa196031062f40" + }, + { + "amount": "432.7384147709755", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0xa3998f6f73372f3841256fc23cb4e182545252515cd8d25d5d228d13636b435c" + }, { "amount": "668.448073601292875", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -25839,6 +25887,16 @@ "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", "tx": "0x9cf6b1e7e12f0786a9aff09f0379ba8162ea88a8357a8e28c562b618093d0f5f" }, + { + "amount": "501.731430959210375", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0x1e91d12aef9afe631095ded8bd5ff6e0a40e5aa87271f46078b3175f41f4ee39" + }, + { + "amount": "429.44362046895375", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0x10f121ed91c0f605893d86d1eed2ccca505b86c73c89c30e0dfb90edcff637b0" + }, { "amount": "504.652814859004625", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -26512,6 +26570,18 @@ } ], "withdrawals": [ + { + "amount": "981.32183505687375", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0xdc3bc277d041e6dff7fb11e0be0a500fadda69ab829b0c6d5caa196031062f40" + }, + { + "amount": "432.7384147709755", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0xa3998f6f73372f3841256fc23cb4e182545252515cd8d25d5d228d13636b435c" + }, { "amount": "668.448073601292875", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -26572,6 +26642,18 @@ "tranche_id": 2, "tx": "0x9cf6b1e7e12f0786a9aff09f0379ba8162ea88a8357a8e28c562b618093d0f5f" }, + { + "amount": "501.731430959210375", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0x1e91d12aef9afe631095ded8bd5ff6e0a40e5aa87271f46078b3175f41f4ee39" + }, + { + "amount": "429.44362046895375", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0x10f121ed91c0f605893d86d1eed2ccca505b86c73c89c30e0dfb90edcff637b0" + }, { "amount": "504.652814859004625", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -27150,8 +27232,8 @@ } ], "total_tokens": "259998.8875", - "withdrawn_tokens": "57731.002552864795", - "remaining_tokens": "202267.884947135205" + "withdrawn_tokens": "60076.237854120808375", + "remaining_tokens": "199922.649645879191625" }, { "address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c", @@ -28045,6 +28127,12 @@ } ], "withdrawals": [ + { + "amount": "243.932422174205", + "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", + "tranche_id": 2, + "tx": "0x9962e848bcc9ec1ee7db91bafe00948c766bf7184d20f39bfe08539928844213" + }, { "amount": "169.6116120463555", "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", @@ -28119,8 +28207,8 @@ } ], "total_tokens": "12362.05", - "withdrawn_tokens": "2584.0836409459565", - "remaining_tokens": "9777.9663590540435" + "withdrawn_tokens": "2828.0160631201615", + "remaining_tokens": "9534.0339368798385" }, { "address": "0xb091D456d0dFCB94dcba6f355379056C5bb995fC", @@ -28744,8 +28832,8 @@ "tranche_start": "2021-11-05T00:00:00.000Z", "tranche_end": "2023-05-05T00:00:00.000Z", "total_added": "14597706.0446472999", - "total_removed": "2923085.955595204497185312", - "locked_amount": "5667729.935859967841691532439599905", + "total_removed": "2926333.340895590665080812", + "locked_amount": "5527208.943810320731141048979540034", "deposits": [ { "amount": "129284.449", @@ -28954,6 +29042,16 @@ } ], "withdrawals": [ + { + "amount": "1360.2331260920135955", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x8c5fe9e7c9b1ff5e11cd044869b4d43b06512d8a8037c945315e44b2829b49d8" + }, + { + "amount": "598.630467392367358", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0xfccb647f645ad7c56c3f73a6b92b19dcad5100cf5dbbaf8a885793d353053f08" + }, { "amount": "927.5894688774561055", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -29024,6 +29122,16 @@ "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", "tx": "0xb45a95262772c307dd2f75b2cba4d5e7d12968b5a04a7ca6c59f5c99ab54815a" }, + { + "amount": "690.53070553304891625", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x16096cd1bc7539778177c7db0fcda97d0085a63b13ebd3a751648337b698d8aa" + }, + { + "amount": "597.99100136873802575", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x6fdfd3c077574cd9b9ede40db9488759ceac7d430e6ad09fdbd5a64bd87ce8b3" + }, { "amount": "700.967684681521309", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -31195,6 +31303,18 @@ } ], "withdrawals": [ + { + "amount": "1360.2331260920135955", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x8c5fe9e7c9b1ff5e11cd044869b4d43b06512d8a8037c945315e44b2829b49d8" + }, + { + "amount": "598.630467392367358", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0xfccb647f645ad7c56c3f73a6b92b19dcad5100cf5dbbaf8a885793d353053f08" + }, { "amount": "927.5894688774561055", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -31255,6 +31375,18 @@ "tranche_id": 3, "tx": "0xb45a95262772c307dd2f75b2cba4d5e7d12968b5a04a7ca6c59f5c99ab54815a" }, + { + "amount": "690.53070553304891625", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x16096cd1bc7539778177c7db0fcda97d0085a63b13ebd3a751648337b698d8aa" + }, + { + "amount": "597.99100136873802575", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x6fdfd3c077574cd9b9ede40db9488759ceac7d430e6ad09fdbd5a64bd87ce8b3" + }, { "amount": "700.967684681521309", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -33111,8 +33243,8 @@ } ], "total_tokens": "359123.469575", - "withdrawn_tokens": "219475.84527111689429425", - "remaining_tokens": "139647.62430388310570575" + "withdrawn_tokens": "222723.23057150306218975", + "remaining_tokens": "136400.23900349693781025" }, { "address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB", @@ -34223,8 +34355,8 @@ "tranche_start": "2021-10-05T00:00:00.000Z", "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "5778205.3912159303", - "total_removed": "1859061.122194459692887301", - "locked_amount": "1922450.97226335538560662121602032", + "total_removed": "1873909.449655528970703801", + "locked_amount": "1866930.278440655586530334992507438", "deposits": [ { "amount": "552496.6455", @@ -34368,6 +34500,16 @@ } ], "withdrawals": [ + { + "amount": "14848.19419062596735675", + "user": "0x9058e12e2F32cB1cD4D3123359963D77786477FC", + "tx": "0x51d2a4b9c2db0dc6c34ee296e468d44d074a1debd4271d66cb1eeb1cc449860f" + }, + { + "amount": "0.13327044331045975", + "user": "0x9058e12e2F32cB1cD4D3123359963D77786477FC", + "tx": "0x31bcddc1d9f267c2337fba36d44e2282388183e2608a7781fedeaa7abb002482" + }, { "amount": "4240.023826533383217", "user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90", @@ -35030,6 +35172,18 @@ } ], "withdrawals": [ + { + "amount": "14848.19419062596735675", + "user": "0x9058e12e2F32cB1cD4D3123359963D77786477FC", + "tranche_id": 4, + "tx": "0x51d2a4b9c2db0dc6c34ee296e468d44d074a1debd4271d66cb1eeb1cc449860f" + }, + { + "amount": "0.13327044331045975", + "user": "0x9058e12e2F32cB1cD4D3123359963D77786477FC", + "tranche_id": 4, + "tx": "0x31bcddc1d9f267c2337fba36d44e2282388183e2608a7781fedeaa7abb002482" + }, { "amount": "2155.49461457390087475", "user": "0x9058e12e2F32cB1cD4D3123359963D77786477FC", @@ -35044,8 +35198,8 @@ } ], "total_tokens": "27624.882275", - "withdrawn_tokens": "3835.43954817344395075", - "remaining_tokens": "23789.44272682655604925" + "withdrawn_tokens": "18683.76700924272176725", + "remaining_tokens": "8941.11526575727823275" }, { "address": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75", @@ -35753,8 +35907,8 @@ "tranche_start": "2022-06-05T00:00:00.000Z", "tranche_end": "2023-06-05T00:00:00.000Z", "total_added": "472355.6199999996", - "total_removed": "4160.13945227826", - "locked_amount": "314460.5687720519725132450634196", + "total_removed": "4675.66485244886", + "locked_amount": "307658.74370516207651625788635212", "deposits": [ { "amount": "3000", @@ -42373,6 +42527,16 @@ } ], "withdrawals": [ + { + "amount": "95.248756976", + "user": "0xA17b91BdDcE741528fDDF8E5738A767B3053ac18", + "tx": "0xad37bdd4cbd855be571f4fd5157688a34b1e9f9f90f93f9460e5123ca221a319" + }, + { + "amount": "48.7169590306", + "user": "0xB168ce7397Dc52ed13B4eD8119f309ec30DDa2c9", + "tx": "0xdca459e274a6629dbb7e9a0874f254b1c8970d73e46ceb42432a70e1690e4227" + }, { "amount": "65.770370368", "user": "0x7708B79e2bc3b7ab816E66aF33A8c9385f0FcA4b", @@ -42408,6 +42572,31 @@ "user": "0xA0beaa6EC671f4cC8B6D6cA52C46D6c252F525a8", "tx": "0x026f716e8e3cc425aaa9a78b34a685f788d52a14d843dc2ed2430a400194b1ac" }, + { + "amount": "24.760013952", + "user": "0x4d4AA3f302cbA998AAFC03F9d73484434ed9Fd53", + "tx": "0x6137b5d86d1038fbad53e50bb0d1f76dbd67a4fef4c2bf9176608c4d1e15ebbe" + }, + { + "amount": "13.344748856", + "user": "0x4eD2b3c68BB4fda084ce1591a210F4aC8b71234A", + "tx": "0x1ce993074ad983b356da0559cd03cde2632665ec9cddaf20ba384fc325cbde60" + }, + { + "amount": "135.474264332", + "user": "0xe28dBf57Ad23cc0c32b6769556CD3c64873b4330", + "tx": "0xc706b9ab1e410b4de90f3969faeec3b7bd71de1c3d1de4eb9ccda0b8be02d1a9" + }, + { + "amount": "61.83652968", + "user": "0x7345AaA0D0e4C4A46d921fA9323973956F2b7392", + "tx": "0xc79c54283a3bdd5944f0098641f9537a62c433718a4c391f01684255155ef9d2" + }, + { + "amount": "136.144127344", + "user": "0xb1EAD214506D0cD73785Dd09B3EfC2307133bf69", + "tx": "0xe563eb4f77cb43e4eeb099bf3d7134e54f2a2d046d77785570afa2869bc0f997" + }, { "amount": "52.731139014", "user": "0x28FC83947F02f59Cb36b40f97f2D32BBC5D00585", @@ -49885,6 +50074,12 @@ } ], "withdrawals": [ + { + "amount": "95.248756976", + "user": "0xA17b91BdDcE741528fDDF8E5738A767B3053ac18", + "tranche_id": 5, + "tx": "0xad37bdd4cbd855be571f4fd5157688a34b1e9f9f90f93f9460e5123ca221a319" + }, { "amount": "42.526268388", "user": "0xA17b91BdDcE741528fDDF8E5738A767B3053ac18", @@ -49893,8 +50088,8 @@ } ], "total_tokens": "400", - "withdrawn_tokens": "42.526268388", - "remaining_tokens": "357.473731612" + "withdrawn_tokens": "137.775025364", + "remaining_tokens": "262.224974636" }, { "address": "0x8CF85d1ecC6eDd70000c57E31ff8FC18633F7328", @@ -50888,10 +51083,17 @@ "tx": "0x96a22c369645e8945b4047374a05332f4054b50a492c43092e8bb8e974a006b9" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "48.7169590306", + "user": "0xB168ce7397Dc52ed13B4eD8119f309ec30DDa2c9", + "tranche_id": 5, + "tx": "0xdca459e274a6629dbb7e9a0874f254b1c8970d73e46ceb42432a70e1690e4227" + } + ], "total_tokens": "140", - "withdrawn_tokens": "0", - "remaining_tokens": "140" + "withdrawn_tokens": "48.7169590306", + "remaining_tokens": "91.2830409694" }, { "address": "0xdD37b0ff9aE7e2EDbABdc291e8d44431084dA4c2", @@ -54673,6 +54875,12 @@ } ], "withdrawals": [ + { + "amount": "13.344748856", + "user": "0x4eD2b3c68BB4fda084ce1591a210F4aC8b71234A", + "tranche_id": 5, + "tx": "0x1ce993074ad983b356da0559cd03cde2632665ec9cddaf20ba384fc325cbde60" + }, { "amount": "26.406887368", "user": "0x4eD2b3c68BB4fda084ce1591a210F4aC8b71234A", @@ -54705,8 +54913,8 @@ } ], "total_tokens": "400", - "withdrawn_tokens": "121.366349568", - "remaining_tokens": "278.633650432" + "withdrawn_tokens": "134.711098424", + "remaining_tokens": "265.288901576" }, { "address": "0x5c90765F50629570738fEe7b7FA82ae118f81Ed1", @@ -56226,10 +56434,17 @@ "tx": "0xe32a466fc780a0fb3fd84a804f622931ebfaf3f428bff0dc6d141270410e75f8" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "136.144127344", + "user": "0xb1EAD214506D0cD73785Dd09B3EfC2307133bf69", + "tranche_id": 5, + "tx": "0xe563eb4f77cb43e4eeb099bf3d7134e54f2a2d046d77785570afa2869bc0f997" + } + ], "total_tokens": "400", - "withdrawn_tokens": "0", - "remaining_tokens": "400" + "withdrawn_tokens": "136.144127344", + "remaining_tokens": "263.855872656" }, { "address": "0xDcD1000CB62FAE013aEd379d9F1287D828bcEaA3", @@ -56725,10 +56940,17 @@ "tx": "0xb1425d9b0d5f10c5b06236d6f9d61ebddd21c4027e0f41deb5ec227a1753c715" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "135.474264332", + "user": "0xe28dBf57Ad23cc0c32b6769556CD3c64873b4330", + "tranche_id": 5, + "tx": "0xc706b9ab1e410b4de90f3969faeec3b7bd71de1c3d1de4eb9ccda0b8be02d1a9" + } + ], "total_tokens": "400", - "withdrawn_tokens": "0", - "remaining_tokens": "400" + "withdrawn_tokens": "135.474264332", + "remaining_tokens": "264.525735668" }, { "address": "0xff2D0F83b812bfbFe5aafca081140C59f67d5fd3", @@ -58600,6 +58822,12 @@ } ], "withdrawals": [ + { + "amount": "61.83652968", + "user": "0x7345AaA0D0e4C4A46d921fA9323973956F2b7392", + "tranche_id": 5, + "tx": "0xc79c54283a3bdd5944f0098641f9537a62c433718a4c391f01684255155ef9d2" + }, { "amount": "201.207077628", "user": "0x7345AaA0D0e4C4A46d921fA9323973956F2b7392", @@ -58614,8 +58842,8 @@ } ], "total_tokens": "1200", - "withdrawn_tokens": "344.995395732", - "remaining_tokens": "855.004604268" + "withdrawn_tokens": "406.831925412", + "remaining_tokens": "793.168074588" }, { "address": "0x47181cf36aDFb0b5dB7EfDB123f403D890607841", @@ -61660,6 +61888,12 @@ } ], "withdrawals": [ + { + "amount": "24.760013952", + "user": "0x4d4AA3f302cbA998AAFC03F9d73484434ed9Fd53", + "tranche_id": 5, + "tx": "0x6137b5d86d1038fbad53e50bb0d1f76dbd67a4fef4c2bf9176608c4d1e15ebbe" + }, { "amount": "14.663413242", "user": "0x4d4AA3f302cbA998AAFC03F9d73484434ed9Fd53", @@ -61674,8 +61908,8 @@ } ], "total_tokens": "200", - "withdrawn_tokens": "42.270268898", - "remaining_tokens": "157.729731102" + "withdrawn_tokens": "67.03028285", + "remaining_tokens": "132.96971715" }, { "address": "0xd9390b46a1749DEe5325A490490491db9a826D1F", diff --git a/apps/token-e2e/cypress.config.js b/apps/token-e2e/cypress.config.js index 21bef6e8e..692d5dbd6 100644 --- a/apps/token-e2e/cypress.config.js +++ b/apps/token-e2e/cypress.config.js @@ -40,6 +40,9 @@ module.exports = defineConfig({ vegaWalletPublicKey: '02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65', vegaWalletPublicKeyShort: '02ecea…2f65', + vegaWalletPublicKey2: + '7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535', + vegaWalletPublicKey2Short: '7f9cf0…5535', vegaTokenContractAddress: '0xF41bD86d462D36b997C0bbb4D97a0a3382f205B7', vegaTokenAddress: '0x67175Da1D5e966e40D11c4B2519392B2058373de', txTimeout: { timeout: 70000 }, diff --git a/apps/token-e2e/src/fixtures/proposals/new-asset.json b/apps/token-e2e/src/fixtures/proposals/new-asset.json new file mode 100644 index 000000000..ac7cade60 --- /dev/null +++ b/apps/token-e2e/src/fixtures/proposals/new-asset.json @@ -0,0 +1,13 @@ +{ + "changes": { + "name": "USDT Coin", + "symbol": "USDT", + "decimals": "18", + "quantum": "1", + "erc20": { + "contractAddress": "0xb404c51bbc10dcbe948077f18a4b8e553d160084", + "withdrawThreshold": "10", + "lifetimeLimit": "10" + } + } +} diff --git a/apps/token-e2e/src/fixtures/proposals/new-market.json b/apps/token-e2e/src/fixtures/proposals/new-market.json new file mode 100644 index 000000000..4e6093343 --- /dev/null +++ b/apps/token-e2e/src/fixtures/proposals/new-market.json @@ -0,0 +1,80 @@ +{ + "changes": { + "decimalPlaces": "5", + "positionDecimalPlaces": "5", + "instrument": { + "name": "Oranges Daily", + "code": "ORANGES.24h", + "future": { + "settlementAsset": "8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4", + "quoteName": "tEuro", + "settlementDataDecimals": 5, + "oracleSpecForSettlementPrice": { + "pubKeys": ["0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"], + "filters": [ + { + "key": { + "name": "prices.BTC.value", + "type": "TYPE_INTEGER" + }, + "conditions": [ + { + "operator": "OPERATOR_GREATER_THAN", + "value": "0" + } + ] + } + ] + }, + "oracleSpecForTradingTermination": { + "pubKeys": ["0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"], + "filters": [ + { + "key": { + "name": "vegaprotocol.builtin.timestamp", + "type": "TYPE_TIMESTAMP" + }, + "conditions": [ + { + "operator": "OPERATOR_GREATER_THAN_OR_EQUAL", + "value": "1648684800000000000" + } + ] + } + ] + }, + "oracleSpecBinding": { + "settlementPriceProperty": "prices.BTC.value", + "tradingTerminationProperty": "vegaprotocol.builtin.timestamp" + } + } + }, + "metadata": ["sector:food", "sector:materials", "source:docs.vega.xyz"], + "priceMonitoringParameters": { + "triggers": [ + { + "horizon": "43200", + "probability": "0.9999999", + "auctionExtension": "600" + } + ] + }, + "liquidityMonitoringParameters": { + "targetStakeParameters": { + "timeWindow": "3600", + "scalingFactor": 10 + }, + "triggeringRatio": 0.7, + "auctionExtension": "1" + }, + "logNormal": { + "tau": 0.0001140771161, + "riskAversionParameter": 0.001, + "params": { + "mu": 0, + "r": 0.016, + "sigma": 0.8 + } + } + } +} diff --git a/apps/token-e2e/src/fixtures/proposals/freeform.json b/apps/token-e2e/src/fixtures/proposals/raw.json similarity index 83% rename from apps/token-e2e/src/fixtures/proposals/freeform.json rename to apps/token-e2e/src/fixtures/proposals/raw.json index 8643b7649..ebe2e397f 100644 --- a/apps/token-e2e/src/fixtures/proposals/freeform.json +++ b/apps/token-e2e/src/fixtures/proposals/raw.json @@ -1,6 +1,6 @@ { "rationale": { - "title": "An example freeform proposal with unique number of: ", + "title": "An example raw proposal with unique number of: ", "description": "I propose that everyone evaluate the following IPFS document and vote Yes if they agree. [bafybeigwwctpv37xdcwacqxvekr6e4kaemqsrv34em6glkbiceo3fcy4si](https://dweb.link/ipfs/bafybeigwwctpv37xdcwacqxvekr6e4kaemqsrv34em6glkbiceo3fcy4si)" }, "terms": { diff --git a/apps/token-e2e/src/fixtures/proposals/update-market.json b/apps/token-e2e/src/fixtures/proposals/update-market.json new file mode 100644 index 000000000..a307255cf --- /dev/null +++ b/apps/token-e2e/src/fixtures/proposals/update-market.json @@ -0,0 +1,69 @@ +{ + "marketId": "315a8e48db0a292c92b617264728048c82c20efc922c75fd292fc54e5c727c81", + "changes": { + "instrument": { + "code": "ORANGES.24h", + "future": { + "quoteName": "tEuro", + "settlementDataDecimals": 5, + "oracleSpecForSettlementPrice": { + "pubKeys": ["0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"], + "filters": [ + { + "key": { + "name": "prices.BTC.value", + "type": "TYPE_INTEGER" + }, + "conditions": [ + { + "operator": "OPERATOR_GREATER_THAN", + "value": "0" + } + ] + } + ] + }, + "oracleSpecForTradingTermination": { + "pubKeys": ["0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"], + "filters": [ + { + "key": { + "name": "vegaprotocol.builtin.timestamp", + "type": "TYPE_TIMESTAMP" + }, + "conditions": [ + { + "operator": "OPERATOR_GREATER_THAN_OR_EQUAL", + "value": "1648684800000000000" + } + ] + } + ] + }, + "oracleSpecBinding": { + "settlementPriceProperty": "prices.BTC.value", + "tradingTerminationProperty": "vegaprotocol.builtin.timestamp" + } + } + }, + "metadata": ["sector:energy", "sector:food", "source:docs.vega.xyz"], + "priceMonitoringParameters": { + "triggers": [ + { + "horizon": "43200", + "probability": "0.9999999", + "auctionExtension": "600" + } + ] + }, + "logNormal": { + "tau": 0.0001140771161, + "riskAversionParameter": 0.001, + "params": { + "mu": 0, + "r": 0.016, + "sigma": 0.3 + } + } + } +} diff --git a/apps/token-e2e/src/integration/flow/governance-flow.cy.js b/apps/token-e2e/src/integration/flow/governance-flow.cy.js index f6e7549de..982c8e8fb 100644 --- a/apps/token-e2e/src/integration/flow/governance-flow.cy.js +++ b/apps/token-e2e/src/integration/flow/governance-flow.cy.js @@ -1,5 +1,4 @@ /// - const vegaWalletUnstakedBalance = '[data-testid="vega-wallet-balance-unstaked"]'; const vegaWalletStakedBalances = @@ -28,16 +27,20 @@ const changeVoteButton = '[data-testid="change-vote-button"]'; const proposalDetailsTitle = '[data-testid="proposal-title"]'; const proposalDetailsDescription = '[data-testid="proposal-description"]'; const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]'; +const minVoteButton = '[data-testid="min-vote"]'; +const maxVoteButton = '[data-testid="max-vote"]'; const voteButtons = '[data-testid="vote-buttons"]'; +const votingDate = '[data-testid="voting-date"]'; +const voteTwoMinExtraNote = '[data-testid="voting-2-mins-extra"]'; const voteStatus = '[data-testid="vote-status"]'; const rejectProposalsLink = '[href="/governance/rejected"]'; const feedbackError = '[data-testid="Error"]'; -const txTimeout = Cypress.env('txTimeout'); -const epochTimeout = Cypress.env('epochTimeout'); -const proposalTimeout = { timeout: 14000 }; const restConnectorForm = '[data-testid="rest-connector-form"]'; const noOpenProposals = '[data-testid="no-open-proposals"]'; const noClosedProposals = '[data-testid="no-closed-proposals"]'; +const txTimeout = Cypress.env('txTimeout'); +const epochTimeout = Cypress.env('epochTimeout'); +const proposalTimeout = { timeout: 14000 }; const governanceProposalType = { NETWORK_PARAMETER: 'Network parameter', @@ -45,6 +48,7 @@ const governanceProposalType = { UPDATE_MARKET: 'Update market', NEW_ASSET: 'New asset', FREEFORM: 'Freeform', + RAW: 'raw proposal', }; context( @@ -142,7 +146,7 @@ context( }); }); - it('should be able to see that no proposals exist', function () { + it('Should be able to see that no proposals exist', function () { // 1004-VOTE-003 cy.get(noOpenProposals) .should('be.visible') @@ -152,13 +156,17 @@ context( .and('have.text', 'There are no enacted or rejected proposals'); }); + // 1005-PROP-002 + // 1005-PROP-003 it('Submit a proposal form - shows how many vega tokens are required to make a proposal', function () { + // 1005-PROP-005 cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET); cy.contains( `You must have at least ${this.minProposerBalance} VEGA associated to make a proposal` ).should('be.visible'); }); + // 1005-PROP-011 it( 'Able to submit a valid freeform proposal - with minimum required tokens associated', { tags: '@smoke' }, @@ -166,20 +174,19 @@ context( cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance ); - cy.navigate_to_page_if_not_already_loaded('governance'); cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); + cy.get(minVoteButton).should('be.visible'); // 1005-PROP-008 + cy.get(maxVoteButton).should('be.visible'); + cy.get(votingDate).should('not.be.empty'); + cy.get(voteTwoMinExtraNote).should( + 'contain.text', + 'we add 2 minutes of extra time' + ); cy.enter_unique_freeform_proposal_body('50'); cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Confirm transaction in wallet', epochTimeout).should( - 'be.visible' - ); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should( - 'be.visible' - ); - cy.get(dialogCloseButton).click(); + // 1005-PROP-012 + // 1005-PROP-016 + cy.wait_for_proposal_submitted(); } ); @@ -190,8 +197,7 @@ context( cy.navigate_to_page_if_not_already_loaded('governance'); cy.get(vegaWalletUnstakedBalance, txTimeout).should( 'contain', - this.minProposerBalance, - txTimeout + this.minProposerBalance ); cy.navigate_to('staking'); cy.wait_for_spinner(); @@ -200,63 +206,19 @@ context( cy.get(vegaWalletStakedBalances, txTimeout).should( 'contain', - this.minProposerBalance, - txTimeout - ); - - cy.navigate_to('governance'); - cy.wait_for_spinner(); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - }); - - it('Newly created freeform proposals list - able to filter by proposalID to show it in list', function () { - cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance ); - cy.navigate_to_page_if_not_already_loaded('governance'); + + cy.navigate_to('governance'); + cy.wait_for_spinner(); cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); cy.enter_unique_freeform_proposal_body('50'); cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); - cy.wait('@proposalSubmissionCompletion') - .its(proposalResponseProposalIdPath) - .then((proposalId) => { - cy.get('[data-testid="set-proposals-filter-visible"]').click(); - cy.get('[data-testid="filter-input"]').type(proposalId); - cy.get(`#${proposalId}`).should('contain', proposalId); - }); + cy.wait_for_proposal_submitted(); }); - it('Newly created freeform proposals list - able to filter by proposerID to show it in list', function () { - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); + it('Newly created proposals list - able to filter by proposerID to show it in list', function () { + createFreeformProposal(this.minProposerBalance); cy.wait('@proposalSubmissionCompletion').then((proposal) => { let proposerId = proposal.request.body.variables.partyId; let proposalId = proposal.response.body.data.busEvents[0].event.id; @@ -266,36 +228,22 @@ context( }); }); - it('Newly created freeform proposals list - shows title and portion of summary', function () { - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50').as('freeformProposal'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); + it('Newly created proposals list - shows title and portion of summary', function () { + createRawProposal(this.minProposerBalance); cy.wait('@proposalSubmissionCompletion') .its(proposalResponseProposalIdPath) .then((proposalId) => { cy.get(openProposals).within(() => { - cy.get('@freeformProposal').then((freeformProposal) => { + cy.get('@rawProposal').then((rawProposal) => { // 1004-VOTE-008 // 1004-VOTE-034 cy.get(`#${proposalId}`) - .should('contain', freeformProposal.rationale.title) + .should('contain', rawProposal.rationale.title) .and('be.visible'); cy.get(`#${proposalId}`) .should( 'contain', - freeformProposal.rationale.description.substring(0, 59) + rawProposal.rationale.description.substring(0, 59) ) .and('be.visible'); }); @@ -303,70 +251,63 @@ context( }); }); - it('Newly created freeform proposals list - shows open proposals in an open state', function () { + it('Newly created proposals list - shows open proposals in an open state', function () { // 1004-VOTE-004 // 1004-VOTE-035 - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); + createRawProposal(this.minProposerBalance); cy.wait('@proposalSubmissionCompletion') .its(proposalResponseProposalIdPath) .then((proposalId) => { cy.get(openProposals).within(() => { - // 1004-VOTE-035 - cy.get(`#${proposalId}`) - .should('contain', proposalId) - .and('contain', 'Open') - .and('be.visible'); + cy.get(`#${proposalId}`).within(() => { + cy.get(viewProposalButton).should('be.visible').click(); + }); }); + cy.get_proposal_information_from_table('ID') + .contains(proposalId) + .and('be.visible'); + cy.get_proposal_information_from_table('State') + .contains('STATE_OPEN') + .and('be.visible'); + cy.get_proposal_information_from_table('Type') + .contains('NewFreeform') + .and('be.visible'); }); }); - it('Newly created freeform proposals list - proposals closest to closing date appear higher in list', function () { + it('Newly created proposals list - proposals closest to closing date appear higher in list', function () { // 1004-VOTE-005 cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance - ).then(() => { - let proposalHours = [ - (Number(this.minCloseHours) + 1).toString(), - this.maxCloseHours, - (Number(this.minCloseHours) + 3).toString(), - (Number(this.minCloseHours) + 2).toString(), - ]; - for (var index = 0; index < proposalHours.length; index++) { - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body(proposalHours[index]); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should( - 'be.visible' - ); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - } - }); - // Ensuring that proposals are not posted in same order as sort order + ); + let proposalDays = [ + this.minCloseDays + 1, + this.maxCloseDays, + this.minCloseDays + 3, + this.minCloseDays + 2, + ]; + for (var index = 0; index < proposalDays.length; index++) { + cy.go_to_make_new_proposal(governanceProposalType.RAW); + cy.create_ten_digit_unix_timestamp_for_specified_days( + proposalDays[index] + ).then((closingDateTimestamp) => { + cy.enter_raw_proposal_body(closingDateTimestamp); + }); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.contains('Awaiting network confirmation', epochTimeout).should( + 'be.visible' + ); + cy.contains('Proposal submitted', proposalTimeout).should( + 'be.visible' + ); + cy.get(dialogCloseButton).click(); + cy.wait_for_proposal_sync(); + } let arrayOfProposals = []; cy.navigate_to('governance'); cy.wait_for_spinner(); - cy.get(proposalDetailsTitle) .each((proposalTitleElement) => { arrayOfProposals.push(proposalTitleElement.text()); @@ -380,22 +321,8 @@ context( }); // Skipping test due to bug: #1320 - it.skip('Newly created freeform proposals list - shows proposal parcipitation - both met and not', function () { - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); + it.skip('Newly created freeform proposals list - shows proposal participation - both met and not', function () { + createFreeformProposal(this.minProposerBalance); cy.get_submitted_proposal_from_proposal_list() .as('submittedProposal') .within(() => { @@ -430,20 +357,7 @@ context( // Skipping test due to bug - should be solved when #1223 released it.skip('Newly created freeform proposal details - shows proposal title and full description', function () { - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50').as('freeformProposal'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); + createRawProposal(this.minProposerBalance); cy.wait('@proposalSubmissionCompletion') .its(proposalResponseProposalIdPath) .then((proposalId) => { @@ -452,7 +366,7 @@ context( cy.get(viewProposalButton).should('be.visible').click(); }); }); - cy.get('@freeformProposal').then((freeformProposal) => { + cy.get('@rawProposal').then((freeformProposal) => { // 1004-VOTE-054 cy.get(proposalDetailsTitle) .should('contain', freeformProposal.rationale.title) @@ -464,23 +378,10 @@ context( }); }); + // 1005-todo-PROP-019 // Skipping test due to bug - should be solved when #1223 released - it.skip('Newly created freeform proposal details - shows full link included in description', function () { - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50').as('freeformProposal'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); + it.skip('Newly created raw proposal details - shows full link included in description', function () { + createRawProposal(this.minProposerBalance); cy.wait('@proposalSubmissionCompletion') .its(proposalResponseProposalIdPath) .then((proposalId) => { @@ -489,7 +390,7 @@ context( cy.get(viewProposalButton).should('be.visible').click(); }); }); - cy.get('@freeformProposal').then(() => { + cy.get('@rawProposal').then(() => { // 1004-VOTE-055 cy.get(proposalDetailsDescription) .should('have.attr', 'href') @@ -502,61 +403,18 @@ context( }); }); - it('Newly created freeform proposal details - shows open proposal in an open state', function () { - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); - cy.wait('@proposalSubmissionCompletion') - .its(proposalResponseProposalIdPath) - .then((proposalId) => { - cy.get(openProposals).within(() => { - cy.get(`#${proposalId}`).within(() => { - cy.get(viewProposalButton).should('be.visible').click(); - }); - }); - cy.get_proposal_information_from_table('ID') - .contains(proposalId) - .and('be.visible'); - cy.get_proposal_information_from_table('State') - .contains('STATE_OPEN') - .and('be.visible'); - cy.get_proposal_information_from_table('Type') - .contains('NewFreeform') - .and('be.visible'); - }); - }); - it('Newly created freeform proposal details - shows proposed and closing dates', function () { const closingVoteHrs = '72'; cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance ); - cy.navigate_to_page_if_not_already_loaded('governance'); cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); cy.create_ten_digit_unix_timestamp_for_specified_days('3').then( (closingDateTimestamp) => { cy.enter_unique_freeform_proposal_body(closingVoteHrs); cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should( - 'be.visible' - ); - cy.get(dialogCloseButton).click(); + cy.wait_for_proposal_submitted(); cy.wait_for_proposal_sync(); cy.navigate_to('governance'); cy.wait_for_spinner(); @@ -583,24 +441,10 @@ context( cy.contains('3 days left to vote').should('be.visible'); }); - it('Newly created freeform proposal details - shows default status set to fail', function () { + it('Newly created proposal details - shows default status set to fail', function () { // 1004-VOTE-037 // 1004-VOTE-040 - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); + createRawProposal(this.minProposerBalance); cy.get_submitted_proposal_from_proposal_list().within(() => cy.get(viewProposalButton).click() ); @@ -621,22 +465,8 @@ context( .should('be.visible'); }); - it('Newly created freeform proposal details - ability to vote for proposal - with minimum required tokens associated', function () { - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); + it('Newly created proposal details - ability to vote for and against proposal - with minimum required tokens associated', function () { + createRawProposal(this.minProposerBalance); cy.get_submitted_proposal_from_proposal_list() .as('submittedProposal') .within(() => cy.get(viewProposalButton).click()); @@ -686,191 +516,28 @@ context( cy.get_proposal_information_from_table('Number of voting parties') .should('have.text', '1') .and('be.visible'); - }); - - it('Newly created freeform proposal details - ability to vote against proposal - with minimum required tokens associated', function () { - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); - cy.get_submitted_proposal_from_proposal_list() - .as('submittedProposal') - .within(() => cy.get(viewProposalButton).click()); - cy.vote_for_proposal('against'); - cy.get_governance_proposal_date_format_for_specified_days( - '0', - 'shortMonth' - ).then((votedDate) => { - // 1004-VOTE-051 - cy.contains('You voted:') - .siblings() - .contains('Against') - .siblings() - .contains(votedDate) - .should('be.visible'); - }); - cy.get(proposalVoteProgressForPercentage) - .contains('0.00%') - .and('be.visible'); - cy.get(proposalVoteProgressAgainstPercentage) - .contains('100.00%') - .and('be.visible'); - cy.get(proposalVoteProgressForTokens) - .contains('0.00') - .and('be.visible'); - cy.get(proposalVoteProgressAgainstTokens) - .contains('1.00') - .and('be.visible'); - cy.get_proposal_information_from_table('Tokens for proposal') - .should('have.text', '0.00') - .and('be.visible'); - cy.get_proposal_information_from_table('Tokens against proposal') - .should('have.text', parseFloat(this.minProposerBalance).toFixed(2)) - .and('be.visible'); - cy.get_proposal_information_from_table('Participation required') - .contains(`${this.requiredParticipation}%`) - .should('be.visible'); - cy.get_proposal_information_from_table('Majority Required') - .contains(`${parseFloat(this.requiredMajority).toFixed(2)}%`) - .should('be.visible'); - cy.get_proposal_information_from_table('Number of voting parties') - .should('have.text', '1') - .and('be.visible'); - }); - - it('Newly created freeform proposal details - ability to change vote from against to for - with minimum required tokens associated', function () { - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); - cy.get_submitted_proposal_from_proposal_list() - .as('submittedProposal') - .within(() => cy.get(viewProposalButton).click()); - cy.vote_for_proposal('against'); - // 1004-VOTE-090 cy.get(changeVoteButton).should('be.visible').click(); - cy.wait_for_spinner(); cy.vote_for_proposal('for'); - cy.get(proposalVoteProgressForPercentage) - .contains('100.00%') - .and('be.visible'); - cy.get(proposalVoteProgressAgainstPercentage) - .contains('0.00%') - .and('be.visible'); - cy.get(proposalVoteProgressForTokens) - .contains('1.00') - .and('be.visible'); - cy.get(proposalVoteProgressAgainstTokens) - .contains('0.00') - .and('be.visible'); // 1004-VOTE-064 cy.get_proposal_information_from_table('Tokens for proposal') .should('have.text', parseFloat(this.minProposerBalance).toFixed(2)) .and('be.visible'); - cy.get_proposal_information_from_table('Tokens against proposal') - .should('have.text', '0.00') - .and('be.visible'); - cy.get_proposal_information_from_table('Participation required') - .contains(`${this.requiredParticipation}%`) - .should('be.visible'); - cy.get_proposal_information_from_table('Majority Required') - .contains(`${parseFloat(this.requiredMajority).toFixed(2)}%`) - .should('be.visible'); - cy.get_proposal_information_from_table('Number of voting parties') - .should('have.text', '1') - .and('be.visible'); - }); - - it('Newly created freeform proposal details - ability to change vote from for to against - with minimum required tokens associated', function () { - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); cy.wait_for_spinner(); - cy.get_submitted_proposal_from_proposal_list() - .as('submittedProposal') - .within(() => cy.get(viewProposalButton).click()); - cy.vote_for_proposal('for'); cy.get(changeVoteButton).should('be.visible').click(); - cy.wait_for_spinner(); cy.vote_for_proposal('against'); - cy.get(proposalVoteProgressForPercentage) - .contains('0.00%') - .and('be.visible'); cy.get(proposalVoteProgressAgainstPercentage) .contains('100.00%') .and('be.visible'); - cy.get(proposalVoteProgressForTokens) - .contains('0.00') - .and('be.visible'); - cy.get(proposalVoteProgressAgainstTokens) - .contains('1.00') - .and('be.visible'); - cy.get_proposal_information_from_table('Tokens for proposal') - .should('have.text', '0.00') - .and('be.visible'); cy.get_proposal_information_from_table('Tokens against proposal') .should('have.text', parseFloat(this.minProposerBalance).toFixed(2)) .and('be.visible'); - cy.get_proposal_information_from_table('Participation required') - .contains(`${this.requiredParticipation}%`) - .should('be.visible'); - cy.get_proposal_information_from_table('Majority Required') - .contains(`${parseFloat(this.requiredMajority).toFixed(2)}%`) - .should('be.visible'); cy.get_proposal_information_from_table('Number of voting parties') .should('have.text', '1') .and('be.visible'); }); - it('Newly created freeform proposal details - ability to increase associated tokens - so that vote sways result', function () { - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); - cy.wait_for_spinner(); + it('Newly created proposal details - ability to increase associated tokens - so that vote sways result', function () { + createRawProposal(this.minProposerBalance); cy.get_submitted_proposal_from_proposal_list() .as('submittedProposal') .within(() => cy.get(viewProposalButton).click()); @@ -935,7 +602,6 @@ context( cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance ); - cy.navigate_to_page_if_not_already_loaded('governance'); cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); cy.enter_unique_freeform_proposal_body('40'); cy.get(newProposalSubmitButton).should('be.visible').click(); @@ -948,7 +614,6 @@ context( cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance ); - cy.navigate_to_page_if_not_already_loaded('governance'); cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); cy.enter_unique_freeform_proposal_body('100000'); cy.get(newProposalSubmitButton).should('be.visible').click(); @@ -962,7 +627,6 @@ context( cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance ); - cy.navigate_to_page_if_not_already_loaded('governance'); cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); cy.enter_unique_freeform_proposal_body('500000000'); cy.get(newProposalSubmitButton).should('be.visible').click(); @@ -991,15 +655,14 @@ context( .and('be.visible'); }); - it('Unable to create a freeform proposal - when no tokens are associated', function () { + it('Unable to create a proposal - when no tokens are associated', function () { cy.vega_wallet_teardown(); cy.get(vegaWalletAssociatedBalance, txTimeout).contains( '0.000000000000000000', txTimeout ); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('49'); - cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.go_to_make_new_proposal(governanceProposalType.RAW); + createRawProposal(); cy.contains('Transaction failed', proposalTimeout).should('be.visible'); cy.get(feedbackError) @@ -1009,14 +672,12 @@ context( .should('be.visible'); }); - it('Unable to create a freeform proposal - when some but not enough tokens are associated', function () { + it('Unable to create a proposal - when some but not enough tokens are associated', function () { cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance - 0.000001 ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('49'); - cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.go_to_make_new_proposal(governanceProposalType.RAW); + createRawProposal(this.minProposerBalance); cy.contains('Transaction failed', proposalTimeout).should('be.visible'); cy.get(feedbackError) @@ -1032,13 +693,12 @@ context( cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance ); - cy.navigate_to_page_if_not_already_loaded('governance'); cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); cy.create_ten_digit_unix_timestamp_for_specified_days('1').then( (closingDateTimestamp) => { cy.fixture('/proposals/freeform.json').then((freeformProposal) => { freeformProposal.terms.closingTimestamp = closingDateTimestamp; - freeformProposal.unexpectfield = `i shouldn't be here`; + freeformProposal.unexpected = `i shouldn't be here`; let proposalPayload = JSON.stringify(freeformProposal); cy.get(proposalDetailsTitle).type( @@ -1056,7 +716,7 @@ context( cy.contains('Transaction failed', proposalTimeout).should('be.visible'); cy.get(feedbackError) - .contains('Unknown field unexpectfield in vega proposal terms') + .contains('Unknown field unexpected in vega proposal terms') .should('be.visible'); }); @@ -1066,18 +726,15 @@ context( cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); + cy.go_to_make_new_proposal(governanceProposalType.RAW); cy.create_ten_digit_unix_timestamp_for_specified_days('1').then( (closingDateTimestamp) => { - cy.fixture('/proposals/freeform.json').then((freeformProposal) => { - freeformProposal.terms.closingTimestamp = closingDateTimestamp; - freeformProposal.terms.unexpectedField = `i shouldn't be here`; - let proposalPayload = JSON.stringify(freeformProposal); + cy.fixture('/proposals/raw.json').then((rawProposal) => { + rawProposal.terms.closingTimestamp = closingDateTimestamp; + rawProposal.terms.unexpectedField = `i shouldn't be here`; + let proposalPayload = JSON.stringify(rawProposal); - cy.get(proposalDetailsTitle).type( - freeformProposal.rationale.title - ); + cy.get(proposalDetailsTitle).type(rawProposal.rationale.title); cy.get(proposalDetailsDescription).type(proposalPayload, { parseSpecialCharSequences: false, delay: 2, @@ -1090,24 +747,20 @@ context( cy.contains('Transaction failed', proposalTimeout).should('be.visible'); cy.get(feedbackError) - .contains('Unknown field unexpectfield in vega proposal terms') + .contains('Unknown field unexpected in vega proposal terms') .should('be.visible'); }); // Have to skip because #1326 bug doesn't handle below scenario + // 1005-todo-PROP-009 it.skip('Unable to vote on a freeform proposal - when some but not enough vega associated', function () { cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance ); - cy.navigate_to_page_if_not_already_loaded('governance'); cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); cy.enter_unique_freeform_proposal_body('50'); cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); + cy.wait_for_proposal_submitted(); cy.wait_for_proposal_sync(); cy.staking_page_disassociate_tokens('0.0001'); cy.get(vegaWallet).within(() => { @@ -1126,21 +779,8 @@ context( cy.get(voteButtons).contains('against').should('not.exist'); }); - it('Unable to vote on a freeform proposal - when vega wallet disconnected - option to connect from within', function () { - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.navigate_to_page_if_not_already_loaded('governance'); - cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); - cy.enter_unique_freeform_proposal_body('50'); - cy.get(newProposalSubmitButton).should('be.visible').click(); - cy.contains('Awaiting network confirmation', epochTimeout).should( - 'be.visible' - ); - cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); - cy.get(dialogCloseButton).click(); - cy.wait_for_proposal_sync(); - cy.navigate_to('governance'); + it('Unable to vote on a proposal - when vega wallet disconnected - option to connect from within', function () { + createRawProposal(this.minProposerBalance); cy.wait_for_spinner(); cy.get('[data-testid="manage-vega-wallet"]').click(); cy.get('[data-testid="disconnect"]').click(); @@ -1171,6 +811,33 @@ context( cy.contains('You voted: Against').should('be.visible'); }); + function createRawProposal(proposerBalance) { + if (proposerBalance) + cy.ensure_specified_unstaked_tokens_are_associated(proposerBalance); + cy.go_to_make_new_proposal('raw proposal'); + cy.create_ten_digit_unix_timestamp_for_specified_days('8').then( + (closingDateTimestamp) => { + cy.enter_raw_proposal_body(closingDateTimestamp).as('rawProposal'); + } + ); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.wait_for_proposal_submitted(); + cy.wait_for_proposal_sync(); + cy.navigate_to('governance'); + cy.wait_for_spinner(); + } + + function createFreeformProposal(proposerBalance) { + cy.ensure_specified_unstaked_tokens_are_associated(proposerBalance); + cy.go_to_make_new_proposal(governanceProposalType.FREEFORM); + cy.enter_unique_freeform_proposal_body('50'); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.wait_for_proposal_submitted(); + cy.wait_for_proposal_sync(); + cy.navigate_to('governance'); + cy.wait_for_spinner(); + } + after( 'teardown environment to prevent test data bleeding into other tests', function () { diff --git a/apps/token-e2e/src/integration/flow/governance-forms-flow.cy.js b/apps/token-e2e/src/integration/flow/governance-forms-flow.cy.js new file mode 100644 index 000000000..f4fe10405 --- /dev/null +++ b/apps/token-e2e/src/integration/flow/governance-forms-flow.cy.js @@ -0,0 +1,177 @@ +const newProposalSubmitButton = '[data-testid="proposal-submit"]'; +const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]'; +const proposalValidationDeadline = + '[data-testid="proposal-validation-deadline"]'; +const proposalParameterSelect = '[data-testid="proposal-parameter-select"]'; +const proposalMarketSelect = '[data-testid="proposal-market-select"]'; +const newProposalTitle = '[data-testid="proposal-title"]'; +const newProposalDescription = '[data-testid="proposal-description"]'; +const newProposalTerms = '[data-testid="proposal-terms"]'; +const currentParameterValue = + '[data-testid="selected-proposal-param-current-value"]'; +const newProposedParameterValue = + '[data-testid="selected-proposal-param-new-value"]'; +const dialogCloseButton = '[data-testid="dialog-close"]'; +const inputError = '[data-testid="input-error-text"]'; +const epochTimeout = Cypress.env('epochTimeout'); +const proposalTimeout = { timeout: 14000 }; + +const governanceProposalType = { + NETWORK_PARAMETER: 'Network parameter', + NEW_MARKET: 'New market', + UPDATE_MARKET: 'Update market', + NEW_ASSET: 'New asset', + FREEFORM: 'Freeform', + RAW: 'raw proposal', +}; + +context( + 'Governance flow - form validations for different governance proposals', + { tags: '@slow' }, + function () { + before('connect wallets and set approval limit', function () { + cy.vega_wallet_import(); + cy.visit('/'); + cy.verify_page_header('The $VEGA token'); + cy.vega_wallet_connect(); + cy.vega_wallet_set_specified_approval_amount('1000'); + cy.reload(); + cy.wait_for_spinner(); + cy.verify_page_header('The $VEGA token'); + cy.ethereum_wallet_connect(); + }); + + beforeEach('visit governance tab', function () { + cy.navigate_to('governance'); + cy.wait_for_spinner(); + cy.intercept('POST', '/query', (req) => { + if (req.body.operationName === 'ProposalEvent') { + req.alias = 'proposalSubmissionCompletion'; + } + }); + cy.ensure_specified_unstaked_tokens_are_associated('1'); + }); + + it('Able to submit valid update network parameter proposal', function () { + cy.navigate_to_page_if_not_already_loaded('governance'); + cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER); + // 1005-PROP-006 + cy.get(newProposalTitle).type('Test update network parameter proposal'); + // 1005-PROP-007 + cy.get(newProposalDescription).type('E2E test for proposals'); + + cy.get(proposalParameterSelect).find('option').should('have.length', 109); + cy.get(proposalParameterSelect).select( + 'governance_proposal_asset_minEnact' + ); + cy.get(currentParameterValue).should('have.value', '2s'); + cy.get(newProposedParameterValue).type('5s'); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.wait_for_proposal_submitted(); + }); + + it('Unable to submit network parameter with missing/invalid fields', function () { + cy.navigate_to_page_if_not_already_loaded('governance'); + cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.get(inputError).should('have.length', 3); + cy.get(newProposalTitle).type( + 'Invalid update network parameter proposal' + ); + cy.get(newProposalDescription).type('E2E invalid test for proposals'); + cy.get(proposalParameterSelect).select( + 'spam_protection_proposal_min_tokens' + ); + cy.get(newProposedParameterValue).type('0'); + cy.get(proposalVoteDeadline).clear().type('0'); + cy.get(newProposalSubmitButton).click(); + cy.contains('Awaiting network confirmation', epochTimeout).should( + 'not.exist' + ); + cy.get(proposalVoteDeadline).clear().type('9000'); + cy.get(newProposalSubmitButton).click(); + cy.contains('Awaiting network confirmation', epochTimeout).should( + 'not.exist' + ); + }); + + it('Able to submit valid new market proposal', function () { + cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET); + cy.get(newProposalTitle).type('Test new market proposal'); + cy.get(newProposalDescription).type('E2E test for proposals'); + cy.fixture('/proposals/new-market').then((newMarketProposal) => { + let newMarketPayload = JSON.stringify(newMarketProposal); + cy.get(newProposalTerms).type(newMarketPayload, { + parseSpecialCharSequences: false, + delay: 2, + }); + }); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.wait_for_proposal_submitted(); + }); + + it('Unable to submit new market proposal with missing/invalid fields', function () { + cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.get(inputError).should('have.length', 3); + }); + + // skipped because of bug #1605 + it.skip('Able to submit update market proposal', function () { + const marketId = + '315a8e48db0a292c92b617264728048c82c20efc922c75fd292fc54e5c727c81'; + cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET); + cy.get(newProposalTitle).type('Test update asset proposal'); + cy.get(newProposalDescription).type('E2E test for proposals'); + cy.get(proposalMarketSelect).select(marketId); + cy.get('[data-testid="update-market-details"]').within(() => { + cy.get('dd').eq(0).should('have.text', 'Oranges Daily'); + cy.get('dd').eq(1).should('have.text', 'ORANGES.24h'); + cy.get('dd').eq(2).should('have.text', marketId); + }); + cy.fixture('/proposals/update-market').then((updateMarketProposal) => { + let newUpdateMarketProposal = JSON.stringify(updateMarketProposal); + cy.get(newProposalTerms).type(newUpdateMarketProposal, { + parseSpecialCharSequences: false, + delay: 2, + }); + }); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.wait_for_proposal_submitted(); + }); + + it('Able to submit new asset proposal', function () { + cy.go_to_make_new_proposal(governanceProposalType.NEW_ASSET); + cy.get(newProposalTitle).type('Test new asset proposal'); + cy.get(newProposalDescription).type('E2E test for proposals'); + cy.fixture('/proposals/new-asset').then((newAssetProposal) => { + let newAssetPayload = JSON.stringify(newAssetProposal); + cy.get(newProposalTerms).type(newAssetPayload, { + parseSpecialCharSequences: false, + delay: 2, + }); + }); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.contains('Awaiting network confirmation', epochTimeout).should( + 'be.visible' + ); + cy.contains('Proposal waiting for node vote', proposalTimeout).should( + 'be.visible' + ); + cy.get(dialogCloseButton).click(); + }); + + it('Unable to submit new asset proposal with missing/invalid fields', function () { + cy.go_to_make_new_proposal(governanceProposalType.NEW_ASSET); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.get(inputError).should('have.length', 3); + cy.get(newProposalTitle).type('Invalid new asset proposal'); + cy.get(newProposalDescription).type('Invalid E2E test for proposals'); + cy.get(proposalValidationDeadline).clear().type('2'); + cy.get(newProposalSubmitButton).click(); + cy.contains('Awaiting network confirmation', epochTimeout).should( + 'not.exist' + ); + }); + } +); diff --git a/apps/token-e2e/src/integration/flow/token-association-flow.cy.js b/apps/token-e2e/src/integration/flow/token-association-flow.cy.js index c4ea61709..ee9e8aa22 100644 --- a/apps/token-e2e/src/integration/flow/token-association-flow.cy.js +++ b/apps/token-e2e/src/integration/flow/token-association-flow.cy.js @@ -14,9 +14,11 @@ const tokenSubmitButton = '[data-testid="token-input-submit-button"]'; const ethWalletDissociateButton = '[href="/staking/disassociate"]'; const vestingContractSection = '[data-testid="vega-in-vesting-contract"]'; const vegaInWalletSection = '[data-testid="vega-in-wallet"]'; +const connectedVegaKey = '[data-testid="connected-vega-key"]'; const associatedKey = '[data-test-id="associated-key"]'; const associatedAmount = '[data-test-id="associated-amount"]'; -const disassocitiationWarning = '[data-testid="disassociation-warning"]'; +const associateCompleteText = '[data-testid="transaction-complete-body"]'; +const disassociationWarning = '[data-testid="disassociation-warning"]'; const vegaWallet = '[data-testid="vega-wallet"]'; context( @@ -47,7 +49,8 @@ context( ); it('Able to associate tokens - from wallet', function () { - //1004-ASSO-008 + //1004-ASSO-003 + //1004-ASSO-005 //1004-ASSO-009 //1004-ASSO-030 //1004-ASSO-012 @@ -162,7 +165,7 @@ context( cy.get('button').contains('Select a validator to nominate').click(); cy.get(ethWalletDissociateButton).click(); - cy.get(disassocitiationWarning).should('contain', warningText); + cy.get(disassociationWarning).should('contain', warningText); cy.staking_page_disassociate_all_tokens(); @@ -185,6 +188,8 @@ context( it('Able to associate and disassociate vesting contract tokens', function () { // 1004-ASSO-006 + // 1004-ASSO-007 + // 1004-ASSO-018 // 1004-ASSO-024 // 1004-ASSO-023 @@ -268,15 +273,44 @@ context( }); it('Not able to associate more tokens than owned', function () { + // 1004-ASSO-008 // 1004-ASSO-010 // No warning visible as described in AC, but the button is disabled cy.get(ethWalletAssociateButton).first().click(); cy.get(associateWalletRadioButton, { timeout: 30000 }).click(); + cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input cy.get(tokenAmountInputBox, { timeout: 10000 }).type(6500000); cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); }); + // 1004-ASSO-004 + it('Able to associate tokens to different public key of connected vega wallet', function () { + cy.get(ethWalletAssociateButton).first().click(); + cy.get(associateWalletRadioButton).click(); + cy.get(connectedVegaKey).should( + 'have.text', + Cypress.env('vegaWalletPublicKey') + ); + + cy.get('[data-testid="manage-vega-wallet"]').click(); + cy.get('[data-testid="select-keypair-button"]').click(); + cy.get(connectedVegaKey).should( + 'have.text', + Cypress.env('vegaWalletPublicKey2') + ); + cy.staking_page_associate_tokens('2'); + cy.get(vegaWallet).within(() => { + cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0); + }); + cy.get(associateCompleteText).should( + 'have.text', + `Vega key ${Cypress.env( + 'vegaWalletPublicKey2Short' + )} can now participate in governance and nominate a validator with your associated $VEGA.` + ); + }); + after( 'teardown environment to prevent test data bleeding into other tests', function () { diff --git a/apps/token-e2e/src/integration/view/governance.cy.js b/apps/token-e2e/src/integration/view/governance.cy.js index a52e4ec42..b950b3b3b 100644 --- a/apps/token-e2e/src/integration/view/governance.cy.js +++ b/apps/token-e2e/src/integration/view/governance.cy.js @@ -29,6 +29,7 @@ context( .and('have.attr', 'href') .and('equal', governanceDocsUrl); + // 1005-PROP-001 cy.request(governanceDocsUrl) .its('body') .then((body) => { diff --git a/apps/token-e2e/src/support/governance.functions.js b/apps/token-e2e/src/support/governance.functions.js index 9eb5887bc..67f92758a 100644 --- a/apps/token-e2e/src/support/governance.functions.js +++ b/apps/token-e2e/src/support/governance.functions.js @@ -2,11 +2,15 @@ const newProposalButton = '[data-testid="new-proposal-link"]'; const proposalInformationTableRows = '[data-testid="key-value-table-row"]'; const newProposalTitle = '[data-testid="proposal-title"]'; const newProposalDescription = '[data-testid="proposal-description"]'; +const rawProposalData = '[data-testid="proposal-data"]'; const proposalResponseProposalIdPath = 'response.body.data.busEvents.0.event.id'; const voteButtons = '[data-testid="vote-buttons"]'; const txTimeout = Cypress.env('txTimeout'); const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]'; +const dialogCloseButton = '[data-testid="dialog-close"]'; +const epochTimeout = Cypress.env('epochTimeout'); +const proposalTimeout = { timeout: 14000 }; Cypress.Commands.add( 'convert_unix_timestamp_to_governance_data_table_date_format', @@ -47,44 +51,26 @@ Cypress.Commands.add( } ); -Cypress.Commands.add('enter_unique_freeform_proposal_body', (timestamp) => { - cy.fixture('/proposals/freeform.json').then((freeformProposal) => { - freeformProposal.terms.closingTimestamp = timestamp; - freeformProposal.rationale.title += timestamp; - let proposalPayload = JSON.stringify(freeformProposal); +Cypress.Commands.add('enter_raw_proposal_body', (timestamp) => { + cy.fixture('/proposals/raw.json').then((rawProposal) => { + rawProposal.terms.closingTimestamp = timestamp; + rawProposal.rationale.title += timestamp; + let proposalPayload = JSON.stringify(rawProposal); - cy.get(newProposalTitle).type(freeformProposal.rationale.title); - - cy.get(newProposalDescription).type(proposalPayload, { + cy.get(rawProposalData).type(proposalPayload, { parseSpecialCharSequences: false, delay: 2, }); - - cy.get(proposalVoteDeadline).clear().click().type(timestamp); - - cy.wrap(freeformProposal); + cy.wrap(rawProposal); }); }); -Cypress.Commands.add('get_network_parameters', () => { - let mutation = '{networkParameters {key value}}'; - cy.request({ - method: 'POST', - url: `http://localhost:3028/query`, - body: { - query: mutation, - }, - headers: { 'content-type': 'application/json' }, - }) - .its(`body.data.networkParameters`) - .then(function (response) { - let object = response.reduce(function (r, e) { - r[e.key] = e.value; - return r; - }, {}); - - return object; - }); +Cypress.Commands.add('enter_unique_freeform_proposal_body', (timestamp) => { + cy.get(newProposalTitle).type(`${timestamp} test freeform proposal`); + cy.get(newProposalDescription).type( + 'this is a e2e freeform proposal description' + ); + cy.get(proposalVoteDeadline).clear().click().type(timestamp); }); Cypress.Commands.add('get_submitted_proposal_from_proposal_list', () => { @@ -165,6 +151,15 @@ Cypress.Commands.add('get_sort_order_of_supplied_array', (suppliedArray) => { }); Cypress.Commands.add('go_to_make_new_proposal', (proposalType) => { + cy.navigate_to_page_if_not_already_loaded('governance'); cy.get(newProposalButton).should('be.visible').click(); cy.get('li').contains(proposalType).click(); }); + +Cypress.Commands.add('wait_for_proposal_submitted', () => { + cy.contains('Awaiting network confirmation', epochTimeout).should( + 'be.visible' + ); + cy.contains('Proposal submitted', proposalTimeout).should('be.visible'); + cy.get(dialogCloseButton).click(); +}); diff --git a/apps/token-e2e/src/support/staking.functions.js b/apps/token-e2e/src/support/staking.functions.js index 0c9afa870..f64abd2f8 100644 --- a/apps/token-e2e/src/support/staking.functions.js +++ b/apps/token-e2e/src/support/staking.functions.js @@ -20,7 +20,7 @@ const vegaKeySelector = '#vega-key-selector'; const txTimeout = Cypress.env('txTimeout'); const epochTimeout = Cypress.env('epochTimeout'); -Cypress.Commands.add('wait_for_begining_of_epoch', () => { +Cypress.Commands.add('wait_for_beginning_of_epoch', () => { cy.contains('Waiting for next epoch to start', epochTimeout).should( 'not.exist' ); @@ -34,7 +34,7 @@ Cypress.Commands.add('staking_validator_page_add_stake', (stake) => { cy.wait_for_spinner(); cy.get(addStakeRadioButton, epochTimeout).click({ force: true }); cy.get(tokenAmountInputBox).type(stake); - cy.wait_for_begining_of_epoch(); + cy.wait_for_beginning_of_epoch(); cy.get(tokenSubmitButton, epochTimeout) .should('be.enabled') .and('contain', `Add ${stake} $VEGA tokens`) @@ -47,7 +47,7 @@ Cypress.Commands.add('staking_validator_page_remove_stake', (stake) => { cy.wait_for_spinner(); cy.get(removeStakeRadioButton, epochTimeout).click(); cy.get(tokenAmountInputBox).type(stake); - cy.wait_for_begining_of_epoch(); + cy.wait_for_beginning_of_epoch(); cy.get(tokenSubmitButton) .should('be.enabled', epochTimeout) .and('contain', `Remove ${stake} $VEGA tokens at the end of epoch`) @@ -151,7 +151,7 @@ Cypress.Commands.add( cy.wait_for_spinner(); cy.contains('Loading...', epochTimeout).should('not.exist'); cy.contains('Total stake this epoch').should('be.visible'); - cy.wait_for_begining_of_epoch(); + cy.wait_for_beginning_of_epoch(); // below is to ensure validator list is shown cy.get(stakeValidatorListName, { timeout: 10000 }).should('exist'); cy.get(stakeValidatorListPendingStake, txTimeout).should( @@ -180,7 +180,7 @@ Cypress.Commands.add( cy.wait_for_spinner(); cy.contains('Loading...', epochTimeout).should('not.exist'); cy.contains('Total stake this epoch').should('be.visible'); - cy.wait_for_begining_of_epoch(); + cy.wait_for_beginning_of_epoch(); cy.get(`[row-id="${positionOnList}"]`).within(() => { cy.get(stakeValidatorListName).should('have.text', expectedValidatorName); cy.get(stakeValidatorListTotalStake, epochTimeout).should( diff --git a/apps/token/src/components/vega-wallet/hooks.ts b/apps/token/src/components/vega-wallet/hooks.ts index 3d62cd694..84f52a2bf 100644 --- a/apps/token/src/components/vega-wallet/hooks.ts +++ b/apps/token/src/components/vega-wallet/hooks.ts @@ -17,7 +17,7 @@ import type { } from './__generated__/Delegations'; import { useVegaWallet } from '@vegaprotocol/wallet'; import { useContracts } from '../../contexts/contracts/contracts-context'; -import { isAssetTypeERC20 } from '@vegaprotocol/react-helpers'; +import { isAssetTypeERC20 } from '@vegaprotocol/assets'; import { AccountType } from '@vegaprotocol/types'; const DELEGATIONS_QUERY = gql` diff --git a/apps/token/src/i18n/translations/dev.json b/apps/token/src/i18n/translations/dev.json index 5f96f96fa..077b19080 100644 --- a/apps/token/src/i18n/translations/dev.json +++ b/apps/token/src/i18n/translations/dev.json @@ -636,6 +636,7 @@ "NewMarketProposal": "New market proposal", "UpdateMarketProposal": "Update market proposal", "NewAssetProposal": "New asset proposal", + "UpdateAssetProposal": "Update asset proposal", "NewFreeformProposal": "New freeform proposal", "NewRawProposal": "New raw proposal", "MinProposalRequirements": "You must have at least {{value}} VEGA associated to make a proposal", @@ -647,6 +648,7 @@ "NewMarket": "New market", "UpdateMarket": "Update market", "NewAsset": "New asset", + "UpdateAsset": "Update asset", "Freeform": "Freeform", "RawProposal": "Let me choose (raw proposal)", "UseMin": "Use minimum", diff --git a/apps/token/src/routes/governance/components/proposals-list-item/proposals-list-item-details.spec.tsx b/apps/token/src/routes/governance/components/proposals-list-item/proposals-list-item-details.spec.tsx index c5e5545dd..1aed2d962 100644 --- a/apps/token/src/routes/governance/components/proposals-list-item/proposals-list-item-details.spec.tsx +++ b/apps/token/src/routes/governance/components/proposals-list-item/proposals-list-item-details.spec.tsx @@ -26,7 +26,7 @@ import { lastWeek, nextWeek, } from '../../test-helpers/mocks'; -import type { ProposalsConnection_proposalsConnection_edges_node as ProposalNode } from '@vegaprotocol/governance'; +import type { Proposals_proposalsConnection_edges_node as ProposalNode } from '../../proposals/__generated__/Proposals'; const renderComponent = ( proposal: ProposalNode, @@ -172,7 +172,7 @@ describe('Proposals list item details', () => { datetime: lastWeek.toString(), party: { __typename: 'Party', - id: mockPubkey, + id: mockPubkey.publicKey, stakingSummary: { __typename: 'StakingSummary', currentStakeAvailable: '1000', @@ -210,7 +210,7 @@ describe('Proposals list item details', () => { datetime: lastWeek.toString(), party: { __typename: 'Party', - id: mockPubkey, + id: mockPubkey.publicKey, stakingSummary: { __typename: 'StakingSummary', currentStakeAvailable: '1000', diff --git a/apps/token/src/routes/governance/propose/freeform/propose-freeform.spec.tsx b/apps/token/src/routes/governance/propose/freeform/propose-freeform.spec.tsx index de6b8ad57..4bf639d83 100644 --- a/apps/token/src/routes/governance/propose/freeform/propose-freeform.spec.tsx +++ b/apps/token/src/routes/governance/propose/freeform/propose-freeform.spec.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { ProposeFreeform } from './propose-freeform'; import { MockedProvider } from '@apollo/client/testing'; import { mockWalletContext } from '../../test-helpers/mocks'; @@ -81,16 +81,14 @@ describe('Propose Freeform', () => { it('should render the title', async () => { renderComponent(); - await waitFor(() => - expect(screen.getByText('New freeform proposal')).toBeInTheDocument() - ); + expect( + await screen.findByText('New freeform proposal') + ).toBeInTheDocument(); }); it('should render the form components', async () => { renderComponent(); - await waitFor(() => - expect(screen.getByTestId('freeform-proposal-form')).toBeTruthy() - ); + expect(await screen.findByTestId('freeform-proposal-form')).toBeTruthy(); expect(screen.getByTestId('min-proposal-requirements')).toBeTruthy(); expect(screen.getByTestId('proposal-docs-link')).toBeTruthy(); expect(screen.getByTestId('proposal-title')).toBeTruthy(); diff --git a/apps/token/src/routes/governance/propose/freeform/propose-freeform.tsx b/apps/token/src/routes/governance/propose/freeform/propose-freeform.tsx index 75b598b64..6f82bd335 100644 --- a/apps/token/src/routes/governance/propose/freeform/propose-freeform.tsx +++ b/apps/token/src/routes/governance/propose/freeform/propose-freeform.tsx @@ -27,7 +27,7 @@ export interface FreeformProposalFormFields { proposalReference: string; } -const docsLink = 'freeform-proposal'; +const DOCS_LINK = 'freeform-proposal'; export const ProposeFreeform = () => { const { params, loading, error } = useNetworkParams([ @@ -76,9 +76,9 @@ export const ProposeFreeform = () => {

{t('ProposalTermsText')} {`${VEGA_DOCS_URL}/tutorials/proposals/${docsLink}`} + >{`${VEGA_DOCS_URL}/tutorials/proposals/${DOCS_LINK}`}

)} diff --git a/apps/token/src/routes/governance/propose/network-parameter/propose-network-parameter.spec.tsx b/apps/token/src/routes/governance/propose/network-parameter/propose-network-parameter.spec.tsx index d6f9fe915..146466482 100644 --- a/apps/token/src/routes/governance/propose/network-parameter/propose-network-parameter.spec.tsx +++ b/apps/token/src/routes/governance/propose/network-parameter/propose-network-parameter.spec.tsx @@ -1,4 +1,4 @@ -import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import { ProposeNetworkParameter } from './propose-network-parameter'; import { MockedProvider } from '@apollo/client/testing'; import { mockWalletContext } from '../../test-helpers/mocks'; @@ -81,16 +81,16 @@ describe('Propose Network Parameter', () => { it('should render the correct title', async () => { renderComponent(); - await waitFor(() => - expect(screen.getByText('Update network parameter proposal')).toBeTruthy() - ); + expect( + await screen.findByText('Update network parameter proposal') + ).toBeTruthy(); }); it('should render the form components', async () => { renderComponent(); - await waitFor(() => - expect(screen.getByTestId('network-parameter-proposal-form')).toBeTruthy() - ); + expect( + await screen.findByTestId('network-parameter-proposal-form') + ).toBeTruthy(); expect(screen.getByTestId('min-proposal-requirements')).toBeTruthy(); expect(screen.getByTestId('proposal-docs-link')).toBeTruthy(); expect(screen.getByTestId('proposal-title')).toBeTruthy(); @@ -103,15 +103,15 @@ describe('Propose Network Parameter', () => { it('should render the network param select element with no initial value', async () => { renderComponent(); - await waitFor(() => - expect(screen.getByTestId('proposal-parameter-select')).toHaveValue('') + expect(await screen.findByTestId('proposal-parameter-select')).toHaveValue( + '' ); }); it('should render the current param value and a new value input when the network param select element is changed', async () => { renderComponent(); - await waitFor(() => - expect(screen.getByTestId('proposal-parameter-select')).toHaveValue('') + expect(await screen.findByTestId('proposal-parameter-select')).toHaveValue( + '' ); fireEvent.change(screen.getByTestId('proposal-parameter-select'), { diff --git a/apps/token/src/routes/governance/propose/network-parameter/propose-network-parameter.tsx b/apps/token/src/routes/governance/propose/network-parameter/propose-network-parameter.tsx index d07090e89..73fd0caec 100644 --- a/apps/token/src/routes/governance/propose/network-parameter/propose-network-parameter.tsx +++ b/apps/token/src/routes/governance/propose/network-parameter/propose-network-parameter.tsx @@ -69,7 +69,7 @@ export interface NetworkParameterProposalFormFields { proposalReference: string; } -const docsLink = '/network-parameter-proposal'; +const DOCS_LINK = '/network-parameter-proposal'; export const ProposeNetworkParameter = () => { const [selectedNetworkParam, setSelectedNetworkParam] = useState< @@ -141,9 +141,9 @@ export const ProposeNetworkParameter = () => {

{t('ProposalTermsText')} {`${VEGA_DOCS_URL}/tutorials/proposals${docsLink}`} + >{`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}

)} diff --git a/apps/token/src/routes/governance/propose/new-asset/propose-new-asset.spec.tsx b/apps/token/src/routes/governance/propose/new-asset/propose-new-asset.spec.tsx index 1ccd0f05e..e5d747ded 100644 --- a/apps/token/src/routes/governance/propose/new-asset/propose-new-asset.spec.tsx +++ b/apps/token/src/routes/governance/propose/new-asset/propose-new-asset.spec.tsx @@ -1,6 +1,6 @@ import { MockedProvider } from '@apollo/client/testing'; import { MemoryRouter as Router } from 'react-router-dom'; -import { render, screen, waitFor } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { VegaWalletContext } from '@vegaprotocol/wallet'; import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider'; import { mockWalletContext } from '../../test-helpers/mocks'; @@ -81,16 +81,12 @@ describe('Propose New Asset', () => { it('should render the title', async () => { renderComponent(); - await waitFor(() => - expect(screen.getByText('New asset proposal')).toBeTruthy() - ); + expect(await screen.findByText('New asset proposal')).toBeTruthy(); }); it('should render the form components', async () => { renderComponent(); - await waitFor(() => - expect(screen.getByTestId('new-asset-proposal-form')).toBeTruthy() - ); + expect(await screen.findByTestId('new-asset-proposal-form')).toBeTruthy(); expect(screen.getByTestId('min-proposal-requirements')).toBeTruthy(); expect(screen.getByTestId('proposal-docs-link')).toBeTruthy(); expect(screen.getByTestId('proposal-title')).toBeTruthy(); diff --git a/apps/token/src/routes/governance/propose/new-asset/propose-new-asset.tsx b/apps/token/src/routes/governance/propose/new-asset/propose-new-asset.tsx index 07ddf9461..6e63d3ace 100644 --- a/apps/token/src/routes/governance/propose/new-asset/propose-new-asset.tsx +++ b/apps/token/src/routes/governance/propose/new-asset/propose-new-asset.tsx @@ -7,6 +7,7 @@ import { getValidationTimestamp, } from '@vegaprotocol/governance'; import { useEnvironment } from '@vegaprotocol/environment'; +import { validateJson } from '@vegaprotocol/react-helpers'; import { ProposalFormMinRequirements, ProposalFormTitle, @@ -32,7 +33,7 @@ export interface NewAssetProposalFormFields { proposalReference: string; } -const docsLink = '/new-asset-proposal'; +const DOCS_LINK = '/new-asset-proposal'; export const ProposeNewAsset = () => { const { @@ -100,9 +101,9 @@ export const ProposeNewAsset = () => {

{t('ProposalTermsText')} {`${VEGA_DOCS_URL}/tutorials/proposals${docsLink}`} + >{`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}

)} @@ -141,20 +142,11 @@ export const ProposeNewAsset = () => { { - try { - JSON.parse(value); - return true; - } catch (e) { - return t('Must be valid JSON'); - } - }, - }, + validate: (value) => validateJson(value), })} labelOverride={'Terms.newAsset (JSON format)'} errorMessage={errors?.proposalTerms?.message} - customDocLink={docsLink} + customDocLink={DOCS_LINK} /> { it('should render the form components', async () => { renderComponent(); - await waitFor(() => - expect(screen.getByTestId('new-market-proposal-form')).toBeTruthy() - ); + expect(await screen.findByTestId('new-market-proposal-form')).toBeTruthy(); expect(screen.getByTestId('min-proposal-requirements')).toBeTruthy(); expect(screen.getByTestId('proposal-docs-link')).toBeTruthy(); expect(screen.getByTestId('proposal-title')).toBeTruthy(); diff --git a/apps/token/src/routes/governance/propose/new-market/propose-new-market.tsx b/apps/token/src/routes/governance/propose/new-market/propose-new-market.tsx index 89c0f419c..4aa0bf0fa 100644 --- a/apps/token/src/routes/governance/propose/new-market/propose-new-market.tsx +++ b/apps/token/src/routes/governance/propose/new-market/propose-new-market.tsx @@ -6,6 +6,7 @@ import { getEnactmentTimestamp, } from '@vegaprotocol/governance'; import { useEnvironment } from '@vegaprotocol/environment'; +import { validateJson } from '@vegaprotocol/react-helpers'; import { ProposalFormMinRequirements, ProposalFormTitle, @@ -30,7 +31,7 @@ export interface NewMarketProposalFormFields { proposalReference: string; } -const docsLink = '/new-market-proposal'; +const DOCS_LINK = '/new-market-proposal'; export const ProposeNewMarket = () => { const { @@ -95,9 +96,9 @@ export const ProposeNewMarket = () => {

{t('ProposalTermsText')} {`${VEGA_DOCS_URL}/tutorials/proposals/${docsLink}`} + >{`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}

)} @@ -136,20 +137,11 @@ export const ProposeNewMarket = () => { { - try { - JSON.parse(value); - return true; - } catch (e) { - return t('Must be valid JSON'); - } - }, - }, + validate: (value) => validateJson(value), })} labelOverride={'Terms.newMarket (JSON format)'} errorMessage={errors?.proposalTerms?.message} - customDocLink={docsLink} + customDocLink={DOCS_LINK} /> { expect(screen.getByText('New market')).toBeTruthy(); expect(screen.getByText('Update market')).toBeTruthy(); expect(screen.getByText('New asset')).toBeTruthy(); + expect(screen.getByText('Update asset')).toBeTruthy(); expect(screen.getByText('Freeform')).toBeTruthy(); expect(screen.getByText('Let me choose (raw proposal)')).toBeTruthy(); }); diff --git a/apps/token/src/routes/governance/propose/propose.tsx b/apps/token/src/routes/governance/propose/propose.tsx index 7b0ba9070..47a1d5372 100644 --- a/apps/token/src/routes/governance/propose/propose.tsx +++ b/apps/token/src/routes/governance/propose/propose.tsx @@ -79,6 +79,16 @@ export const Propose = () => {

+
  • +

    + + {t('UpdateAsset')} + +

    +
  • { data-testid="proposal-data" {...register('rawProposalData', { required: t('Required'), - validate: { - validateJson: (value) => { - try { - JSON.parse(value); - return true; - } catch (e) { - return t('Must be valid JSON'); - } - }, - }, + validate: (value) => validateJson(value), })} /> {errors.rawProposalData?.message && ( diff --git a/apps/token/src/routes/governance/propose/update-asset/index.tsx b/apps/token/src/routes/governance/propose/update-asset/index.tsx new file mode 100644 index 000000000..06b069cbd --- /dev/null +++ b/apps/token/src/routes/governance/propose/update-asset/index.tsx @@ -0,0 +1,4 @@ +export { + ProposeUpdateAsset, + ProposeUpdateAsset as default, +} from './propose-update-asset'; diff --git a/apps/token/src/routes/governance/propose/update-asset/propose-update-asset.spec.tsx b/apps/token/src/routes/governance/propose/update-asset/propose-update-asset.spec.tsx new file mode 100644 index 000000000..fd5e453e0 --- /dev/null +++ b/apps/token/src/routes/governance/propose/update-asset/propose-update-asset.spec.tsx @@ -0,0 +1,102 @@ +import { MockedProvider } from '@apollo/client/testing'; +import { MemoryRouter as Router } from 'react-router-dom'; +import { render, screen } from '@testing-library/react'; +import { VegaWalletContext } from '@vegaprotocol/wallet'; +import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider'; +import { mockWalletContext } from '../../test-helpers/mocks'; +import { ProposeUpdateAsset } from './propose-update-asset'; +import type { NetworkParamsQuery } from '@vegaprotocol/web3'; +import type { MockedResponse } from '@apollo/client/testing'; +import { NETWORK_PARAMETERS_QUERY } from '@vegaprotocol/react-helpers'; + +jest.mock('@vegaprotocol/environment', () => ({ + useEnvironment: () => ({ + VEGA_DOCS_URL: 'https://docs.vega.xyz', + }), +})); + +const updateAssetNetworkParamsQueryMock: MockedResponse = { + request: { + query: NETWORK_PARAMETERS_QUERY, + }, + result: { + data: { + networkParameters: [ + { + __typename: 'NetworkParameter', + key: 'governance.proposal.updateAsset.maxClose', + value: '8760h0m0s', + }, + { + __typename: 'NetworkParameter', + key: 'governance.proposal.updateAsset.maxEnact', + value: '8760h0m0s', + }, + { + __typename: 'NetworkParameter', + key: 'governance.proposal.updateAsset.minClose', + value: '1h0m0s', + }, + { + __typename: 'NetworkParameter', + key: 'governance.proposal.updateAsset.minEnact', + value: '2h0m0s', + }, + { + __typename: 'NetworkParameter', + key: 'governance.proposal.updateAsset.minProposerBalance', + value: '1', + }, + { + __typename: 'NetworkParameter', + key: 'spam.protection.proposal.min.tokens', + value: '1000000000000000000', + }, + ], + }, + }, +}; + +const renderComponent = () => + render( + + + + + + + + + + ); + +// Note: form submission is tested in propose-raw.spec.tsx. Reusable form +// components are tested in their own directory. + +describe('Propose Update Asset', () => { + it('should render successfully', async () => { + const { baseElement } = renderComponent(); + await expect(baseElement).toBeTruthy(); + }); + + it('should render the title', async () => { + renderComponent(); + expect(await screen.findByText('Update asset proposal')).toBeTruthy(); + }); + + it('should render the form components', async () => { + renderComponent(); + expect( + await screen.findByTestId('update-asset-proposal-form') + ).toBeTruthy(); + expect(screen.getByTestId('min-proposal-requirements')).toBeTruthy(); + expect(screen.getByTestId('proposal-docs-link')).toBeTruthy(); + expect(screen.getByTestId('proposal-title')).toBeTruthy(); + expect(screen.getByTestId('proposal-description')).toBeTruthy(); + expect(screen.getByTestId('proposal-terms')).toBeTruthy(); + expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy(); + expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy(); + expect(screen.getByTestId('proposal-submit')).toBeTruthy(); + expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy(); + }); +}); diff --git a/apps/token/src/routes/governance/propose/update-asset/propose-update-asset.tsx b/apps/token/src/routes/governance/propose/update-asset/propose-update-asset.tsx new file mode 100644 index 000000000..ad9009f43 --- /dev/null +++ b/apps/token/src/routes/governance/propose/update-asset/propose-update-asset.tsx @@ -0,0 +1,182 @@ +import { useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { + useProposalSubmit, + getClosingTimestamp, + getEnactmentTimestamp, +} from '@vegaprotocol/governance'; +import { useEnvironment } from '@vegaprotocol/environment'; +import { validateJson } from '@vegaprotocol/react-helpers'; +import { + ProposalFormMinRequirements, + ProposalFormTitle, + ProposalFormDescription, + ProposalFormTerms, + ProposalFormSubmit, + ProposalFormTransactionDialog, + ProposalFormSubheader, + ProposalFormVoteAndEnactmentDeadline, +} from '../../components/propose'; +import { AsyncRenderer, Link } from '@vegaprotocol/ui-toolkit'; +import { Heading } from '../../../../components/heading'; +import { VegaWalletContainer } from '../../../../components/vega-wallet-container'; +import { NetworkParams, useNetworkParams } from '@vegaprotocol/react-helpers'; + +export interface UpdateAssetProposalFormFields { + proposalVoteDeadline: string; + proposalEnactmentDeadline: string; + proposalTitle: string; + proposalDescription: string; + proposalTerms: string; + proposalReference: string; +} + +const DOCS_LINK = '/update-asset-proposal'; + +export const ProposeUpdateAsset = () => { + const { + params, + loading: networkParamsLoading, + error: networkParamsError, + } = useNetworkParams([ + NetworkParams.governance_proposal_updateAsset_minClose, + NetworkParams.governance_proposal_updateAsset_maxClose, + NetworkParams.governance_proposal_updateAsset_minEnact, + NetworkParams.governance_proposal_updateAsset_maxEnact, + NetworkParams.governance_proposal_updateAsset_minProposerBalance, + NetworkParams.spam_protection_proposal_min_tokens, + ]); + + const { VEGA_EXPLORER_URL, VEGA_DOCS_URL } = useEnvironment(); + const { t } = useTranslation(); + const { + register, + handleSubmit, + formState: { isSubmitting, errors }, + } = useForm(); + const { finalizedProposal, submit, Dialog } = useProposalSubmit(); + + const onSubmit = async (fields: UpdateAssetProposalFormFields) => { + await submit({ + rationale: { + title: fields.proposalTitle, + description: fields.proposalDescription, + }, + terms: { + updateAsset: { + ...JSON.parse(fields.proposalTerms), + }, + closingTimestamp: getClosingTimestamp(fields.proposalVoteDeadline), + enactmentTimestamp: getEnactmentTimestamp( + fields.proposalVoteDeadline, + fields.proposalEnactmentDeadline + ), + }, + }); + }; + + return ( + + + + {() => ( + <> + + + {VEGA_DOCS_URL && ( +

    + {t('ProposalTermsText')} + {`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`} +

    + )} + + {VEGA_EXPLORER_URL && ( +

    + {t('MoreAssetsInfo')}{' '} + {`${VEGA_EXPLORER_URL}/assets`} +

    + )} + +
    +
    + + {t('ProposalRationale')} + + + + + + + + {t('UpdateAsset')} + + + validateJson(value), + })} + labelOverride={'Terms.updateAsset (JSON format)'} + errorMessage={errors?.proposalTerms?.message} + customDocLink={DOCS_LINK} + /> + + + + + + +
    + + )} + + + ); +}; diff --git a/apps/token/src/routes/governance/propose/update-market/propose-update-market.spec.tsx b/apps/token/src/routes/governance/propose/update-market/propose-update-market.spec.tsx index cd5a2c5ef..ab88929a6 100644 --- a/apps/token/src/routes/governance/propose/update-market/propose-update-market.spec.tsx +++ b/apps/token/src/routes/governance/propose/update-market/propose-update-market.spec.tsx @@ -178,17 +178,17 @@ describe('Propose Update Market', () => { it('should render the select element with no initial value', async () => { renderComponent(); - await waitFor(() => - expect(screen.getByText('Update market proposal')).toBeInTheDocument() - ); + expect( + await screen.findByText('Update market proposal') + ).toBeInTheDocument(); expect(screen.getByTestId('proposal-market-select')).toHaveValue(''); }); it('should render the correct market details when the market select is used', async () => { renderComponent(); - await waitFor(() => - expect(screen.getByText('Update market proposal')).toBeInTheDocument() - ); + expect( + await screen.findByText('Update market proposal') + ).toBeInTheDocument(); fireEvent.change(screen.getByTestId('proposal-market-select'), { target: { value: diff --git a/apps/token/src/routes/governance/propose/update-market/propose-update-market.tsx b/apps/token/src/routes/governance/propose/update-market/propose-update-market.tsx index c8e32652d..303101da5 100644 --- a/apps/token/src/routes/governance/propose/update-market/propose-update-market.tsx +++ b/apps/token/src/routes/governance/propose/update-market/propose-update-market.tsx @@ -8,6 +8,7 @@ import { getEnactmentTimestamp, } from '@vegaprotocol/governance'; import { useEnvironment } from '@vegaprotocol/environment'; +import { validateJson } from '@vegaprotocol/react-helpers'; import { ProposalFormSubheader, ProposalFormMinRequirements, @@ -60,7 +61,7 @@ export interface UpdateMarketProposalFormFields { proposalReference: string; } -const docsLink = '/update-market-proposal'; +const DOCS_LINK = '/update-market-proposal'; export const ProposeUpdateMarket = () => { const { @@ -158,9 +159,9 @@ export const ProposeUpdateMarket = () => {

    {t('ProposalTermsText')} {`${VEGA_DOCS_URL}/tutorials/proposals${docsLink}`} + >{`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}

    )} @@ -255,20 +256,11 @@ export const ProposeUpdateMarket = () => { { - try { - JSON.parse(value); - return true; - } catch (e) { - return t('Must be valid JSON'); - } - }, - }, + validate: (value) => validateJson(value), })} labelOverride={t('ProposeUpdateMarketTerms')} errorMessage={errors?.proposalTerms?.message} - customDocLink={docsLink} + customDocLink={DOCS_LINK} /> + import( + /* webpackChunkName: "route-governance-propose-update-asset", webpackPrefetch: true */ './governance/propose/update-asset' + ) +); + const LazyGovernanceProposeFreeform = React.lazy( () => import( @@ -273,6 +280,10 @@ const routerConfig = [ element: , }, { path: 'new-asset', element: }, + { + path: 'update-asset', + element: , + }, { path: 'freeform', element: }, { path: 'raw', element: }, ], diff --git a/apps/token/src/routes/withdrawals/index.tsx b/apps/token/src/routes/withdrawals/index.tsx index 486fc7fa3..9fe4e9ae9 100644 --- a/apps/token/src/routes/withdrawals/index.tsx +++ b/apps/token/src/routes/withdrawals/index.tsx @@ -5,6 +5,7 @@ import { Heading } from '../../components/heading'; import { SplashLoader } from '../../components/splash-loader'; import { VegaWalletContainer } from '../../components/vega-wallet-container'; import { + PendingWithdrawalsTable, useWithdrawals, WithdrawalDialogs, WithdrawalsTable, @@ -30,7 +31,7 @@ const Withdrawals = ({ name }: RouteChildProps) => { const WithdrawPendingContainer = () => { const [withdrawDialog, setWithdrawDialog] = useState(false); const { t } = useTranslation(); - const { withdrawals, loading, error } = useWithdrawals(); + const { pending, completed, loading, error } = useWithdrawals(); if (error) { return ( @@ -58,7 +59,11 @@ const WithdrawPendingContainer = () => {

    {t('withdrawalsText')}

    {t('withdrawalsPreparedWarningText')}

    - + {pending && pending.length > 0 && ( + + )} +

    {t('Withdrawal history')}

    +
    { cy.mockGQLSubscription(); cy.mockGQL((req) => { aliasQuery(req, 'NetworkParamsQuery', generateNetworkParameters()); - aliasQuery(req, 'DepositPage', generateDepositPage()); + aliasQuery(req, 'Assets', generateAssets()); }); cy.visit('/portfolio/deposit'); @@ -22,7 +22,7 @@ describe('deposit form validation', { tags: '@smoke' }, () => { cy.getByTestId(connectEthWalletBtn).click(); cy.getByTestId('web3-connector-MetaMask').click(); - cy.wait('@DepositPage'); + cy.wait('@Assets'); }); it('handles empty fields', () => { @@ -41,7 +41,7 @@ describe('deposit form validation', { tags: '@smoke' }, () => { // Deposit amount smaller than minimum viable for selected asset // Select an amount so that we have a known decimal places value to work with - cy.get(assetSelectField).select('Asset 0'); + cy.get(assetSelectField).select('Euro'); cy.get(amountField) .clear() .type('0.00000000000000000000000000000000001') diff --git a/apps/trading-e2e/src/integration/markets.cy.ts b/apps/trading-e2e/src/integration/markets.cy.ts index b9b2f1c0d..adc6c40b9 100644 --- a/apps/trading-e2e/src/integration/markets.cy.ts +++ b/apps/trading-e2e/src/integration/markets.cy.ts @@ -115,7 +115,7 @@ describe('markets table', { tags: '@regression' }, () => { .should('have.attr', 'href') .and( 'include', - 'https://docs.fairground.vega.xyz/docs/trading-questions/#auctions-what-is-a-liquidity-monitoring-auction' + 'https://docs.vega.xyz/docs/testnet/concepts/trading-on-vega/trading-modes#auction-type-liquidity-monitoring' ); }); diff --git a/apps/trading-e2e/src/integration/trading-orders.cy.ts b/apps/trading-e2e/src/integration/trading-orders.cy.ts index 333404488..f1cc5f4e6 100644 --- a/apps/trading-e2e/src/integration/trading-orders.cy.ts +++ b/apps/trading-e2e/src/integration/trading-orders.cy.ts @@ -42,7 +42,6 @@ describe('orders', { tags: '@smoke' }, () => { it('renders orders', () => { cy.getByTestId('tab-orders').should('be.visible'); - expect(subscriptionMocks.OrderSub).to.be.calledOnce; cy.getByTestId('tab-orders').within(() => { cy.get(`[col-id='${orderSymbol}']`).each(($symbol) => { diff --git a/apps/trading-e2e/src/integration/withdraw.cy.ts b/apps/trading-e2e/src/integration/withdraw.cy.ts index 2002be06e..b47a9cb18 100644 --- a/apps/trading-e2e/src/integration/withdraw.cy.ts +++ b/apps/trading-e2e/src/integration/withdraw.cy.ts @@ -1,9 +1,9 @@ import { aliasQuery } from '@vegaprotocol/cypress'; import { connectEthereumWallet } from '../support/ethereum-wallet'; -import { generateAccounts } from '../support/mocks/generate-accounts'; import { generateChainId } from '../support/mocks/generate-chain-id'; +import { generateAccounts } from '../support/mocks/generate-accounts'; +import { generateAssets } from '../support/mocks/generate-assets'; import { generateNetworkParameters } from '../support/mocks/generate-network-parameters'; -import { generateWithdrawFormQuery } from '../support/mocks/generate-withdraw-page-query'; import { generateWithdrawals } from '../support/mocks/generate-withdrawals'; import { connectVegaWallet } from '../support/vega-wallet'; @@ -24,7 +24,7 @@ describe('withdraw', { tags: '@smoke' }, () => { aliasQuery(req, 'ChainId', generateChainId()); aliasQuery(req, 'Withdrawals', generateWithdrawals()); aliasQuery(req, 'NetworkParamsQuery', generateNetworkParameters()); - aliasQuery(req, 'WithdrawFormQuery', generateWithdrawFormQuery()); + aliasQuery(req, 'Assets', generateAssets()); aliasQuery(req, 'Accounts', generateAccounts()); }); cy.mockGQLSubscription(); @@ -39,7 +39,8 @@ describe('withdraw', { tags: '@smoke' }, () => { connectEthereumWallet(); cy.getByTestId('withdraw-dialog-button').click(); - cy.wait('@WithdrawFormQuery'); + cy.wait('@Accounts'); + cy.wait('@Assets'); }); it('form validation', () => { diff --git a/apps/trading-e2e/src/support/mocks/generate-accounts.ts b/apps/trading-e2e/src/support/mocks/generate-accounts.ts index 13c9011a3..a277be603 100644 --- a/apps/trading-e2e/src/support/mocks/generate-accounts.ts +++ b/apps/trading-e2e/src/support/mocks/generate-accounts.ts @@ -1,6 +1,6 @@ import merge from 'lodash/merge'; -import type { AccountsQuery, AssetsQuery } from '@vegaprotocol/accounts'; -import { AccountType, Schema as Types } from '@vegaprotocol/types'; +import type { AccountsQuery } from '@vegaprotocol/accounts'; +import { AccountType } from '@vegaprotocol/types'; import type { PartialDeep } from 'type-fest'; export const generateAccounts = ( @@ -70,48 +70,19 @@ export const generateAccounts = ( id: 'asset-0', }, }, + // account to withdraw Sepolia tBTC + { + __typename: 'Account', + type: AccountType.ACCOUNT_TYPE_GENERAL, + balance: '100000000', + market: null, + asset: { + __typename: 'Asset', + id: 'cee709223217281d7893b650850ae8ee8a18b7539b5658f9b4cc24de95dd18ad', + }, + }, ], }, }; return merge(defaultAccounts, override); }; - -export const generateAssets = (override?: PartialDeep) => { - const defaultAssets: AssetsQuery = { - assetsConnection: { - edges: [ - { - node: { - id: 'asset-id', - symbol: 'tEURO', - decimals: 5, - name: 'Euro', - quantum: '', - status: Types.AssetStatus.STATUS_ENABLED, - }, - }, - { - node: { - id: 'asset-id-2', - symbol: 'tDAI', - decimals: 5, - name: 'DAI', - quantum: '', - status: Types.AssetStatus.STATUS_ENABLED, - }, - }, - { - node: { - id: 'asset-0', - symbol: 'AST0', - decimals: 5, - name: 'Asto', - quantum: '', - status: Types.AssetStatus.STATUS_ENABLED, - }, - }, - ], - }, - }; - return merge(defaultAssets, override); -}; diff --git a/apps/trading-e2e/src/support/mocks/generate-assets.ts b/apps/trading-e2e/src/support/mocks/generate-assets.ts new file mode 100644 index 000000000..d5da22d46 --- /dev/null +++ b/apps/trading-e2e/src/support/mocks/generate-assets.ts @@ -0,0 +1,90 @@ +import merge from 'lodash/merge'; +import type { AssetsQuery } from '@vegaprotocol/assets'; +import { Schema as Types } from '@vegaprotocol/types'; +import type { PartialDeep } from 'type-fest'; + +export const generateAssets = (override?: PartialDeep) => { + const defaultAssets: AssetsQuery = { + assetsConnection: { + edges: [ + { + node: { + id: 'asset-id', + symbol: 'tEURO', + decimals: 5, + name: 'Euro', + source: { + __typename: 'ERC20', + contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4', + }, + quantum: '1', + status: Types.AssetStatus.STATUS_ENABLED, + }, + }, + { + node: { + id: 'asset-id-2', + symbol: 'tDAI', + decimals: 5, + name: 'DAI', + source: { + __typename: 'ERC20', + contractAddress: '0x26223f9C67871CFcEa329975f7BC0C9cB8FBDb9b', + }, + quantum: '1', + status: Types.AssetStatus.STATUS_ENABLED, + }, + }, + { + node: { + id: 'asset-0', + symbol: 'AST0', + decimals: 5, + name: 'Asto', + source: { + __typename: 'BuiltinAsset', + }, + quantum: '1', + status: Types.AssetStatus.STATUS_ENABLED, + }, + }, + // NOTE: These assets ids and contract addresses are real assets on Sepolia, this is needed + // because we don't currently mock our seplia infura provider. If we change network these will + // need to be updated + { + node: { + id: 'cee709223217281d7893b650850ae8ee8a18b7539b5658f9b4cc24de95dd18ad', + symbol: 'tBTC', + name: 'Sepolia tBTC', + decimals: 5, + status: Types.AssetStatus.STATUS_ENABLED, + source: { + __typename: 'ERC20', + contractAddress: '0x1d525fB145Af5c51766a89706C09fE07E6058D1D', + }, + quantum: '1', + __typename: 'Asset', + }, + __typename: 'AssetEdge', + }, + { + node: { + id: 'c9fe6fc24fce121b2cc72680543a886055abb560043fda394ba5376203b7527d', + symbol: 'tUSDC', + name: 'Sepolia tUSDC', + decimals: 5, + status: Types.AssetStatus.STATUS_ENABLED, + source: { + __typename: 'ERC20', + contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d81', + }, + quantum: '1', + __typename: 'Asset', + }, + __typename: 'AssetEdge', + }, + ], + }, + }; + return merge(defaultAssets, override); +}; diff --git a/apps/trading-e2e/src/support/mocks/generate-deposit-page.ts b/apps/trading-e2e/src/support/mocks/generate-deposit-page.ts deleted file mode 100644 index 105e41d07..000000000 --- a/apps/trading-e2e/src/support/mocks/generate-deposit-page.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { AssetStatus } from '@vegaprotocol/types'; -import merge from 'lodash/merge'; -import type { PartialDeep } from 'type-fest'; - -export const generateDepositPage = ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - override?: PartialDeep -) => { - const defaultResult = { - assetsConnection: { - edges: [ - { - node: { - id: 'asset-0', - symbol: 'AST0', - name: 'Asset 0', - decimals: 5, - status: AssetStatus.STATUS_ENABLED, - source: { - __typename: 'ERC20', - contractAddress: '0x5E4b9aDA947130Fc320a144cd22bC1641e5c9d81', - }, - __typename: 'Asset', - }, - __typename: 'AssetEdge', - }, - { - node: { - id: 'asset-1', - symbol: 'AST1', - name: 'Asset 1', - decimals: 5, - status: AssetStatus.STATUS_ENABLED, - source: { - __typename: 'ERC20', - contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d81', - }, - __typename: 'Asset', - }, - __typename: 'AssetEdge', - }, - { - node: { - id: 'asset-2', - symbol: 'AST2', - name: 'Asset 2', - decimals: 5, - status: AssetStatus.STATUS_PENDING_LISTING, - source: { - __typename: 'ERC20', - contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d82', - }, - __typename: 'Asset', - }, - __typename: 'AssetEdge', - }, - { - node: { - id: 'asset-3', - symbol: 'AST3', - name: 'Asset 3', - decimals: 5, - status: AssetStatus.STATUS_PROPOSED, - source: { - __typename: 'ERC20', - contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d83', - }, - __typename: 'Asset', - }, - __typename: 'AssetEdge', - }, - { - node: { - id: 'asset-4', - symbol: 'AST4', - name: 'Asset 4', - decimals: 5, - status: AssetStatus.STATUS_REJECTED, - source: { - __typename: 'ERC20', - contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d84', - }, - __typename: 'Asset', - }, - __typename: 'AssetEdge', - }, - ], - __typename: 'AssetsConnection', - }, - }; - - return merge(defaultResult, override); -}; diff --git a/apps/trading-e2e/src/support/mocks/generate-positions.ts b/apps/trading-e2e/src/support/mocks/generate-positions.ts index 666c667b9..b910bd804 100644 --- a/apps/trading-e2e/src/support/mocks/generate-positions.ts +++ b/apps/trading-e2e/src/support/mocks/generate-positions.ts @@ -1,15 +1,15 @@ import merge from 'lodash/merge'; import type { PartialDeep } from 'type-fest'; import type { - Positions, - Positions_party_positionsConnection_edges_node, - Margins, + PositionsQuery, + PositionFieldsFragment, + MarginsQuery, } from '@vegaprotocol/positions'; export const generatePositions = ( - override?: PartialDeep -): Positions => { - const nodes: Positions_party_positionsConnection_edges_node[] = [ + override?: PartialDeep +): PositionsQuery => { + const nodes: PositionFieldsFragment[] = [ { __typename: 'Position', realisedPNL: '0', @@ -48,7 +48,7 @@ export const generatePositions = ( }, ]; - const defaultResult: Positions = { + const defaultResult: PositionsQuery = { party: { __typename: 'Party', id: Cypress.env('VEGA_PUBLIC_KEY'), @@ -67,7 +67,7 @@ export const generatePositions = ( return merge(defaultResult, override); }; -export const generateMargins = (): Margins => { +export const generateMargins = (): MarginsQuery => { return { party: { id: Cypress.env('VEGA_PUBLIC_KEY'), diff --git a/apps/trading-e2e/src/support/mocks/generate-withdraw-page-query.ts b/apps/trading-e2e/src/support/mocks/generate-withdraw-page-query.ts deleted file mode 100644 index 610f6f2ca..000000000 --- a/apps/trading-e2e/src/support/mocks/generate-withdraw-page-query.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { AccountType, AssetStatus } from '@vegaprotocol/types'; -import type { - WithdrawFormQuery, - WithdrawFormQuery_assetsConnection_edges, - WithdrawFormQuery_party_accounts, - WithdrawFormQuery_party_withdrawals, -} from '@vegaprotocol/withdraws'; -import merge from 'lodash/merge'; -import type { PartialDeep } from 'type-fest'; - -export const generateWithdrawFormQuery = ( - override?: PartialDeep -): WithdrawFormQuery => { - const withdrawal: WithdrawFormQuery_party_withdrawals = { - id: 'withdrawal-0', - txHash: null, - __typename: 'Withdrawal', - }; - - // NOTE: These assets ids and contract addresses are real assets on Sepolia, this is needed - // because we don't currently mock our seplia infura provider. If we change network these will - // need to be updated - const assetEdge1: WithdrawFormQuery_assetsConnection_edges = { - node: { - id: 'cee709223217281d7893b650850ae8ee8a18b7539b5658f9b4cc24de95dd18ad', - symbol: 'tBTC', - name: 'Sepolia tBTC', - decimals: 5, - status: AssetStatus.STATUS_ENABLED, - source: { - __typename: 'ERC20', - contractAddress: '0x1d525fB145Af5c51766a89706C09fE07E6058D1D', - }, - __typename: 'Asset', - }, - __typename: 'AssetEdge', - }; - const assetEdge2: WithdrawFormQuery_assetsConnection_edges = { - node: { - id: 'c9fe6fc24fce121b2cc72680543a886055abb560043fda394ba5376203b7527d', - symbol: 'tUSDC', - name: 'Sepolia tUSDC', - decimals: 5, - status: AssetStatus.STATUS_ENABLED, - source: { - __typename: 'ERC20', - contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d81', - }, - __typename: 'Asset', - }, - __typename: 'AssetEdge', - }; - const account: WithdrawFormQuery_party_accounts = { - type: AccountType.ACCOUNT_TYPE_GENERAL, - balance: '100000000', - asset: { - __typename: 'Asset', - id: assetEdge1.node.id, - symbol: 'AST0', - }, - __typename: 'Account', - }; - - const defaultResult = { - party: { - id: 'party-0', - withdrawals: [withdrawal], - accounts: [account], - __typename: 'Party', - }, - assetsConnection: { - __typename: 'AssetsConnection', - edges: [assetEdge1, assetEdge2], - }, - }; - return merge(defaultResult, override); -}; diff --git a/apps/trading-e2e/src/support/trading.ts b/apps/trading-e2e/src/support/trading.ts index 38477e220..74f21aedc 100644 --- a/apps/trading-e2e/src/support/trading.ts +++ b/apps/trading-e2e/src/support/trading.ts @@ -1,7 +1,8 @@ import { aliasQuery } from '@vegaprotocol/cypress'; import type { MarketState } from '@vegaprotocol/types'; import type { CyHttpMessages } from 'cypress/types/net-stubbing'; -import { generateAccounts, generateAssets } from './mocks/generate-accounts'; +import { generateAccounts } from './mocks/generate-accounts'; +import { 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'; diff --git a/apps/trading/components/select-market/select-market.tsx b/apps/trading/components/select-market/select-market.tsx index 8b607b8ee..71b0b351b 100644 --- a/apps/trading/components/select-market/select-market.tsx +++ b/apps/trading/components/select-market/select-market.tsx @@ -15,7 +15,7 @@ import type { MarketWithData, } from '@vegaprotocol/market-list'; import { useVegaWallet } from '@vegaprotocol/wallet'; -import type { Positions_party_positionsConnection_edges_node } from '@vegaprotocol/positions'; +import type { PositionFieldsFragment } from '@vegaprotocol/positions'; import { positionsDataProvider } from '@vegaprotocol/positions'; import { SelectMarketTableHeader, @@ -79,7 +79,7 @@ export const SelectAllMarketsTableBody = ({ tableColumns = (market) => columns(market, onSelect, onCellClick), }: { markets?: Market[] | null; - positions?: Positions_party_positionsConnection_edges_node[]; + positions?: PositionFieldsFragment[]; title?: string; onSelect: (id: string) => void; onCellClick: OnCellClickHandler; diff --git a/apps/trading/lib/query-fragments.ts b/apps/trading/lib/query-fragments.ts deleted file mode 100644 index b1dd2ed11..000000000 --- a/apps/trading/lib/query-fragments.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { gql } from '@apollo/client'; - -export const ASSET_FRAGMENT = gql` - fragment AssetFields on Asset { - id - symbol - name - decimals - status - source { - ... on ERC20 { - contractAddress - } - } - } -`; diff --git a/apps/trading/pages/markets/[marketId].page.tsx b/apps/trading/pages/markets/[marketId].page.tsx index d62d4fa00..e668296e2 100644 --- a/apps/trading/pages/markets/[marketId].page.tsx +++ b/apps/trading/pages/markets/[marketId].page.tsx @@ -4,6 +4,7 @@ import { addDecimalsFormatNumber, t, titlefy, + useYesterday, } from '@vegaprotocol/react-helpers'; import { Interval } from '@vegaprotocol/types'; import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit'; @@ -113,12 +114,12 @@ const MarketPage = ({ id }: { id?: string }) => { } }; + const yesterday = useYesterday(); // Cache timestamp for yesterday to prevent full unmount of market page when // a rerender occurs const yTimestamp = useMemo(() => { - const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600; - return new Date(yesterday * 1000).toISOString(); - }, []); + return new Date(yesterday).toISOString(); + }, [yesterday]); const variables = useMemo( () => ({ diff --git a/apps/trading/pages/portfolio/deposit/Deposit.graphql b/apps/trading/pages/portfolio/deposit/Deposit.graphql deleted file mode 100644 index e004bf2f6..000000000 --- a/apps/trading/pages/portfolio/deposit/Deposit.graphql +++ /dev/null @@ -1,17 +0,0 @@ -query DepositPage { - assetsConnection { - edges { - node { - id - symbol - name - decimals - source { - ... on ERC20 { - contractAddress - } - } - } - } - } -} diff --git a/apps/trading/pages/portfolio/deposit/__generated__/DepositPage.ts b/apps/trading/pages/portfolio/deposit/__generated__/DepositPage.ts deleted file mode 100644 index 858b6236b..000000000 --- a/apps/trading/pages/portfolio/deposit/__generated__/DepositPage.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// @generated -// This file was automatically generated and should not be edited. - -import { AssetStatus } from "@vegaprotocol/types"; - -// ==================================================== -// GraphQL query operation: DepositPage -// ==================================================== - -export interface DepositPage_assetsConnection_edges_node_source_BuiltinAsset { - __typename: "BuiltinAsset"; -} - -export interface DepositPage_assetsConnection_edges_node_source_ERC20 { - __typename: "ERC20"; - /** - * The address of the ERC20 contract - */ - contractAddress: string; -} - -export type DepositPage_assetsConnection_edges_node_source = DepositPage_assetsConnection_edges_node_source_BuiltinAsset | DepositPage_assetsConnection_edges_node_source_ERC20; - -export interface DepositPage_assetsConnection_edges_node { - __typename: "Asset"; - /** - * The ID of the asset - */ - id: string; - /** - * The symbol of the asset (e.g: GBP) - */ - symbol: string; - /** - * The full name of the asset (e.g: Great British Pound) - */ - name: string; - /** - * The precision of the asset. Should match the decimal precision of the asset on its native chain, e.g: for ERC20 assets, it is often 18 - */ - decimals: number; - /** - * The status of the asset in the Vega network - */ - status: AssetStatus; - /** - * The origin source of the asset (e.g: an ERC20 asset) - */ - source: DepositPage_assetsConnection_edges_node_source; -} - -export interface DepositPage_assetsConnection_edges { - __typename: "AssetEdge"; - /** - * The asset information - */ - node: DepositPage_assetsConnection_edges_node; -} - -export interface DepositPage_assetsConnection { - __typename: "AssetsConnection"; - /** - * The assets - */ - edges: (DepositPage_assetsConnection_edges | null)[] | null; -} - -export interface DepositPage { - /** - * The list of all assets in use in the Vega network or the specified asset if ID is provided - */ - assetsConnection: DepositPage_assetsConnection | null; -} diff --git a/apps/trading/pages/portfolio/deposit/__generated___/Deposit.ts b/apps/trading/pages/portfolio/deposit/__generated___/Deposit.ts deleted file mode 100644 index a695f0dc0..000000000 --- a/apps/trading/pages/portfolio/deposit/__generated___/Deposit.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Schema as Types } from '@vegaprotocol/types'; - -import { gql } from '@apollo/client'; -import * as Apollo from '@apollo/client'; -const defaultOptions = {} as const; -export type DepositPageQueryVariables = Types.Exact<{ [key: string]: never; }>; - - -export type DepositPageQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string } } } | null> | null } | null }; - - -export const DepositPageDocument = gql` - query DepositPage { - assetsConnection { - edges { - node { - id - symbol - name - decimals - source { - ... on ERC20 { - contractAddress - } - } - } - } - } -} - `; - -/** - * __useDepositPageQuery__ - * - * To run a query within a React component, call `useDepositPageQuery` and pass it any options that fit your needs. - * When your component renders, `useDepositPageQuery` 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 } = useDepositPageQuery({ - * variables: { - * }, - * }); - */ -export function useDepositPageQuery(baseOptions?: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(DepositPageDocument, options); - } -export function useDepositPageLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(DepositPageDocument, options); - } -export type DepositPageQueryHookResult = ReturnType; -export type DepositPageLazyQueryHookResult = ReturnType; -export type DepositPageQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/trading/pages/portfolio/deposit/deposit-container.tsx b/apps/trading/pages/portfolio/deposit/deposit-container.tsx index cf609c592..0a1821361 100644 --- a/apps/trading/pages/portfolio/deposit/deposit-container.tsx +++ b/apps/trading/pages/portfolio/deposit/deposit-container.tsx @@ -1,37 +1,24 @@ -import { gql } from '@apollo/client'; -import { PageQueryContainer } from '../../../components/page-query-container'; -import type { DepositPage } from './__generated__/DepositPage'; import { DepositManager } from '@vegaprotocol/deposits'; -import { getEnabledAssets, t } from '@vegaprotocol/react-helpers'; +import { useDataProvider, t } from '@vegaprotocol/react-helpers'; +import { enabledAssetsProvider } from '@vegaprotocol/assets'; import { useEnvironment } from '@vegaprotocol/environment'; -import { Splash } from '@vegaprotocol/ui-toolkit'; -import { ASSET_FRAGMENT } from '../../../lib/query-fragments'; - -const DEPOSIT_PAGE_QUERY = gql` - ${ASSET_FRAGMENT} - query DepositPage { - assetsConnection { - edges { - node { - ...AssetFields - } - } - } - } -`; +import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit'; /** * Fetches data required for the Deposit page */ export const DepositContainer = () => { const { VEGA_ENV } = useEnvironment(); - + const { data, error, loading } = useDataProvider({ + dataProvider: enabledAssetsProvider, + }); return ( - - query={DEPOSIT_PAGE_QUERY} - render={(data) => { - const assets = getEnabledAssets(data); - if (!assets.length) { + { + if (!assets || !assets.length) { return (

    {t('No assets on this network')}

    diff --git a/apps/trading/pages/portfolio/withdrawals-container.tsx b/apps/trading/pages/portfolio/withdrawals-container.tsx index 6299a6677..d3772d625 100644 --- a/apps/trading/pages/portfolio/withdrawals-container.tsx +++ b/apps/trading/pages/portfolio/withdrawals-container.tsx @@ -1,5 +1,6 @@ import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit'; import { + PendingWithdrawalsTable, useWithdrawals, WithdrawalDialogs, WithdrawalsTable, @@ -10,7 +11,7 @@ import { VegaWalletContainer } from '../../components/vega-wallet-container'; import { Web3Container } from '@vegaprotocol/web3'; export const WithdrawalsContainer = () => { - const { withdrawals, loading, error } = useWithdrawals(); + const { pending, completed, loading, error } = useWithdrawals(); const [withdrawDialog, setWithdrawDialog] = useState(false); return ( @@ -25,17 +26,27 @@ export const WithdrawalsContainer = () => { onClick={() => setWithdrawDialog(true)} data-testid="withdraw-dialog-button" > - {t('Withdraw')} + {t('Make withdrawal')} -
    +
    { - return ; - }} + render={({ pending, completed }) => ( + <> + {pending && pending.length > 0 && ( + <> +

    {t('Pending withdrawals')}

    + + + )} + +

    {t('Withdrawal history')}

    + + + )} />
    diff --git a/libs/accounts/src/lib/Accounts.graphql b/libs/accounts/src/lib/Accounts.graphql index 661080629..1d91d95d2 100644 --- a/libs/accounts/src/lib/Accounts.graphql +++ b/libs/accounts/src/lib/Accounts.graphql @@ -26,22 +26,3 @@ subscription AccountEvents($partyId: ID!) { marketId } } - -fragment AssetsFields on Asset { - id - name - symbol - decimals - quantum - status -} - -query Assets { - assetsConnection { - edges { - node { - ...AssetsFields - } - } - } -} diff --git a/libs/accounts/src/lib/__generated___/Accounts.ts b/libs/accounts/src/lib/__generated___/Accounts.ts index b45f04ac9..5a80482fd 100644 --- a/libs/accounts/src/lib/__generated___/Accounts.ts +++ b/libs/accounts/src/lib/__generated___/Accounts.ts @@ -19,13 +19,6 @@ export type AccountEventsSubscriptionVariables = Types.Exact<{ export type AccountEventsSubscription = { __typename?: 'Subscription', accounts: Array<{ __typename?: 'AccountUpdate', type: Types.AccountType, balance: string, assetId: string, marketId?: string | null }> }; -export type AssetsFieldsFragment = { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus }; - -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 } } | null> | null } | null }; - export const AccountFieldsFragmentDoc = gql` fragment AccountFields on Account { type @@ -38,16 +31,6 @@ export const AccountFieldsFragmentDoc = gql` } } `; -export const AssetsFieldsFragmentDoc = gql` - fragment AssetsFields on Asset { - id - name - symbol - decimals - quantum - status -} - `; export const AccountsDocument = gql` query Accounts($partyId: ID!) { party(id: $partyId) { @@ -118,42 +101,4 @@ export function useAccountEventsSubscription(baseOptions: Apollo.SubscriptionHoo return Apollo.useSubscription(AccountEventsDocument, options); } export type AccountEventsSubscriptionHookResult = ReturnType; -export type AccountEventsSubscriptionResult = Apollo.SubscriptionResult; -export const AssetsDocument = gql` - query Assets { - assetsConnection { - edges { - node { - ...AssetsFields - } - } - } -} - ${AssetsFieldsFragmentDoc}`; - -/** - * __useAssetsQuery__ - * - * To run a query within a React component, call `useAssetsQuery` and pass it any options that fit your needs. - * When your component renders, `useAssetsQuery` 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 } = useAssetsQuery({ - * variables: { - * }, - * }); - */ -export function useAssetsQuery(baseOptions?: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(AssetsDocument, options); - } -export function useAssetsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(AssetsDocument, options); - } -export type AssetsQueryHookResult = ReturnType; -export type AssetsLazyQueryHookResult = ReturnType; -export type AssetsQueryResult = Apollo.QueryResult; \ No newline at end of file +export type AccountEventsSubscriptionResult = Apollo.SubscriptionResult; \ No newline at end of file diff --git a/libs/accounts/src/lib/accounts-data-provider.ts b/libs/accounts/src/lib/accounts-data-provider.ts index 299b8e789..8a381109d 100644 --- a/libs/accounts/src/lib/accounts-data-provider.ts +++ b/libs/accounts/src/lib/accounts-data-provider.ts @@ -8,7 +8,6 @@ import type { AccountFieldsFragment, AccountsQuery, AccountEventsSubscription, - AssetsFieldsFragment, } from './__generated___/Accounts'; import { makeDataProvider, @@ -17,7 +16,8 @@ import { import { AccountType } from '@vegaprotocol/types'; import type { Market } from '@vegaprotocol/market-list'; import { marketsProvider } from '@vegaprotocol/market-list'; -import { assetProvider } from './asset-data-provider'; +import type { AssetsFieldsFragment } from '@vegaprotocol/assets'; +import { assetsProvider } from '@vegaprotocol/assets'; function isAccount( account: @@ -77,7 +77,7 @@ const getDelta = ( subscriptionData: AccountEventsSubscription ): AccountEventsSubscription['accounts'] => subscriptionData.accounts; -export const accountsBasedDataProvider = makeDataProvider< +export const accountsOnlyDataProvider = makeDataProvider< AccountsQuery, AccountFieldsFragment[], AccountEventsSubscription, @@ -114,10 +114,12 @@ const getTotalBalance = (accounts: AccountFieldsFragment[]) => accounts.reduce((acc, a) => acc + BigInt(a.balance), BigInt(0)); export const getAccountData = (data: Account[]): AccountFields[] => { - return getAssetIds(data).map((assetId) => { - const accounts = data.filter((a) => a.asset.id === assetId); - return accounts && getAssetAccountAggregation(accounts, assetId); - }); + return getAssetIds(data) + .map((assetId) => { + const accounts = data.filter((a) => a.asset.id === assetId); + return accounts && getAssetAccountAggregation(accounts, assetId); + }) + .filter((a) => a.deposited !== '0'); // filter empty accounts }; const getAssetAccountAggregation = ( @@ -150,12 +152,13 @@ const getAssetAccountAggregation = ( deposited: balanceAccount.deposited, available: balanceAccount.available, used: a.balance, - })); + })) + .filter((a) => a.used !== '0'); return { ...balanceAccount, breakdown }; }; export const accountsDataProvider = makeDerivedDataProvider( - [accountsBasedDataProvider, marketsProvider, assetProvider], + [accountsOnlyDataProvider, marketsProvider, assetsProvider], ([accounts, markets, assets]): Account[] | null => { return accounts ? accounts diff --git a/libs/accounts/src/lib/accounts-manager.tsx b/libs/accounts/src/lib/accounts-manager.tsx index 231a37795..9ed00c085 100644 --- a/libs/accounts/src/lib/accounts-manager.tsx +++ b/libs/accounts/src/lib/accounts-manager.tsx @@ -1,4 +1,4 @@ -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import { useDataProvider } from '@vegaprotocol/react-helpers'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import type { AgGridReact } from 'ag-grid-react'; diff --git a/libs/accounts/src/lib/accounts-table.spec.tsx b/libs/accounts/src/lib/accounts-table.spec.tsx index 3a7fcb152..254a7b0c4 100644 --- a/libs/accounts/src/lib/accounts-table.spec.tsx +++ b/libs/accounts/src/lib/accounts-table.spec.tsx @@ -38,7 +38,7 @@ describe('AccountsTable', () => { null} /> ); }); - const expectedHeaders = ['Asset', 'Deposited', 'Used', '', '']; + const expectedHeaders = ['Asset', 'Total', 'Used', '', '']; const headers = await screen.findAllByRole('columnheader'); expect(headers).toHaveLength(expectedHeaders.length); expect( diff --git a/libs/accounts/src/lib/accounts-table.tsx b/libs/accounts/src/lib/accounts-table.tsx index 5c52f00db..aeb25886b 100644 --- a/libs/accounts/src/lib/accounts-table.tsx +++ b/libs/accounts/src/lib/accounts-table.tsx @@ -1,6 +1,6 @@ import { forwardRef, useState } from 'react'; import type { ValueFormatterParams } from 'ag-grid-community'; -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers'; import type { ValueProps, @@ -109,8 +109,11 @@ export const AccountTable = forwardRef( maxWidth={300} /> ( headerName={t('Used')} field="used" flex={2} + minWidth={150} maxWidth={500} headerComponentParams={progressBarHeaderComponentParams} cellRendererSelector={progressBarCellRendererSelector} @@ -133,7 +137,7 @@ export const AccountTable = forwardRef( ) => { @@ -154,6 +158,7 @@ export const AccountTable = forwardRef( colId="transact" headerName="" sortable={false} + minWidth={250} cellRenderer={({ data, }: VegaICellRendererParams) => { diff --git a/libs/accounts/src/lib/asset-data-provider.ts b/libs/accounts/src/lib/asset-data-provider.ts deleted file mode 100644 index 7509b61d4..000000000 --- a/libs/accounts/src/lib/asset-data-provider.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { makeDataProvider } from '@vegaprotocol/react-helpers'; -import { AssetsDocument } from './__generated___/Accounts'; -import type { - AssetsQuery, - AssetsFieldsFragment, -} from './__generated___/Accounts'; - -const getData = (responseData: AssetsQuery) => - responseData.assetsConnection?.edges - ?.filter((e) => Boolean(e?.node)) - .map((e) => e?.node as AssetsFieldsFragment) ?? null; - -export const assetProvider = makeDataProvider< - AssetsQuery, - AssetsFieldsFragment[] | null, - never, - never ->({ - query: AssetsDocument, - getData, -}); diff --git a/libs/accounts/src/lib/breakdown-table.spec.tsx b/libs/accounts/src/lib/breakdown-table.spec.tsx index 36be0d297..59d1016f2 100644 --- a/libs/accounts/src/lib/breakdown-table.spec.tsx +++ b/libs/accounts/src/lib/breakdown-table.spec.tsx @@ -37,10 +37,10 @@ describe('BreakdownTable', () => { render(); }); const headers = await screen.findAllByRole('columnheader'); - expect(headers).toHaveLength(5); + expect(headers).toHaveLength(4); expect( headers.map((h) => h.querySelector('[ref="eText"]')?.textContent?.trim()) - ).toEqual(['Account type', 'Market', 'Used', 'Deposited', 'Balance']); + ).toEqual(['Account type', 'Market', 'Used', 'Balance']); }); it('should apply correct formatting', async () => { diff --git a/libs/accounts/src/lib/breakdown-table.tsx b/libs/accounts/src/lib/breakdown-table.tsx index fc7e7a12d..fdf809fe0 100644 --- a/libs/accounts/src/lib/breakdown-table.tsx +++ b/libs/accounts/src/lib/breakdown-table.tsx @@ -74,21 +74,6 @@ const BreakdownTable = forwardRef( cellRendererSelector={progressBarCellRendererSelector} valueFormatter={progressBarValueFormatter} /> - - ) => { - if (data && data.asset) { - return addDecimalsFormatNumber(value, data.asset.decimals); - } - return '-'; - }} - maxWidth={300} - /> ; - - -export type AssetQuery = { __typename?: 'Query', asset?: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string } } | null }; - - -export const AssetDocument = gql` - query Asset($assetId: ID!) { - asset(id: $assetId) { - id - name - symbol - decimals - quantum - source { - ... on ERC20 { - contractAddress - lifetimeLimit - withdrawThreshold - } - } - } -} - `; - -/** - * __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) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(AssetDocument, options); - } -export function useAssetLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(AssetDocument, options); - } -export type AssetQueryHookResult = ReturnType; -export type AssetLazyQueryHookResult = ReturnType; -export type AssetQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/libs/assets/src/lib/__generated___/Assets.ts b/libs/assets/src/lib/__generated___/Assets.ts index a4d53232e..07c585f43 100644 --- a/libs/assets/src/lib/__generated___/Assets.ts +++ b/libs/assets/src/lib/__generated___/Assets.ts @@ -3,58 +3,63 @@ import { Schema as Types } from '@vegaprotocol/types'; import { gql } from '@apollo/client'; import * as Apollo from '@apollo/client'; const defaultOptions = {} as const; -export type AssetsConnectionQueryVariables = Types.Exact<{ [key: string]: never; }>; +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 AssetsConnectionQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: 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' } | { __typename?: 'ERC20', contractAddress: string } } } | null> | null } | null }; - -export const AssetsConnectionDocument = gql` - query AssetsConnection { - assetsConnection { - edges { - node { - id - name - symbol - decimals - quantum - source { - ... on ERC20 { - contractAddress - lifetimeLimit - withdrawThreshold - } - } - } +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 + } + } + } +} + ${AssetsFieldsFragmentDoc}`; /** - * __useAssetsConnectionQuery__ + * __useAssetsQuery__ * - * To run a query within a React component, call `useAssetsConnectionQuery` and pass it any options that fit your needs. - * When your component renders, `useAssetsConnectionQuery` returns an object from Apollo Client that contains loading, error, and data properties + * To run a query within a React component, call `useAssetsQuery` and pass it any options that fit your needs. + * When your component renders, `useAssetsQuery` 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 } = useAssetsConnectionQuery({ + * const { data, loading, error } = useAssetsQuery({ * variables: { * }, * }); */ -export function useAssetsConnectionQuery(baseOptions?: Apollo.QueryHookOptions) { +export function useAssetsQuery(baseOptions?: Apollo.QueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(AssetsConnectionDocument, options); + return Apollo.useQuery(AssetsDocument, options); } -export function useAssetsConnectionLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { +export function useAssetsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(AssetsConnectionDocument, options); + return Apollo.useLazyQuery(AssetsDocument, options); } -export type AssetsConnectionQueryHookResult = ReturnType; -export type AssetsConnectionLazyQueryHookResult = ReturnType; -export type AssetsConnectionQueryResult = Apollo.QueryResult; \ No newline at end of file +export type AssetsQueryHookResult = ReturnType; +export type AssetsLazyQueryHookResult = ReturnType; +export type AssetsQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/libs/assets/src/lib/asset-details-dialog.spec.tsx b/libs/assets/src/lib/asset-details-dialog.spec.tsx index 509322051..29715a999 100644 --- a/libs/assets/src/lib/asset-details-dialog.spec.tsx +++ b/libs/assets/src/lib/asset-details-dialog.spec.tsx @@ -1,7 +1,7 @@ import { MockedProvider } from '@apollo/react-testing'; import { render, screen } from '@testing-library/react'; import { AssetDetailsDialog } from './asset-details-dialog'; -import { AssetsConnectionDocument } from './__generated___/Assets'; +import { AssetsDocument } from './__generated___/Assets'; const mockedData = { data: { @@ -273,7 +273,7 @@ const mockedData = { const mocks = [ { request: { - query: AssetsConnectionDocument, + query: AssetsDocument, variables: {}, }, result: mockedData, diff --git a/libs/assets/src/lib/asset-details-dialog.tsx b/libs/assets/src/lib/asset-details-dialog.tsx index badcb096d..e5cc37d27 100644 --- a/libs/assets/src/lib/asset-details-dialog.tsx +++ b/libs/assets/src/lib/asset-details-dialog.tsx @@ -1,5 +1,9 @@ -import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers'; -import type { Asset } from '@vegaprotocol/react-helpers'; +import { + addDecimalsFormatNumber, + t, + useDataProvider, +} from '@vegaprotocol/react-helpers'; +import type { Asset } from './assets-data-provider'; import { Button, Dialog, @@ -9,7 +13,7 @@ import { Splash, Tooltip, } from '@vegaprotocol/ui-toolkit'; -import { useAssetsConnectionQuery } from './__generated___/Assets'; +import { assetsProvider } from './assets-data-provider'; import type { Schema } from '@vegaprotocol/types'; import create from 'zustand'; @@ -59,12 +63,10 @@ export const AssetDetailsDialog = ({ open, onChange, }: AssetDetailsDialogProps) => { - const { data } = useAssetsConnectionQuery(); + const { data } = useDataProvider({ dataProvider: assetsProvider }); const symbol = typeof assetSymbol === 'string' ? assetSymbol : assetSymbol.symbol; - const asset = data?.assetsConnection?.edges?.find( - (e) => e?.node.symbol === symbol - ); + const asset = data?.find((a) => a?.symbol === symbol); let details: AssetDetails = []; if (asset != null) { @@ -72,31 +74,31 @@ export const AssetDetailsDialog = ({ { key: 'name', label: t('Name'), - value: asset.node.name, + value: asset.name, tooltip: '', // t('Name of the asset (e.g: Great British Pound)') }, { key: 'symbol', label: t('Symbol'), - value: asset.node.symbol, + value: asset.symbol, tooltip: '', // t('Symbol of the asset (e.g: GBP)') }, { key: 'decimals', label: t('Decimals'), - value: asset.node.decimals.toString(), + value: asset.decimals.toString(), tooltip: t('Number of decimal / precision handled by this asset'), }, { key: 'quantum', label: t('Quantum'), - value: asset.node.quantum, + value: asset.quantum, tooltip: t('The minimum economically meaningful amount in the asset'), }, { key: 'contractaddress', label: t('Contract address'), - value: (asset.node.source as Schema.ERC20).contractAddress, + value: (asset.source as Schema.ERC20).contractAddress, tooltip: t( 'The address of the contract for the token, on the ethereum network' ), @@ -105,8 +107,8 @@ export const AssetDetailsDialog = ({ key: 'withdrawalthreshold', label: t('Withdrawal threshold'), value: addDecimalsFormatNumber( - (asset.node.source as Schema.ERC20).withdrawThreshold, - asset.node.decimals + (asset.source as Schema.ERC20).withdrawThreshold, + asset.decimals ), tooltip: t( 'The maximum allowed per withdraw note: this is a temporary measure for restricted mainnet' @@ -116,8 +118,8 @@ export const AssetDetailsDialog = ({ key: 'lifetimelimit', label: t('Lifetime limit'), value: addDecimalsFormatNumber( - (asset.node.source as Schema.ERC20).lifetimeLimit, - asset.node.decimals + (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' diff --git a/libs/assets/src/lib/assets-data-provider.ts b/libs/assets/src/lib/assets-data-provider.ts new file mode 100644 index 000000000..c811357c4 --- /dev/null +++ b/libs/assets/src/lib/assets-data-provider.ts @@ -0,0 +1,60 @@ +import { + makeDataProvider, + makeDerivedDataProvider, +} 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; + +export interface ERC20AssetSource { + __typename: 'ERC20'; + contractAddress: string; +} + +export interface BuiltinAssetSource { + __typename: 'BuiltinAsset'; +} + +export type ERC20Asset = Omit & { + source: ERC20AssetSource; +}; + +export type BuiltinAsset = Omit & { + source: BuiltinAssetSource; +}; + +export const isAssetTypeERC20 = ( + asset?: Pick +): asset is ERC20Asset => { + if (!asset?.source) return false; + return asset.source.__typename === 'ERC20'; +}; + +const getData = (responseData: AssetsQuery) => + responseData.assetsConnection?.edges + ?.filter((e) => Boolean(e?.node)) + .map((e) => e?.node as Asset) ?? []; + +export const assetsProvider = makeDataProvider< + AssetsQuery, + Asset[] | null, + never, + never +>({ + query: AssetsDocument, + getData, +}); + +export const enabledAssetsProvider = makeDerivedDataProvider< + ReturnType, + never +>([assetsProvider], ([assets]) => + (assets as ReturnType).filter( + (a) => a.status === AssetStatus.STATUS_ENABLED + ) +); diff --git a/libs/assets/src/lib/index.ts b/libs/assets/src/lib/index.ts index c07a13583..b8041e7cb 100644 --- a/libs/assets/src/lib/index.ts +++ b/libs/assets/src/lib/index.ts @@ -1,2 +1,3 @@ export * from './__generated___/Assets'; +export * from './assets-data-provider'; export * from './asset-details-dialog'; diff --git a/libs/assets/tsconfig.spec.json b/libs/assets/tsconfig.spec.json index a85d573fc..3da863401 100644 --- a/libs/assets/tsconfig.spec.json +++ b/libs/assets/tsconfig.spec.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "../../dist/out-tsc", "module": "commonjs", - "types": ["jest", "node"] + "types": ["jest", "node", "@testing-library/jest-dom"] }, "include": [ "**/*.test.ts", diff --git a/libs/cypress/src/index.ts b/libs/cypress/src/index.ts index 48352ef64..465f2826e 100644 --- a/libs/cypress/src/index.ts +++ b/libs/cypress/src/index.ts @@ -12,6 +12,7 @@ import { addVegaWalletReceiveFaucetedAsset } from './lib/commands/vega-wallet-re import { addVegaWalletImport } from './lib/commands/vega-wallet-import'; import { addContainsExactly } from './lib/commands/contains-exactly'; import { addRestartVegacapsuleNetwork } from './lib/commands/restart-vegacapsule-network'; +import { addGetNetworkParameters } from './lib/commands/get-network-parameters'; addGetTestIdcommand(); addSlackCommand(); @@ -25,6 +26,7 @@ addGetAssetInformation(); addVegaWalletImport(); addContainsExactly(); addRestartVegacapsuleNetwork(); +addGetNetworkParameters(); export * from './lib/graphql-test-utils'; export type { onMessage } from './lib/commands/mock-gql'; diff --git a/libs/cypress/src/lib/commands/get-network-parameters.ts b/libs/cypress/src/lib/commands/get-network-parameters.ts new file mode 100644 index 000000000..108bfaee0 --- /dev/null +++ b/libs/cypress/src/lib/commands/get-network-parameters.ts @@ -0,0 +1,33 @@ +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Chainable { + get_network_parameters(): void; + } + } +} + +export function addGetNetworkParameters() { + // @ts-ignore - ignoring Cypress type error which gets resolved when Cypress uses the command + Cypress.Commands.add('get_network_parameters', () => { + const mutation = '{networkParameters {key value}}'; + cy.request({ + method: 'POST', + url: `http://localhost:3028/query`, + body: { + query: mutation, + }, + headers: { 'content-type': 'application/json' }, + }) + .its('body.data.networkParameters') + .then(function (response) { + // @ts-ignore - ignoring Cypress type error which gets resolved when Cypress uses the command + const object = response.reduce(function (r, e) { + r[e.key] = e.value; + return r; + }, {}); + return object; + }); + }); +} diff --git a/libs/cypress/src/lib/commands/vega-wallet-import.ts b/libs/cypress/src/lib/commands/vega-wallet-import.ts index 47c81bba4..02cfb7055 100644 --- a/libs/cypress/src/lib/commands/vega-wallet-import.ts +++ b/libs/cypress/src/lib/commands/vega-wallet-import.ts @@ -11,20 +11,20 @@ declare global { 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')}`); + const walletName = Cypress.env('vegaWalletName'); + const walletLocation = Cypress.env('vegaWalletLocation'); + + cy.highlight(`Importing Vega Wallet ${walletName}`); + cy.exec(`vega wallet init -f --home ${walletLocation}`); 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' - )}`, + `vega wallet import -w ${walletName} --recovery-phrase-file ./src/fixtures/wallet/recovery -p ./src/fixtures/wallet/passphrase --home ${walletLocation}`, { failOnNonZeroExit: false } ); cy.exec( - `vega wallet service run --network DV --automatic-consent --home ${Cypress.env( - 'vegaWalletLocation' - )}` + `vega wallet key generate -w ${walletName} -p ./src/fixtures/wallet/passphrase --home ${walletLocation}` + ); + cy.exec( + `vega wallet service run --network DV --automatic-consent --home ${walletLocation}` ); }); } diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-market-amount.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-market-amount.tsx index 91d0d7c42..11c134ae8 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-market-amount.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-market-amount.tsx @@ -17,7 +17,7 @@ export const DealTicketMarketAmount = ({ }: DealTicketMarketAmountProps) => { const sizeStep = toDecimal(market?.positionDecimalPlaces); return ( -
    +
    - +
    {t(`Estimated uncrossing price`)} - +
    )} - +
    {price && quoteName ? ( <> ~{price} {quoteName} @@ -57,7 +57,7 @@ export const DealTicketMarketAmount = ({ ) : ( '-' )} - +
    ); diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx index eed0852d1..7c9a94486 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx @@ -15,8 +15,10 @@ import { ExpirySelector } from './expiry-selector'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import { OrderTimeInForce, OrderType } from '@vegaprotocol/types'; import { getDefaultOrder } from '../deal-ticket-validation'; -import { useOrderValidation } from '../deal-ticket-validation/use-order-validation'; -import { MarketTradingMode } from '@vegaprotocol/types'; +import { + isMarketInAuction, + useOrderValidation, +} from '../deal-ticket-validation/use-order-validation'; export type TransactionStatus = 'default' | 'pending'; @@ -73,16 +75,15 @@ export const DealTicket = ({ ); const getPrice = () => { - if ( - market.tradingMode === MarketTradingMode.TRADING_MODE_OPENING_AUCTION || - market.tradingMode === MarketTradingMode.TRADING_MODE_BATCH_AUCTION - ) { - return market.data?.indicativePrice; - } - if ( - market.tradingMode === MarketTradingMode.TRADING_MODE_MONITORING_AUCTION - ) { - return null; + if (isMarketInAuction(market)) { + // 0 can never be a valid uncrossing price as it would require there being orders on the book at that price. + if ( + market.data?.indicativePrice && + BigInt(market.data?.indicativePrice) !== BigInt(0) + ) { + return market.data.indicativePrice; + } + return '-'; } return market.depth.lastTrade?.price; }; diff --git a/libs/deal-ticket/src/components/trading-mode-tooltip/compile-grid-data.tsx b/libs/deal-ticket/src/components/trading-mode-tooltip/compile-grid-data.tsx index 0f15ec962..ebd9fe270 100644 --- a/libs/deal-ticket/src/components/trading-mode-tooltip/compile-grid-data.tsx +++ b/libs/deal-ticket/src/components/trading-mode-tooltip/compile-grid-data.tsx @@ -77,7 +77,7 @@ export const compileGridData = ( '~' + addDecimalsFormatNumber( market.data.indicativePrice, - market.positionDecimalPlaces + market.decimalPlaces ), }); } diff --git a/libs/deposits/src/lib/__generated__/Deposit.ts b/libs/deposits/src/lib/__generated__/Deposit.ts deleted file mode 100644 index 2d06ea49a..000000000 --- a/libs/deposits/src/lib/__generated__/Deposit.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { Schema as Types } from '@vegaprotocol/types'; - -import { gql } from '@apollo/client'; -import * as Apollo from '@apollo/client'; -const defaultOptions = {} as const; -export type DepositFieldsFragment = { __typename?: 'Deposit', id: string, status: Types.DepositStatus, amount: string, createdTimestamp: string, creditedTimestamp?: string | null, txHash?: string | null, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } }; - -export type DepositsQueryVariables = Types.Exact<{ - partyId: Types.Scalars['ID']; -}>; - - -export type DepositsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, depositsConnection?: { __typename?: 'DepositsConnection', edges?: Array<{ __typename?: 'DepositEdge', node: { __typename?: 'Deposit', id: string, status: Types.DepositStatus, amount: string, createdTimestamp: string, creditedTimestamp?: string | null, txHash?: string | null, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } } } | null> | null } | null } | null }; - -export type DepositEventSubscriptionVariables = Types.Exact<{ - partyId: Types.Scalars['ID']; -}>; - - -export type DepositEventSubscription = { __typename?: 'Subscription', busEvents?: Array<{ __typename?: 'BusEvent', event: { __typename?: 'Account' } | { __typename?: 'Asset' } | { __typename?: 'AuctionEvent' } | { __typename?: 'Deposit', id: string, status: Types.DepositStatus, amount: string, createdTimestamp: string, creditedTimestamp?: string | null, txHash?: string | null, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } } | { __typename?: 'LiquidityProvision' } | { __typename?: 'LossSocialization' } | { __typename?: 'MarginLevels' } | { __typename?: 'Market' } | { __typename?: 'MarketData' } | { __typename?: 'MarketEvent' } | { __typename?: 'MarketTick' } | { __typename?: 'NodeSignature' } | { __typename?: 'OracleSpec' } | { __typename?: 'Order' } | { __typename?: 'Party' } | { __typename?: 'PositionResolution' } | { __typename?: 'Proposal' } | { __typename?: 'RiskFactor' } | { __typename?: 'SettleDistressed' } | { __typename?: 'SettlePosition' } | { __typename?: 'TimeUpdate' } | { __typename?: 'Trade' } | { __typename?: 'TransferResponses' } | { __typename?: 'Vote' } | { __typename?: 'Withdrawal' } }> | null }; - -export const DepositFieldsFragmentDoc = gql` - fragment DepositFields on Deposit { - id - status - amount - asset { - id - symbol - decimals - } - createdTimestamp - creditedTimestamp - txHash -} - `; -export const DepositsDocument = gql` - query Deposits($partyId: ID!) { - party(id: $partyId) { - id - depositsConnection { - edges { - node { - ...DepositFields - } - } - } - } -} - ${DepositFieldsFragmentDoc}`; - -/** - * __useDepositsQuery__ - * - * To run a query within a React component, call `useDepositsQuery` and pass it any options that fit your needs. - * When your component renders, `useDepositsQuery` 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 } = useDepositsQuery({ - * variables: { - * partyId: // value for 'partyId' - * }, - * }); - */ -export function useDepositsQuery(baseOptions: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(DepositsDocument, options); - } -export function useDepositsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(DepositsDocument, options); - } -export type DepositsQueryHookResult = ReturnType; -export type DepositsLazyQueryHookResult = ReturnType; -export type DepositsQueryResult = Apollo.QueryResult; -export const DepositEventDocument = gql` - subscription DepositEvent($partyId: ID!) { - busEvents(partyId: $partyId, batchSize: 0, types: [Deposit]) { - event { - ... on Deposit { - ...DepositFields - } - } - } -} - ${DepositFieldsFragmentDoc}`; - -/** - * __useDepositEventSubscription__ - * - * To run a query within a React component, call `useDepositEventSubscription` and pass it any options that fit your needs. - * When your component renders, `useDepositEventSubscription` 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 subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = useDepositEventSubscription({ - * variables: { - * partyId: // value for 'partyId' - * }, - * }); - */ -export function useDepositEventSubscription(baseOptions: Apollo.SubscriptionHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useSubscription(DepositEventDocument, options); - } -export type DepositEventSubscriptionHookResult = ReturnType; -export type DepositEventSubscriptionResult = Apollo.SubscriptionResult; \ No newline at end of file diff --git a/libs/deposits/src/lib/__generated__/DepositAsset.ts b/libs/deposits/src/lib/__generated__/DepositAsset.ts deleted file mode 100644 index 5113e5c4e..000000000 --- a/libs/deposits/src/lib/__generated__/DepositAsset.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// @generated -// This file was automatically generated and should not be edited. - -import { AssetStatus } from "@vegaprotocol/types"; - -// ==================================================== -// GraphQL query operation: DepositAsset -// ==================================================== - -export interface DepositAsset_assetsConnection_edges_node_source_BuiltinAsset { - __typename: "BuiltinAsset"; -} - -export interface DepositAsset_assetsConnection_edges_node_source_ERC20 { - __typename: "ERC20"; - /** - * The address of the ERC20 contract - */ - contractAddress: string; -} - -export type DepositAsset_assetsConnection_edges_node_source = DepositAsset_assetsConnection_edges_node_source_BuiltinAsset | DepositAsset_assetsConnection_edges_node_source_ERC20; - -export interface DepositAsset_assetsConnection_edges_node { - __typename: "Asset"; - /** - * The ID of the asset - */ - id: string; - /** - * The full name of the asset (e.g: Great British Pound) - */ - name: string; - /** - * The symbol of the asset (e.g: GBP) - */ - symbol: string; - /** - * The precision of the asset. Should match the decimal precision of the asset on its native chain, e.g: for ERC20 assets, it is often 18 - */ - decimals: number; - /** - * The status of the asset in the Vega network - */ - status: AssetStatus; - /** - * The origin source of the asset (e.g: an ERC20 asset) - */ - source: DepositAsset_assetsConnection_edges_node_source; -} - -export interface DepositAsset_assetsConnection_edges { - __typename: "AssetEdge"; - node: DepositAsset_assetsConnection_edges_node; -} - -export interface DepositAsset_assetsConnection { - __typename: "AssetsConnection"; - /** - * The assets - */ - edges: (DepositAsset_assetsConnection_edges | null)[] | null; -} - -export interface DepositAsset { - /** - * The list of all assets in use in the Vega network or the specified asset if ID is provided - */ - assetsConnection: DepositAsset_assetsConnection; -} diff --git a/libs/deposits/src/lib/__generated__/index.ts b/libs/deposits/src/lib/__generated__/index.ts deleted file mode 100644 index 28bd955ea..000000000 --- a/libs/deposits/src/lib/__generated__/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './Deposit'; -export * from './DepositAsset'; diff --git a/libs/deposits/src/lib/deposit-container.tsx b/libs/deposits/src/lib/deposit-container.tsx index 05611bcac..fa680011d 100644 --- a/libs/deposits/src/lib/deposit-container.tsx +++ b/libs/deposits/src/lib/deposit-container.tsx @@ -1,54 +1,26 @@ -import { gql, useQuery } from '@apollo/client'; import { Networks, useEnvironment } from '@vegaprotocol/environment'; import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit'; -import { useVegaWallet } from '@vegaprotocol/wallet'; import { Web3Container } from '@vegaprotocol/web3'; import { DepositManager } from './deposit-manager'; -import { getEnabledAssets, t } from '@vegaprotocol/react-helpers'; -import type { DepositAsset } from './__generated__/DepositAsset'; - -const DEPOSITS_QUERY = gql` - query DepositAsset { - assetsConnection { - edges { - node { - id - name - symbol - decimals - status - source { - ... on ERC20 { - contractAddress - } - } - } - } - } - } -`; +import { t, useDataProvider } from '@vegaprotocol/react-helpers'; +import { enabledAssetsProvider } from '@vegaprotocol/assets'; /** * Fetches data required for the Deposit page */ export const DepositContainer = ({ assetId }: { assetId?: string }) => { const { VEGA_ENV } = useEnvironment(); - const { pubKey } = useVegaWallet(); - - const { data, loading, error } = useQuery(DEPOSITS_QUERY, { - variables: { partyId: pubKey }, - skip: !pubKey, + const { data, loading, error } = useDataProvider({ + dataProvider: enabledAssetsProvider, }); - const assets = getEnabledAssets(data); - return ( - data={data} loading={loading} error={error}> - {assets.length ? ( + + {data && data.length ? ( diff --git a/libs/deposits/src/lib/deposit-form.tsx b/libs/deposits/src/lib/deposit-form.tsx index d5d6d1d91..54143ee32 100644 --- a/libs/deposits/src/lib/deposit-form.tsx +++ b/libs/deposits/src/lib/deposit-form.tsx @@ -1,4 +1,5 @@ -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; +import { isAssetTypeERC20 } from '@vegaprotocol/assets'; import { ethereumAddress, t, @@ -7,7 +8,6 @@ import { minSafe, maxSafe, addDecimal, - isAssetTypeERC20, } from '@vegaprotocol/react-helpers'; import { Button, diff --git a/libs/deposits/src/lib/deposit-manager.tsx b/libs/deposits/src/lib/deposit-manager.tsx index 2813c2ecb..c8ae442fc 100644 --- a/libs/deposits/src/lib/deposit-manager.tsx +++ b/libs/deposits/src/lib/deposit-manager.tsx @@ -6,7 +6,7 @@ import { useSubmitFaucet } from './use-submit-faucet'; import { useDepositStore } from './deposit-store'; import { useCallback, useEffect } from 'react'; import { useDepositBalances } from './use-deposit-balances'; -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; interface DepositManagerProps { assetId?: string; diff --git a/libs/deposits/src/lib/deposit-store.ts b/libs/deposits/src/lib/deposit-store.ts index 4adb4440a..b9e0d13f3 100644 --- a/libs/deposits/src/lib/deposit-store.ts +++ b/libs/deposits/src/lib/deposit-store.ts @@ -1,4 +1,4 @@ -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import BigNumber from 'bignumber.js'; import create from 'zustand'; diff --git a/libs/deposits/src/lib/deposits-table.tsx b/libs/deposits/src/lib/deposits-table.tsx index e04bb32a8..eddcf32ce 100644 --- a/libs/deposits/src/lib/deposits-table.tsx +++ b/libs/deposits/src/lib/deposits-table.tsx @@ -10,7 +10,7 @@ import type { VegaValueFormatterParams, } from '@vegaprotocol/ui-toolkit'; import { AgGridDynamic as AgGrid, Link } from '@vegaprotocol/ui-toolkit'; -import type { DepositFieldsFragment } from './__generated__/Deposit'; +import type { DepositFieldsFragment } from './__generated___/Deposit'; import { useEnvironment } from '@vegaprotocol/environment'; import { DepositStatusMapping } from '@vegaprotocol/types'; diff --git a/libs/deposits/src/lib/index.ts b/libs/deposits/src/lib/index.ts index c9f1840db..75cfcfb10 100644 --- a/libs/deposits/src/lib/index.ts +++ b/libs/deposits/src/lib/index.ts @@ -1,4 +1,4 @@ -export * from './__generated__'; +export * from './__generated___/Deposit'; export * from './deposit-container'; export * from './deposit-form'; export * from './deposit-limits'; diff --git a/libs/deposits/src/lib/use-deposit-balances.ts b/libs/deposits/src/lib/use-deposit-balances.ts index 3de32d65e..1864a8754 100644 --- a/libs/deposits/src/lib/use-deposit-balances.ts +++ b/libs/deposits/src/lib/use-deposit-balances.ts @@ -6,7 +6,7 @@ import { useGetAllowance } from './use-get-allowance'; import { useGetBalanceOfERC20Token } from './use-get-balance-of-erc20-token'; import { useGetDepositMaximum } from './use-get-deposit-maximum'; import { useGetDepositedAmount } from './use-get-deposited-amount'; -import { isAssetTypeERC20 } from '@vegaprotocol/react-helpers'; +import { isAssetTypeERC20 } from '@vegaprotocol/assets'; /** * Hook which fetches all the balances required for depositing diff --git a/libs/deposits/src/lib/use-deposits.ts b/libs/deposits/src/lib/use-deposits.ts index 3fdf138b8..348791b76 100644 --- a/libs/deposits/src/lib/use-deposits.ts +++ b/libs/deposits/src/lib/use-deposits.ts @@ -8,13 +8,13 @@ import { Schema } from '@vegaprotocol/types'; import { useDepositsQuery, DepositEventDocument, -} from './__generated__/Deposit'; +} from './__generated___/Deposit'; import type { DepositFieldsFragment, DepositsQuery, DepositEventSubscription, DepositEventSubscriptionVariables, -} from './__generated__/Deposit'; +} from './__generated___/Deposit'; export const useDeposits = () => { const { pubKey } = useVegaWallet(); diff --git a/libs/deposits/src/lib/use-get-allowance.ts b/libs/deposits/src/lib/use-get-allowance.ts index 42468e69e..5e2be32f5 100644 --- a/libs/deposits/src/lib/use-get-allowance.ts +++ b/libs/deposits/src/lib/use-get-allowance.ts @@ -4,7 +4,7 @@ import { useWeb3React } from '@web3-react/core'; import { useCallback } from 'react'; import { useEthereumConfig } from '@vegaprotocol/web3'; import BigNumber from 'bignumber.js'; -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import { addDecimal } from '@vegaprotocol/react-helpers'; export const useGetAllowance = ( diff --git a/libs/deposits/src/lib/use-get-balance-of-erc20-token.ts b/libs/deposits/src/lib/use-get-balance-of-erc20-token.ts index 7ffb0b311..3e87d40ea 100644 --- a/libs/deposits/src/lib/use-get-balance-of-erc20-token.ts +++ b/libs/deposits/src/lib/use-get-balance-of-erc20-token.ts @@ -3,7 +3,7 @@ import * as Sentry from '@sentry/react'; import { useWeb3React } from '@web3-react/core'; import { useCallback } from 'react'; import BigNumber from 'bignumber.js'; -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import { addDecimal } from '@vegaprotocol/react-helpers'; export const useGetBalanceOfERC20Token = ( diff --git a/libs/deposits/src/lib/use-get-deposit-maximum.ts b/libs/deposits/src/lib/use-get-deposit-maximum.ts index 267588d77..8c3182e9f 100644 --- a/libs/deposits/src/lib/use-get-deposit-maximum.ts +++ b/libs/deposits/src/lib/use-get-deposit-maximum.ts @@ -1,7 +1,7 @@ import { useCallback } from 'react'; import * as Sentry from '@sentry/react'; import BigNumber from 'bignumber.js'; -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import { addDecimal } from '@vegaprotocol/react-helpers'; import type { CollateralBridge } from '@vegaprotocol/smart-contracts'; diff --git a/libs/deposits/src/lib/use-get-deposited-amount.ts b/libs/deposits/src/lib/use-get-deposited-amount.ts index ad85f4050..a268e2b96 100644 --- a/libs/deposits/src/lib/use-get-deposited-amount.ts +++ b/libs/deposits/src/lib/use-get-deposited-amount.ts @@ -3,7 +3,7 @@ import * as Sentry from '@sentry/react'; import { ethers } from 'ethers'; import { useEthereumConfig } from '@vegaprotocol/web3'; import BigNumber from 'bignumber.js'; -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import { addDecimal } from '@vegaprotocol/react-helpers'; import { useWeb3React } from '@web3-react/core'; diff --git a/libs/deposits/src/lib/use-submit-approval.ts b/libs/deposits/src/lib/use-submit-approval.ts index 55255be38..c4b1c591d 100644 --- a/libs/deposits/src/lib/use-submit-approval.ts +++ b/libs/deposits/src/lib/use-submit-approval.ts @@ -1,4 +1,5 @@ -import { isAssetTypeERC20, removeDecimal } from '@vegaprotocol/react-helpers'; +import { removeDecimal } from '@vegaprotocol/react-helpers'; +import { isAssetTypeERC20 } from '@vegaprotocol/assets'; import * as Sentry from '@sentry/react'; import type { Token } from '@vegaprotocol/smart-contracts'; import { diff --git a/libs/deposits/src/lib/use-submit-deposit.tsx b/libs/deposits/src/lib/use-submit-deposit.tsx index d71ce9546..a9816bea8 100644 --- a/libs/deposits/src/lib/use-submit-deposit.tsx +++ b/libs/deposits/src/lib/use-submit-deposit.tsx @@ -3,15 +3,12 @@ import * as Sentry from '@sentry/react'; import type { DepositEventSubscription, DepositEventSubscriptionVariables, -} from './__generated__/Deposit'; -import { DepositEventDocument } from './__generated__/Deposit'; +} from './__generated___/Deposit'; +import { DepositEventDocument } from './__generated___/Deposit'; import { Schema } from '@vegaprotocol/types'; import { useState } from 'react'; -import { - isAssetTypeERC20, - remove0x, - removeDecimal, -} from '@vegaprotocol/react-helpers'; +import { remove0x, removeDecimal } from '@vegaprotocol/react-helpers'; +import { isAssetTypeERC20 } from '@vegaprotocol/assets'; import { useBridgeContract, useEthereumConfig, diff --git a/libs/deposits/src/lib/use-submit-faucet.ts b/libs/deposits/src/lib/use-submit-faucet.ts index 4bc28e7e8..4a9e67002 100644 --- a/libs/deposits/src/lib/use-submit-faucet.ts +++ b/libs/deposits/src/lib/use-submit-faucet.ts @@ -3,7 +3,7 @@ import * as Sentry from '@sentry/react'; import { useEthereumTransaction, useTokenContract } from '@vegaprotocol/web3'; import { useDepositStore } from './deposit-store'; import { useGetBalanceOfERC20Token } from './use-get-balance-of-erc20-token'; -import { isAssetTypeERC20 } from '@vegaprotocol/react-helpers'; +import { isAssetTypeERC20 } from '@vegaprotocol/assets'; export const useSubmitFaucet = () => { const { asset, update } = useDepositStore(); diff --git a/libs/market-depth/src/lib/market-depth-provider.ts b/libs/market-depth/src/lib/market-depth-provider.ts index ae6c04710..91f2a2e02 100644 --- a/libs/market-depth/src/lib/market-depth-provider.ts +++ b/libs/market-depth/src/lib/market-depth-provider.ts @@ -60,19 +60,10 @@ const update: Update< > = (data, deltas, reload) => { for (const delta of deltas) { if (delta.marketId !== data.id) { - //console.log('wrong-market'); continue; } const sequenceNumber = Number(delta.sequenceNumber); - console.log(delta.previousSequenceNumber, delta.sequenceNumber); if (sequenceNumber <= sequenceNumbers[delta.marketId]) { - /* - console.log( - 'smaller sequence number', - sequenceNumber, - sequenceNumbers[delta.marketId] - ); - */ return data; } /* @@ -82,8 +73,6 @@ const update: Update< return; } */ - // const { buy, sell } = delta; - // console.log({ buy, sell }); sequenceNumbers[delta.marketId] = sequenceNumber; const updatedData = { ...data, @@ -95,7 +84,6 @@ const update: Update< if (delta.sell) { updatedData.depth.sell = updateLevels(data.depth.sell ?? [], delta.sell); } - // console.log({ updatedData }); return updatedData; } return data; diff --git a/libs/market-depth/src/lib/orderbook.tsx b/libs/market-depth/src/lib/orderbook.tsx index e3d225dd3..f1cf58fc9 100644 --- a/libs/market-depth/src/lib/orderbook.tsx +++ b/libs/market-depth/src/lib/orderbook.tsx @@ -295,11 +295,10 @@ export const Orderbook = ({ return; } const { - contentRect: { width, height }, + contentRect: { width }, } = entries[0]; headerElement.current.style.width = `${width}px`; footerElement.current.style.width = `${width}px`; - setViewportHeight(height); }, [headerElement, footerElement] ); diff --git a/libs/market-info/src/components/market-info/info-market.tsx b/libs/market-info/src/components/market-info/info-market.tsx index a7434e516..a6a8ed24c 100644 --- a/libs/market-info/src/components/market-info/info-market.tsx +++ b/libs/market-info/src/components/market-info/info-market.tsx @@ -1,5 +1,5 @@ import { useMemo } from 'react'; -import { formatNumber, t } from '@vegaprotocol/react-helpers'; +import { formatNumber, t, useYesterday } from '@vegaprotocol/react-helpers'; import { AsyncRenderer, Splash, Accordion } from '@vegaprotocol/ui-toolkit'; import pick from 'lodash/pick'; import BigNumber from 'bignumber.js'; @@ -57,10 +57,10 @@ export const MarketInfoContainer = ({ marketId, onSelect, }: MarketInfoContainerProps) => { + const yesterday = useYesterday(); const yTimestamp = useMemo(() => { - const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600; - return new Date(yesterday * 1000).toISOString(); - }, []); + return new Date(yesterday).toISOString(); + }, [yesterday]); const variables = useMemo( () => ({ marketId, since: yTimestamp, interval: Interval.INTERVAL_I1H }), [marketId, yTimestamp] diff --git a/libs/market-list/src/lib/markets-provider.ts b/libs/market-list/src/lib/markets-provider.ts index 4cb8451d2..bce227f2f 100644 --- a/libs/market-list/src/lib/markets-provider.ts +++ b/libs/market-list/src/lib/markets-provider.ts @@ -2,6 +2,7 @@ import { makeDataProvider, makeDerivedDataProvider, useDataProvider, + useYesterday, } from '@vegaprotocol/react-helpers'; import type { MarketsQuery, @@ -90,13 +91,13 @@ export const marketListProvider = makeDerivedDataProvider< ); export const useMarketList = () => { + const yesterday = useYesterday(); const variables = useMemo(() => { - const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600; return { - since: new Date(yesterday * 1000).toISOString(), + since: new Date(yesterday).toISOString(), interval: Interval.INTERVAL_I1H, }; - }, []); + }, [yesterday]); const { data, loading, error } = useDataProvider({ dataProvider: marketListProvider, variables, diff --git a/libs/positions/src/index.ts b/libs/positions/src/index.ts index 6f30311d7..db59b5136 100644 --- a/libs/positions/src/index.ts +++ b/libs/positions/src/index.ts @@ -1,7 +1,4 @@ -export * from './lib/__generated__/Positions'; -export * from './lib/__generated__/Margins'; -export * from './lib/__generated__/PositionsSubscription'; -export * from './lib/__generated__/MarginsSubscription'; +export * from './lib/__generated___/Positions'; export * from './lib/positions-container'; export * from './lib/positions-data-providers'; export * from './lib/positions-table'; diff --git a/libs/positions/src/lib/Positions.graphql b/libs/positions/src/lib/Positions.graphql index fee859bd0..d13ade8e0 100644 --- a/libs/positions/src/lib/Positions.graphql +++ b/libs/positions/src/lib/Positions.graphql @@ -4,38 +4,8 @@ fragment PositionFields on Position { unrealisedPNL averageEntryPrice updatedAt - marginsConnection { - edges { - node { - market { - id - } - maintenanceLevel - searchLevel - initialLevel - collateralReleaseLevel - asset { - symbol - } - } - } - } market { id - decimalPlaces - positionDecimalPlaces - tradingMode - tradableInstrument { - instrument { - name - } - } - data { - markPrice - market { - id - } - } } } @@ -62,3 +32,42 @@ subscription PositionsSubscription($partyId: ID!) { marketId } } + +fragment MarginFields on MarginLevels { + maintenanceLevel + searchLevel + initialLevel + collateralReleaseLevel + asset { + id + } + market { + id + } +} + +query Margins($partyId: ID!) { + party(id: $partyId) { + id + marginsConnection { + edges { + node { + ...MarginFields + } + } + } + } +} + +subscription MarginsSubscription($partyId: ID!) { + margins(partyId: $partyId) { + marketId + asset + partyId + maintenanceLevel + searchLevel + initialLevel + collateralReleaseLevel + timestamp + } +} diff --git a/libs/positions/src/lib/__generated__/Margins.ts b/libs/positions/src/lib/__generated__/Margins.ts deleted file mode 100644 index a61171625..000000000 --- a/libs/positions/src/lib/__generated__/Margins.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// @generated -// This file was automatically generated and should not be edited. - -// ==================================================== -// GraphQL query operation: Margins -// ==================================================== - -export interface Margins_party_marginsConnection_edges_node_market { - __typename: "Market"; - /** - * Market ID - */ - id: string; -} - -export interface Margins_party_marginsConnection_edges_node_asset { - __typename: "Asset"; - /** - * The ID of the asset - */ - id: string; -} - -export interface Margins_party_marginsConnection_edges_node { - __typename: "MarginLevels"; - /** - * Market in which the margin is required for this party - */ - market: Margins_party_marginsConnection_edges_node_market; - /** - * Minimal margin for the position to be maintained in the network (unsigned integer) - */ - maintenanceLevel: string; - /** - * If the margin is between maintenance and search, the network will initiate a collateral search (unsigned integer) - */ - searchLevel: string; - /** - * This is the minimum margin required for a party to place a new order on the network (unsigned integer) - */ - initialLevel: string; - /** - * If the margin of the party is greater than this level, then collateral will be released from the margin account into - * the general account of the party for the given asset. - */ - collateralReleaseLevel: string; - /** - * Asset for the current margins - */ - asset: Margins_party_marginsConnection_edges_node_asset; -} - -export interface Margins_party_marginsConnection_edges { - __typename: "MarginEdge"; - node: Margins_party_marginsConnection_edges_node; -} - -export interface Margins_party_marginsConnection { - __typename: "MarginConnection"; - /** - * The margin levels in this connection - */ - edges: Margins_party_marginsConnection_edges[] | null; -} - -export interface Margins_party { - __typename: "Party"; - /** - * Party identifier - */ - id: string; - /** - * Margin levels for a market - */ - marginsConnection: Margins_party_marginsConnection | null; -} - -export interface Margins { - /** - * An entity that is trading on the Vega network - */ - party: Margins_party | null; -} - -export interface MarginsVariables { - partyId: string; -} diff --git a/libs/positions/src/lib/__generated__/MarginsSubscription.ts b/libs/positions/src/lib/__generated__/MarginsSubscription.ts deleted file mode 100644 index 257ea5c6d..000000000 --- a/libs/positions/src/lib/__generated__/MarginsSubscription.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// @generated -// This file was automatically generated and should not be edited. - -// ==================================================== -// GraphQL subscription operation: MarginsSubscription -// ==================================================== - -export interface MarginsSubscription_margins { - __typename: "MarginLevelsUpdate"; - /** - * Market in which the margin is required for this party - */ - marketId: string; - /** - * Asset for the current margins - */ - asset: string; - /** - * The party for this margin - */ - partyId: string; - /** - * Minimal margin for the position to be maintained in the network (unsigned integer) - */ - maintenanceLevel: string; - /** - * If the margin is between maintenance and search, the network will initiate a collateral search (unsigned integer) - */ - searchLevel: string; - /** - * This is the minimum margin required for a party to place a new order on the network (unsigned integer) - */ - initialLevel: string; - /** - * If the margin of the party is greater than this level, then collateral will be released from the margin account into - * the general account of the party for the given asset. - */ - collateralReleaseLevel: string; - /** - * RFC3339Nano time from at which this margin level was relevant - */ - timestamp: string; -} - -export interface MarginsSubscription { - /** - * Subscribe to the margin changes - */ - margins: MarginsSubscription_margins; -} - -export interface MarginsSubscriptionVariables { - partyId: string; -} diff --git a/libs/positions/src/lib/__generated__/PositionFields.ts b/libs/positions/src/lib/__generated__/PositionFields.ts deleted file mode 100644 index 04c13baff..000000000 --- a/libs/positions/src/lib/__generated__/PositionFields.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// @generated -// This file was automatically generated and should not be edited. - -// ==================================================== -// GraphQL fragment: PositionFields -// ==================================================== - -export interface PositionFields_market { - __typename: "Market"; - /** - * Market ID - */ - id: string; -} - -export interface PositionFields { - __typename: "Position"; - /** - * Realised Profit and Loss (int64) - */ - realisedPNL: string; - /** - * Open volume (uint64) - */ - openVolume: string; - /** - * Unrealised Profit and Loss (int64) - */ - unrealisedPNL: string; - /** - * Average entry price for this position - */ - averageEntryPrice: string; - /** - * RFC3339Nano time the position was updated - */ - updatedAt: string | null; - /** - * Market relating to this position - */ - market: PositionFields_market; -} diff --git a/libs/positions/src/lib/__generated__/Positions.ts b/libs/positions/src/lib/__generated__/Positions.ts deleted file mode 100644 index f3458262e..000000000 --- a/libs/positions/src/lib/__generated__/Positions.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// @generated -// This file was automatically generated and should not be edited. - -// ==================================================== -// GraphQL query operation: Positions -// ==================================================== - -export interface Positions_party_positionsConnection_edges_node_market { - __typename: "Market"; - /** - * Market ID - */ - id: string; -} - -export interface Positions_party_positionsConnection_edges_node { - __typename: "Position"; - /** - * Realised Profit and Loss (int64) - */ - realisedPNL: string; - /** - * Open volume (uint64) - */ - openVolume: string; - /** - * Unrealised Profit and Loss (int64) - */ - unrealisedPNL: string; - /** - * Average entry price for this position - */ - averageEntryPrice: string; - /** - * RFC3339Nano time the position was updated - */ - updatedAt: string | null; - /** - * Market relating to this position - */ - market: Positions_party_positionsConnection_edges_node_market; -} - -export interface Positions_party_positionsConnection_edges { - __typename: "PositionEdge"; - /** - * The position - */ - node: Positions_party_positionsConnection_edges_node; -} - -export interface Positions_party_positionsConnection { - __typename: "PositionConnection"; - /** - * The positions in this connection - */ - edges: Positions_party_positionsConnection_edges[] | null; -} - -export interface Positions_party { - __typename: "Party"; - /** - * Party identifier - */ - id: string; - /** - * Trading positions relating to a party - */ - positionsConnection: Positions_party_positionsConnection | null; -} - -export interface Positions { - /** - * An entity that is trading on the Vega network - */ - party: Positions_party | null; -} - -export interface PositionsVariables { - partyId: string; -} diff --git a/libs/positions/src/lib/__generated__/PositionsSubscription.ts b/libs/positions/src/lib/__generated__/PositionsSubscription.ts deleted file mode 100644 index 3a8800c19..000000000 --- a/libs/positions/src/lib/__generated__/PositionsSubscription.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// @generated -// This file was automatically generated and should not be edited. - -// ==================================================== -// GraphQL subscription operation: PositionsSubscription -// ==================================================== - -export interface PositionsSubscription_positions { - __typename: "PositionUpdate"; - /** - * Realised Profit and Loss (int64) - */ - realisedPNL: string; - /** - * Open volume (uint64) - */ - openVolume: string; - /** - * Unrealised Profit and Loss (int64) - */ - unrealisedPNL: string; - /** - * Average entry price for this position - */ - averageEntryPrice: string; - /** - * RFC3339Nano time the position was updated - */ - updatedAt: string | null; - /** - * Market relating to this position - */ - marketId: string; -} - -export interface PositionsSubscription { - /** - * Subscribe to the positions updates - */ - positions: PositionsSubscription_positions[]; -} - -export interface PositionsSubscriptionVariables { - partyId: string; -} diff --git a/libs/positions/src/lib/__generated___/Positions.ts b/libs/positions/src/lib/__generated___/Positions.ts index c7143eee6..d4872de7e 100644 --- a/libs/positions/src/lib/__generated___/Positions.ts +++ b/libs/positions/src/lib/__generated___/Positions.ts @@ -3,14 +3,14 @@ import { Schema as Types } from '@vegaprotocol/types'; import { gql } from '@apollo/client'; import * as Apollo from '@apollo/client'; const defaultOptions = {} as const; -export type PositionFieldsFragment = { __typename?: 'Position', realisedPNL: string, openVolume: string, unrealisedPNL: string, averageEntryPrice: string, updatedAt?: string | null, marginsConnection?: { __typename?: 'MarginConnection', edges?: Array<{ __typename?: 'MarginEdge', node: { __typename?: 'MarginLevels', maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, market: { __typename?: 'Market', id: string }, asset: { __typename?: 'Asset', symbol: string } } }> | null } | null, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, tradingMode: Types.MarketTradingMode, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } }, data?: { __typename?: 'MarketData', markPrice: string, market: { __typename?: 'Market', id: string } } | null } }; +export type PositionFieldsFragment = { __typename?: 'Position', realisedPNL: string, openVolume: string, unrealisedPNL: string, averageEntryPrice: string, updatedAt?: string | null, market: { __typename?: 'Market', id: string } }; export type PositionsQueryVariables = Types.Exact<{ partyId: Types.Scalars['ID']; }>; -export type PositionsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, positionsConnection?: { __typename?: 'PositionConnection', edges?: Array<{ __typename?: 'PositionEdge', node: { __typename?: 'Position', realisedPNL: string, openVolume: string, unrealisedPNL: string, averageEntryPrice: string, updatedAt?: string | null, marginsConnection?: { __typename?: 'MarginConnection', edges?: Array<{ __typename?: 'MarginEdge', node: { __typename?: 'MarginLevels', maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, market: { __typename?: 'Market', id: string }, asset: { __typename?: 'Asset', symbol: string } } }> | null } | null, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, tradingMode: Types.MarketTradingMode, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } }, data?: { __typename?: 'MarketData', markPrice: string, market: { __typename?: 'Market', id: string } } | null } } }> | null } | null } | null }; +export type PositionsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, positionsConnection?: { __typename?: 'PositionConnection', edges?: Array<{ __typename?: 'PositionEdge', node: { __typename?: 'Position', realisedPNL: string, openVolume: string, unrealisedPNL: string, averageEntryPrice: string, updatedAt?: string | null, market: { __typename?: 'Market', id: string } } }> | null } | null } | null }; export type PositionsSubscriptionSubscriptionVariables = Types.Exact<{ partyId: Types.Scalars['ID']; @@ -19,6 +19,22 @@ export type PositionsSubscriptionSubscriptionVariables = Types.Exact<{ export type PositionsSubscriptionSubscription = { __typename?: 'Subscription', positions: Array<{ __typename?: 'PositionUpdate', realisedPNL: string, openVolume: string, unrealisedPNL: string, averageEntryPrice: string, updatedAt?: string | null, marketId: string }> }; +export type MarginFieldsFragment = { __typename?: 'MarginLevels', maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, asset: { __typename?: 'Asset', id: string }, market: { __typename?: 'Market', id: string } }; + +export type MarginsQueryVariables = Types.Exact<{ + partyId: Types.Scalars['ID']; +}>; + + +export type MarginsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, marginsConnection?: { __typename?: 'MarginConnection', edges?: Array<{ __typename?: 'MarginEdge', node: { __typename?: 'MarginLevels', maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, asset: { __typename?: 'Asset', id: string }, market: { __typename?: 'Market', id: string } } }> | null } | null } | null }; + +export type MarginsSubscriptionSubscriptionVariables = Types.Exact<{ + partyId: Types.Scalars['ID']; +}>; + + +export type MarginsSubscriptionSubscription = { __typename?: 'Subscription', margins: { __typename?: 'MarginLevelsUpdate', marketId: string, asset: string, partyId: string, maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, timestamp: string } }; + export const PositionFieldsFragmentDoc = gql` fragment PositionFields on Position { realisedPNL @@ -26,38 +42,22 @@ export const PositionFieldsFragmentDoc = gql` unrealisedPNL averageEntryPrice updatedAt - marginsConnection { - edges { - node { - market { - id - } - maintenanceLevel - searchLevel - initialLevel - collateralReleaseLevel - asset { - symbol - } - } - } + market { + id + } +} + `; +export const MarginFieldsFragmentDoc = gql` + fragment MarginFields on MarginLevels { + maintenanceLevel + searchLevel + initialLevel + collateralReleaseLevel + asset { + id } market { id - decimalPlaces - positionDecimalPlaces - tradingMode - tradableInstrument { - instrument { - name - } - } - data { - markPrice - market { - id - } - } } } `; @@ -137,4 +137,83 @@ export function usePositionsSubscriptionSubscription(baseOptions: Apollo.Subscri return Apollo.useSubscription(PositionsSubscriptionDocument, options); } export type PositionsSubscriptionSubscriptionHookResult = ReturnType; -export type PositionsSubscriptionSubscriptionResult = Apollo.SubscriptionResult; \ No newline at end of file +export type PositionsSubscriptionSubscriptionResult = Apollo.SubscriptionResult; +export const MarginsDocument = gql` + query Margins($partyId: ID!) { + party(id: $partyId) { + id + marginsConnection { + edges { + node { + ...MarginFields + } + } + } + } +} + ${MarginFieldsFragmentDoc}`; + +/** + * __useMarginsQuery__ + * + * To run a query within a React component, call `useMarginsQuery` and pass it any options that fit your needs. + * When your component renders, `useMarginsQuery` 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 } = useMarginsQuery({ + * variables: { + * partyId: // value for 'partyId' + * }, + * }); + */ +export function useMarginsQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(MarginsDocument, options); + } +export function useMarginsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(MarginsDocument, options); + } +export type MarginsQueryHookResult = ReturnType; +export type MarginsLazyQueryHookResult = ReturnType; +export type MarginsQueryResult = Apollo.QueryResult; +export const MarginsSubscriptionDocument = gql` + subscription MarginsSubscription($partyId: ID!) { + margins(partyId: $partyId) { + marketId + asset + partyId + maintenanceLevel + searchLevel + initialLevel + collateralReleaseLevel + timestamp + } +} + `; + +/** + * __useMarginsSubscriptionSubscription__ + * + * To run a query within a React component, call `useMarginsSubscriptionSubscription` and pass it any options that fit your needs. + * When your component renders, `useMarginsSubscriptionSubscription` 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 subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useMarginsSubscriptionSubscription({ + * variables: { + * partyId: // value for 'partyId' + * }, + * }); + */ +export function useMarginsSubscriptionSubscription(baseOptions: Apollo.SubscriptionHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useSubscription(MarginsSubscriptionDocument, options); + } +export type MarginsSubscriptionSubscriptionHookResult = ReturnType; +export type MarginsSubscriptionSubscriptionResult = Apollo.SubscriptionResult; \ No newline at end of file diff --git a/libs/positions/src/lib/margin-data-provider.ts b/libs/positions/src/lib/margin-data-provider.ts index 76e21a83a..ae158485d 100644 --- a/libs/positions/src/lib/margin-data-provider.ts +++ b/libs/positions/src/lib/margin-data-provider.ts @@ -1,55 +1,21 @@ -import { gql } from '@apollo/client'; import produce from 'immer'; import { makeDataProvider } from '@vegaprotocol/react-helpers'; +import { + MarginsSubscriptionDocument, + MarginsDocument, +} from './__generated___/Positions'; import type { - MarginsSubscription, - MarginsSubscription_margins, -} from './__generated__/MarginsSubscription'; -import type { Margins, Margins_party } from './__generated__/Margins'; + MarginsQuery, + MarginsSubscriptionSubscription, +} from './__generated___/Positions'; -export const MARGINS_QUERY = gql` - query Margins($partyId: ID!) { - party(id: $partyId) { - id - marginsConnection { - edges { - node { - market { - id - } - maintenanceLevel - searchLevel - initialLevel - collateralReleaseLevel - asset { - id - } - } - } - } - } - } -`; - -export const MARGINS_SUBSCRIPTION = gql` - subscription MarginsSubscription($partyId: ID!) { - margins(partyId: $partyId) { - marketId - asset - partyId - maintenanceLevel - searchLevel - initialLevel - collateralReleaseLevel - timestamp - } - } -`; - -const update = (data: Margins_party, delta: MarginsSubscription_margins) => { +const update = ( + data: MarginsQuery['party'], + delta: MarginsSubscriptionSubscription['margins'] +) => { return produce(data, (draft) => { const { marketId } = delta; - if (marketId && draft.marginsConnection?.edges) { + if (marketId && draft?.marginsConnection?.edges) { const index = draft.marginsConnection.edges.findIndex( (edge) => edge.node.market.id === marketId ); @@ -86,18 +52,18 @@ const update = (data: Margins_party, delta: MarginsSubscription_margins) => { }); }; -const getData = (responseData: Margins) => responseData.party; -const getDelta = (subscriptionData: MarginsSubscription) => +const getData = (responseData: MarginsQuery) => responseData.party; +const getDelta = (subscriptionData: MarginsSubscriptionSubscription) => subscriptionData.margins; export const marginsDataProvider = makeDataProvider< - Margins, - Margins_party, - MarginsSubscription, - MarginsSubscription_margins + MarginsQuery, + MarginsQuery['party'], + MarginsSubscriptionSubscription, + MarginsSubscriptionSubscription['margins'] >({ - query: MARGINS_QUERY, - subscriptionQuery: MARGINS_SUBSCRIPTION, + query: MarginsDocument, + subscriptionQuery: MarginsSubscriptionDocument, update, getData, getDelta, diff --git a/libs/positions/src/lib/positions-data-providers.spec.ts b/libs/positions/src/lib/positions-data-providers.spec.ts index e9cd281bc..8981ac92c 100644 --- a/libs/positions/src/lib/positions-data-providers.spec.ts +++ b/libs/positions/src/lib/positions-data-providers.spec.ts @@ -1,9 +1,8 @@ import { AccountType, MarketTradingMode } from '@vegaprotocol/types'; import type { Account } from '@vegaprotocol/accounts'; -import type { Positions } from './__generated__/Positions'; -import { getMetrics, rejoinPositionData } from './positions-data-providers'; import type { MarketWithData } from '@vegaprotocol/market-list'; -import type { Margins } from './__generated__/Margins'; +import type { PositionsQuery, MarginsQuery } from './__generated___/Positions'; +import { getMetrics, rejoinPositionData } from './positions-data-providers'; const accounts = [ { @@ -64,7 +63,7 @@ const accounts = [ }, ] as Account[]; -const positions: Positions = { +const positions: PositionsQuery = { party: { __typename: 'Party', id: '02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65', @@ -163,7 +162,7 @@ const marketsData = [ }, ] as MarketWithData[]; -const margins: Margins = { +const margins: MarginsQuery = { party: { id: '02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65', marginsConnection: { diff --git a/libs/positions/src/lib/positions-data-providers.ts b/libs/positions/src/lib/positions-data-providers.ts index dc3fd68b7..263032eab 100644 --- a/libs/positions/src/lib/positions-data-providers.ts +++ b/libs/positions/src/lib/positions-data-providers.ts @@ -1,37 +1,31 @@ -import { gql } from '@apollo/client'; import produce from 'immer'; import BigNumber from 'bignumber.js'; import sortBy from 'lodash/sortBy'; import type { Account } from '@vegaprotocol/accounts'; import { accountsDataProvider } from '@vegaprotocol/accounts'; import { toBigNum } from '@vegaprotocol/react-helpers'; -import type { - Positions, - Positions_party, - Positions_party_positionsConnection_edges, -} from './__generated__/Positions'; import { makeDataProvider, makeDerivedDataProvider, } from '@vegaprotocol/react-helpers'; - -import type { - PositionsSubscription, - PositionsSubscription_positions, -} from './__generated__/PositionsSubscription'; - import { AccountType } from '@vegaprotocol/types'; import type { MarketTradingMode } from '@vegaprotocol/types'; import type { MarketWithData } from '@vegaprotocol/market-list'; import { marketsWithDataProvider } from '@vegaprotocol/market-list'; -import { marginsDataProvider } from './margin-data-provider'; import type { - Margins_party, - Margins_party_marginsConnection_edges_node, -} from './__generated__/Margins'; + PositionsQuery, + PositionsSubscriptionSubscription, + MarginsQuery, + MarginFieldsFragment, +} from './__generated___/Positions'; +import { + PositionsDocument, + PositionsSubscriptionDocument, +} from './__generated___/Positions'; +import { marginsDataProvider } from './margin-data-provider'; type PositionMarginLevel = Pick< - Margins_party_marginsConnection_edges_node, + MarginFieldsFragment, 'maintenanceLevel' | 'searchLevel' | 'initialLevel' >; @@ -40,7 +34,7 @@ interface PositionRejoined { openVolume: string; unrealisedPNL: string; averageEntryPrice: string; - updatedAt: string | null; + updatedAt?: string | null; market: MarketWithData | null; margins: PositionMarginLevel | null; } @@ -69,52 +63,10 @@ export interface Position { } export interface Data { - party: Positions_party | null; + party: PositionsQuery['party'] | null; positions: Position[] | null; } -const POSITION_FIELDS = gql` - fragment PositionFields on Position { - realisedPNL - openVolume - unrealisedPNL - averageEntryPrice - updatedAt - market { - id - } - } -`; - -export const POSITIONS_QUERY = gql` - ${POSITION_FIELDS} - query Positions($partyId: ID!) { - party(id: $partyId) { - id - positionsConnection { - edges { - node { - ...PositionFields - } - } - } - } - } -`; - -export const POSITIONS_SUBSCRIPTION = gql` - subscription PositionsSubscription($partyId: ID!) { - positions(partyId: $partyId) { - realisedPNL - openVolume - unrealisedPNL - averageEntryPrice - updatedAt - marketId - } - } -`; - export const getMetrics = ( data: PositionRejoined[] | null, accounts: Account[] | null @@ -221,19 +173,19 @@ export const getMetrics = ( searchPrice: searchPrice .multipliedBy(10 ** marketDecimalPlaces) .toFixed(0), - updatedAt: position.updatedAt, + updatedAt: position.updatedAt || null, }); }); return metrics; }; export const update = ( - data: Positions_party, - deltas: PositionsSubscription_positions[] + data: PositionsQuery['party'], + deltas: PositionsSubscriptionSubscription['positions'] ) => { return produce(data, (draft) => { deltas.forEach((delta) => { - if (!draft.positionsConnection?.edges || !delta) { + if (!draft?.positionsConnection?.edges || !delta) { return; } const index = draft.positionsConnection.edges.findIndex( @@ -267,22 +219,22 @@ export const update = ( }; export const positionsDataProvider = makeDataProvider< - Positions, - Positions_party, - PositionsSubscription, - PositionsSubscription_positions[] + PositionsQuery, + PositionsQuery['party'], + PositionsSubscriptionSubscription, + PositionsSubscriptionSubscription['positions'] >({ - query: POSITIONS_QUERY, - subscriptionQuery: POSITIONS_SUBSCRIPTION, + query: PositionsDocument, + subscriptionQuery: PositionsSubscriptionDocument, update, - getData: (responseData: Positions) => responseData.party, - getDelta: (subscriptionData: PositionsSubscription) => + getData: (responseData: PositionsQuery) => responseData.party, + getDelta: (subscriptionData: PositionsSubscriptionSubscription) => subscriptionData.positions, }); const upgradeMarginsConection = ( marketId: string, - margins: Margins_party | null + margins: MarginsQuery['party'] | null ) => { if (marketId && margins?.marginsConnection?.edges) { const index = @@ -302,26 +254,23 @@ const upgradeMarginsConection = ( }; export const rejoinPositionData = ( - positions: Positions_party | null, + positions: PositionsQuery['party'] | null, marketsData: MarketWithData[] | null, - margins: Margins_party | null + margins: MarginsQuery['party'] | null ): PositionRejoined[] | null => { if (positions?.positionsConnection?.edges && marketsData && margins) { - return positions.positionsConnection.edges.map( - (nodes: Positions_party_positionsConnection_edges) => { - return { - realisedPNL: nodes.node.realisedPNL, - openVolume: nodes.node.openVolume, - unrealisedPNL: nodes.node.unrealisedPNL, - averageEntryPrice: nodes.node.averageEntryPrice, - updatedAt: nodes.node.updatedAt, - market: - marketsData?.find((market) => market.id === nodes.node.market.id) || - null, - margins: upgradeMarginsConection(nodes.node.market.id, margins), - }; - } - ); + return positions.positionsConnection.edges.map(({ node }) => { + return { + realisedPNL: node.realisedPNL, + openVolume: node.openVolume, + unrealisedPNL: node.unrealisedPNL, + averageEntryPrice: node.averageEntryPrice, + updatedAt: node.updatedAt, + market: + marketsData?.find((market) => market.id === node.market.id) || null, + margins: upgradeMarginsConection(node.market.id, margins), + }; + }); } return null; }; diff --git a/libs/react-helpers/src/hooks/index.ts b/libs/react-helpers/src/hooks/index.ts index cba4598ae..a18ccef85 100644 --- a/libs/react-helpers/src/hooks/index.ts +++ b/libs/react-helpers/src/hooks/index.ts @@ -1,11 +1,12 @@ +export * from './__generated__/NetworkParam'; export * from './use-apply-grid-transaction'; export * from './use-data-provider'; export * from './use-fetch'; +export * from './use-mutation-observer'; export * from './use-network-params'; export * from './use-outside-click'; +export * from './use-resize-observer'; export * from './use-resize'; export * from './use-screen-dimensions'; export * from './use-theme-switcher'; -export * from './use-mutation-observer'; -export * from './use-resize-observer'; -export * from './__generated__/NetworkParam'; +export * from './use-yesterday'; diff --git a/libs/react-helpers/src/hooks/use-network-params.ts b/libs/react-helpers/src/hooks/use-network-params.ts index 5bc3f59d4..a4c2e14d0 100644 --- a/libs/react-helpers/src/hooks/use-network-params.ts +++ b/libs/react-helpers/src/hooks/use-network-params.ts @@ -43,6 +43,14 @@ export const NetworkParams = { governance_proposal_asset_maxClose: 'governance_proposal_asset_maxClose', governance_proposal_asset_minEnact: 'governance_proposal_asset_minEnact', governance_proposal_asset_maxEnact: 'governance_proposal_asset_maxEnact', + governance_proposal_updateAsset_minClose: + 'governance_proposal_updateAsset_minClose', + governance_proposal_updateAsset_maxClose: + 'governance_proposal_updateAsset_maxClose', + governance_proposal_updateAsset_minEnact: + 'governance_proposal_updateAsset_minEnact', + governance_proposal_updateAsset_maxEnact: + 'governance_proposal_updateAsset_maxEnact', governance_proposal_updateNetParam_minClose: 'governance_proposal_updateNetParam_minClose', governance_proposal_updateNetParam_maxClose: @@ -71,6 +79,8 @@ export const NetworkParams = { 'governance_proposal_asset_requiredParticipation', governance_proposal_asset_minProposerBalance: 'governance_proposal_asset_minProposerBalance', + governance_proposal_updateAsset_minProposerBalance: + 'governance_proposal_updateAsset_minProposerBalance', governance_proposal_updateNetParam_requiredMajority: 'governance_proposal_updateNetParam_requiredMajority', governance_proposal_updateNetParam_requiredParticipation: diff --git a/libs/react-helpers/src/hooks/use-yesterday.spec.ts b/libs/react-helpers/src/hooks/use-yesterday.spec.ts new file mode 100644 index 000000000..98348fa66 --- /dev/null +++ b/libs/react-helpers/src/hooks/use-yesterday.spec.ts @@ -0,0 +1,57 @@ +import { act } from 'react-dom/test-utils'; +import { now, useYesterday } from './use-yesterday'; +import { renderHook } from '@testing-library/react'; + +describe('now', () => { + beforeAll(() => { + jest.useFakeTimers().setSystemTime(new Date('1970-01-05T14:36:20.100Z')); + }); + afterAll(() => { + jest.useRealTimers(); + }); + it.each([ + { o: '1970-01-05T14:36:20.000Z', roundBy: 1 }, // by 1ms + { o: '1970-01-05T14:36:00.000Z', roundBy: 60 * 1000 }, // by 1m + { o: '1970-01-05T14:35:00.000Z', roundBy: 5 * 60 * 1000 }, // by 5m + { o: '1970-01-05T14:30:00.000Z', roundBy: 10 * 60 * 1000 }, // by 10m + { o: '1970-01-05T14:20:00.000Z', roundBy: 20 * 60 * 1000 }, // by 20m + { o: '1970-01-05T14:00:00.000Z', roundBy: 60 * 60 * 1000 }, // by 1h + { o: '1970-01-05T00:00:00.000Z', roundBy: 24 * 60 * 60 * 1000 }, // by 1d + ])( + 'returns the now timestamp rounded by given number (ms)', + ({ roundBy, o }) => { + expect(now(roundBy)).toEqual(new Date(o).getTime()); + } + ); +}); + +describe('useYesterday', () => { + beforeAll(() => { + jest.useFakeTimers().setSystemTime(new Date('1970-01-05T14:36:20.100Z')); + }); + afterAll(() => { + jest.useRealTimers(); + }); + it('returns yesterday timestamp rounded by 5 minutes', () => { + const { result, rerender } = renderHook(() => useYesterday()); + expect(result.current).toEqual( + new Date('1970-01-04T14:35:00.000Z').getTime() + ); + rerender(); + rerender(); + rerender(); + expect(result.current).toEqual( + new Date('1970-01-04T14:35:00.000Z').getTime() + ); + }); + it('updates yesterday timestamp after 5 minutes', () => { + const { result, rerender } = renderHook(() => useYesterday()); + act(() => { + jest.advanceTimersByTime(5 * 60 * 1000); + rerender(); + }); + expect(result.current).toEqual( + new Date('1970-01-04T14:40:00.000Z').getTime() + ); + }); +}); diff --git a/libs/react-helpers/src/hooks/use-yesterday.ts b/libs/react-helpers/src/hooks/use-yesterday.ts new file mode 100644 index 000000000..195e11e25 --- /dev/null +++ b/libs/react-helpers/src/hooks/use-yesterday.ts @@ -0,0 +1,22 @@ +import { useEffect, useRef } from 'react'; + +const DEFAULT_ROUND_BY_MS = 5 * 60 * 1000; +const TWENTY_FOUR_HOURS_MS = 24 * 60 * 60 * 1000; + +export const now = (roundBy = 1) => + Math.floor((Math.round(new Date().getTime() / 1000) * 1000) / roundBy) * + roundBy; + +/** + * Returns the yesterday's timestamp rounded by given number (in milliseconds; 5 minutes by default) + */ +export const useYesterday = (roundBy = DEFAULT_ROUND_BY_MS) => { + const yesterday = useRef(now(roundBy) - TWENTY_FOUR_HOURS_MS); + useEffect(() => { + const i = setInterval(() => { + yesterday.current = now(roundBy) - TWENTY_FOUR_HOURS_MS; + }, roundBy); + return () => clearInterval(i); + }, [roundBy]); + return yesterday.current; +}; diff --git a/libs/react-helpers/src/index.ts b/libs/react-helpers/src/index.ts index 3e5b1ddec..5464d1c13 100644 --- a/libs/react-helpers/src/index.ts +++ b/libs/react-helpers/src/index.ts @@ -1,5 +1,4 @@ export * from './hooks'; -export * from './lib/assets'; export * from './lib/context'; export * from './lib/format'; export * from './lib/generic-data-provider'; diff --git a/libs/react-helpers/src/lib/assets.ts b/libs/react-helpers/src/lib/assets.ts deleted file mode 100644 index 7c00c0b00..000000000 --- a/libs/react-helpers/src/lib/assets.ts +++ /dev/null @@ -1,65 +0,0 @@ -export interface ERC20AssetSource { - __typename: 'ERC20'; - contractAddress: string; -} - -export interface BuiltinAssetSource { - __typename: 'BuiltinAsset'; -} - -export interface Asset { - __typename: 'Asset'; - id: string; - symbol: string; - name: string; - decimals: number; - source: ERC20AssetSource | BuiltinAssetSource; -} - -export enum AssetStatus { - STATUS_ENABLED = 'STATUS_ENABLED', - STATUS_PENDING_LISTING = 'STATUS_PENDING_LISTING', - STATUS_PROPOSED = 'STATUS_PROPOSED', - STATUS_REJECTED = 'STATUS_REJECTED', -} - -export interface AssetWithStatus extends Asset { - status: AssetStatus; -} - -export type ERC20Asset = Omit & { - source: ERC20AssetSource; -}; - -export type BuiltinAsset = Omit & { - source: BuiltinAssetSource; -}; - -export const isAssetTypeERC20 = (asset?: Asset): asset is ERC20Asset => { - if (!asset?.source) return false; - return asset.source.__typename === 'ERC20'; -}; - -type AssetEdge = { - __typename: 'AssetEdge'; - node: T; -}; - -type AssetEdges = { edges: (AssetEdge | null)[] | null }; - -type AssetsConnection = { - assetsConnection: AssetEdges | null; -}; - -export const getAssets = (data?: AssetsConnection): Asset[] => - data?.assetsConnection?.edges - ?.filter((e) => e && e?.node) - .map((e) => (e as AssetEdge).node as Asset) || []; - -export const getEnabledAssets = ( - data?: AssetsConnection -): Asset[] => - data?.assetsConnection?.edges - ?.filter((e) => e && e?.node) - .map((e) => (e as AssetEdge).node) - .filter((a) => a.status === AssetStatus.STATUS_ENABLED) || []; diff --git a/libs/react-helpers/src/lib/validate/index.ts b/libs/react-helpers/src/lib/validate/index.ts index cae0791c4..acbdeb957 100644 --- a/libs/react-helpers/src/lib/validate/index.ts +++ b/libs/react-helpers/src/lib/validate/index.ts @@ -45,3 +45,12 @@ export const suitableForSyntaxHighlighter = (str: string) => { return false; } }; + +export const validateJson = (value: string) => { + try { + JSON.parse(value); + return true; + } catch (e) { + return t('Must be valid JSON'); + } +}; diff --git a/libs/types/.env b/libs/types/.env index d7698de3b..0c3680567 100644 --- a/libs/types/.env +++ b/libs/types/.env @@ -1 +1 @@ -GRAPHQL_SCHEMA_PATH=https://api.n11.testnet.vega.xyz/graphql +GRAPHQL_SCHEMA_PATH=https://api.n07.testnet.vega.xyz/graphql diff --git a/libs/ui-toolkit/src/components/ag-grid/index.tsx b/libs/ui-toolkit/src/components/ag-grid/index.tsx index 19da00e74..9db7ee4d9 100644 --- a/libs/ui-toolkit/src/components/ag-grid/index.tsx +++ b/libs/ui-toolkit/src/components/ag-grid/index.tsx @@ -4,6 +4,9 @@ import type { ValueFormatterParams, } from 'ag-grid-community'; +import type { IDatasource, IGetRowsParams } from 'ag-grid-community'; +import type { AgGridReactProps } from 'ag-grid-react'; + export * from './ag-grid-lazy'; export * from './ag-grid-dynamic'; @@ -27,3 +30,16 @@ export type VegaICellRendererParams< TRow, TField extends Field = string > = RowHelper; + +export interface GetRowsParams extends IGetRowsParams { + successCallback(rowsThisBlock: T[], lastRow?: number): void; +} + +export interface Datasource extends IDatasource { + getRows(params: GetRowsParams): void; +} + +export interface TypedDataAgGrid extends AgGridReactProps { + rowData?: T[] | null; + datasource?: Datasource; +} diff --git a/libs/wallet/src/connect-dialog/connect-dialog.spec.tsx b/libs/wallet/src/connect-dialog/connect-dialog.spec.tsx index dac9755f9..074c88082 100644 --- a/libs/wallet/src/connect-dialog/connect-dialog.spec.tsx +++ b/libs/wallet/src/connect-dialog/connect-dialog.spec.tsx @@ -184,11 +184,11 @@ describe('VegaConnectDialog', () => { const fillInForm = () => { const walletValue = 'test-wallet'; - fireEvent.change(screen.getByLabelText('Wallet'), { + fireEvent.change(screen.getByTestId('rest-wallet'), { target: { value: walletValue }, }); const passphraseValue = 'test-passphrase'; - fireEvent.change(screen.getByLabelText('Passphrase'), { + fireEvent.change(screen.getByTestId('rest-passphrase'), { target: { value: passphraseValue }, }); return { wallet: walletValue, passphrase: passphraseValue }; diff --git a/libs/wallet/src/connect-dialog/rest-connector-form.tsx b/libs/wallet/src/connect-dialog/rest-connector-form.tsx index d00106256..9be2acefa 100644 --- a/libs/wallet/src/connect-dialog/rest-connector-form.tsx +++ b/libs/wallet/src/connect-dialog/rest-connector-form.tsx @@ -55,10 +55,11 @@ export function RestConnectorForm({ return (
    - + {errors.wallet?.message && ( @@ -69,6 +70,7 @@ export function RestConnectorForm({ {errors.passphrase?.message && ( diff --git a/libs/wallet/src/connectors/rest-connector.ts b/libs/wallet/src/connectors/rest-connector.ts index ea76987fd..07bc14937 100644 --- a/libs/wallet/src/connectors/rest-connector.ts +++ b/libs/wallet/src/connectors/rest-connector.ts @@ -283,7 +283,7 @@ export class RestConnector implements VegaConnector { } } catch (err) { return { - error: 'Failed to fetch', + error: 'No wallet detected', }; } } diff --git a/libs/wallet/src/connectors/vega-connector.ts b/libs/wallet/src/connectors/vega-connector.ts index a83a7c495..d428cce9b 100644 --- a/libs/wallet/src/connectors/vega-connector.ts +++ b/libs/wallet/src/connectors/vega-connector.ts @@ -168,6 +168,21 @@ interface ProposalNewAssetTerms { validationTimestamp: number; } +interface ProposalUpdateAssetTerms { + updateAsset: { + assetId: string; + changes: { + quantum: string; + erc20: { + withdrawThreshold: string; + lifetimeLimit: string; + }; + }; + }; + closingTimestamp: number; + enactmentTimestamp: number; +} + interface OracleSpecBinding { settlementPriceProperty: string; tradingTerminationProperty: string; @@ -227,7 +242,8 @@ export interface ProposalSubmission { | ProposalNewMarketTerms | ProposalUpdateMarketTerms | ProposalNetworkParameterTerms - | ProposalNewAssetTerms; + | ProposalNewAssetTerms + | ProposalUpdateAssetTerms; } export interface ProposalSubmissionBody { diff --git a/libs/web3/src/lib/use-token-contract.ts b/libs/web3/src/lib/use-token-contract.ts index 1cefd7030..e4ab3bd8f 100644 --- a/libs/web3/src/lib/use-token-contract.ts +++ b/libs/web3/src/lib/use-token-contract.ts @@ -1,4 +1,4 @@ -import type { ERC20Asset } from '@vegaprotocol/react-helpers'; +import type { ERC20Asset } from '@vegaprotocol/assets'; import { Token, TokenFaucetable } from '@vegaprotocol/smart-contracts'; import { useWeb3React } from '@web3-react/core'; import { useMemo } from 'react'; diff --git a/libs/withdraws/src/index.ts b/libs/withdraws/src/index.ts index 75697296d..eb989a97b 100644 --- a/libs/withdraws/src/index.ts +++ b/libs/withdraws/src/index.ts @@ -3,6 +3,7 @@ export * from './lib/withdraw-form'; export * from './lib/withdraw-form-container'; export * from './lib/withdraw-manager'; export * from './lib/withdrawals-table'; +export * from './lib/pending-withdrawals-table'; export * from './lib/withdrawal-feedback'; export * from './lib/use-complete-withdraw'; export * from './lib/use-create-withdraw'; @@ -10,4 +11,3 @@ export * from './lib/use-verify-withdrawal'; export * from './lib/use-withdrawals'; export * from './lib/__generated__/Withdrawals'; export * from './lib/__generated__/WithdrawalFields'; -export * from './lib/__generated__/WithdrawFormQuery'; diff --git a/libs/withdraws/src/lib/__generated__/WithdrawFormQuery.ts b/libs/withdraws/src/lib/__generated__/WithdrawFormQuery.ts deleted file mode 100644 index bb0b90ecf..000000000 --- a/libs/withdraws/src/lib/__generated__/WithdrawFormQuery.ts +++ /dev/null @@ -1,139 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// @generated -// This file was automatically generated and should not be edited. - -import { AccountType, AssetStatus } from "@vegaprotocol/types"; - -// ==================================================== -// GraphQL query operation: WithdrawFormQuery -// ==================================================== - -export interface WithdrawFormQuery_party_withdrawals { - __typename: "Withdrawal"; - /** - * The Vega internal ID of the withdrawal - */ - id: string; - /** - * Hash of the transaction on the foreign chain - */ - txHash: string | null; -} - -export interface WithdrawFormQuery_party_accounts_asset { - __typename: "Asset"; - /** - * The ID of the asset - */ - id: string; - /** - * The symbol of the asset (e.g: GBP) - */ - symbol: string; -} - -export interface WithdrawFormQuery_party_accounts { - __typename: "Account"; - /** - * Account type (General, Margin, etc) - */ - type: AccountType; - /** - * Balance as string - current account balance (approx. as balances can be updated several times per second) - */ - balance: string; - /** - * Asset, the 'currency' - */ - asset: WithdrawFormQuery_party_accounts_asset; -} - -export interface WithdrawFormQuery_party { - __typename: "Party"; - /** - * Party identifier - */ - id: string; - /** - * The list of all withdrawals initiated by the party - */ - withdrawals: WithdrawFormQuery_party_withdrawals[] | null; - /** - * Collateral accounts relating to a party - */ - accounts: WithdrawFormQuery_party_accounts[] | null; -} - -export interface WithdrawFormQuery_assetsConnection_edges_node_source_BuiltinAsset { - __typename: "BuiltinAsset"; -} - -export interface WithdrawFormQuery_assetsConnection_edges_node_source_ERC20 { - __typename: "ERC20"; - /** - * The address of the ERC20 contract - */ - contractAddress: string; -} - -export type WithdrawFormQuery_assetsConnection_edges_node_source = WithdrawFormQuery_assetsConnection_edges_node_source_BuiltinAsset | WithdrawFormQuery_assetsConnection_edges_node_source_ERC20; - -export interface WithdrawFormQuery_assetsConnection_edges_node { - __typename: "Asset"; - /** - * The ID of the asset - */ - id: string; - /** - * The symbol of the asset (e.g: GBP) - */ - symbol: string; - /** - * The full name of the asset (e.g: Great British Pound) - */ - name: string; - /** - * The precision of the asset. Should match the decimal precision of the asset on its native chain, e.g: for ERC20 assets, it is often 18 - */ - decimals: number; - /** - * The status of the asset in the Vega network - */ - status: AssetStatus; - /** - * The origin source of the asset (e.g: an ERC20 asset) - */ - source: WithdrawFormQuery_assetsConnection_edges_node_source; -} - -export interface WithdrawFormQuery_assetsConnection_edges { - __typename: "AssetEdge"; - /** - * The asset information - */ - node: WithdrawFormQuery_assetsConnection_edges_node; -} - -export interface WithdrawFormQuery_assetsConnection { - __typename: "AssetsConnection"; - /** - * The assets - */ - edges: (WithdrawFormQuery_assetsConnection_edges | null)[] | null; -} - -export interface WithdrawFormQuery { - /** - * An entity that is trading on the Vega network - */ - party: WithdrawFormQuery_party | null; - /** - * The list of all assets in use in the Vega network or the specified asset if ID is provided - */ - assetsConnection: WithdrawFormQuery_assetsConnection | null; -} - -export interface WithdrawFormQueryVariables { - partyId: string; -} diff --git a/libs/withdraws/src/lib/pending-withdrawals-table.spec.tsx b/libs/withdraws/src/lib/pending-withdrawals-table.spec.tsx new file mode 100644 index 000000000..3c6f4ef41 --- /dev/null +++ b/libs/withdraws/src/lib/pending-withdrawals-table.spec.tsx @@ -0,0 +1,65 @@ +import { MockedProvider } from '@apollo/client/testing'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { generateWithdrawal } from './test-helpers'; +import { CompleteCell } from './pending-withdrawals-table'; +import { PendingWithdrawalsTable } from './pending-withdrawals-table'; +import { getTimeFormat } from '@vegaprotocol/react-helpers'; +import type { TypedDataAgGrid } from '@vegaprotocol/ui-toolkit'; +import type { WithdrawalFields } from './__generated__/WithdrawalFields'; + +jest.mock('@web3-react/core', () => ({ + useWeb3React: () => ({ provider: undefined }), +})); + +const generateTable = (props: TypedDataAgGrid) => ( + + + +); + +describe('PendingWithdrawalsTable', () => { + it('displays correct columns', async () => { + const withdrawal = generateWithdrawal(); + await act(async () => { + render(generateTable({ rowData: [withdrawal] })); + }); + const headers = screen.getAllByRole('columnheader'); + expect(headers).toHaveLength(5); + expect(headers.map((h) => h.textContent?.trim())).toEqual([ + 'Asset', + 'Amount', + 'Recipient', + 'Created', + '', + ]); + }); + it('displays given withdrawals', async () => { + const withdrawal = generateWithdrawal(); + await act(async () => { + render(generateTable({ rowData: [withdrawal] })); + }); + const cells = screen.getAllByRole('gridcell'); + const expectedValues = [ + 'asset-symbol', + '1.00', + '123456…123456', + getTimeFormat().format(new Date(withdrawal.createdTimestamp)), + 'Complete withdrawal', + ]; + cells.forEach((cell, i) => { + expect(cell).toHaveTextContent(expectedValues[i]); + }); + }); +}); + +describe('CompleteCell', () => { + const mockComplete = jest.fn(); + const data = generateWithdrawal(); + it('opens the dialog', () => { + render(); + fireEvent.click( + screen.getByText('Complete withdrawal', { selector: 'button' }) + ); + expect(mockComplete).toBeCalled(); + }); +}); diff --git a/libs/withdraws/src/lib/pending-withdrawals-table.tsx b/libs/withdraws/src/lib/pending-withdrawals-table.tsx new file mode 100644 index 000000000..b58163ca9 --- /dev/null +++ b/libs/withdraws/src/lib/pending-withdrawals-table.tsx @@ -0,0 +1,201 @@ +import { AgGridColumn } from 'ag-grid-react'; +import { + getDateTimeFormat, + t, + truncateByChars, + addDecimalsFormatNumber, +} from '@vegaprotocol/react-helpers'; +import type { + TypedDataAgGrid, + VegaICellRendererParams, + VegaValueFormatterParams, +} from '@vegaprotocol/ui-toolkit'; +import { Button } from '@vegaprotocol/ui-toolkit'; +import { + Dialog, + Link, + AgGridDynamic as AgGrid, + Intent, + Loader, + Icon, +} from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/environment'; +import { useCompleteWithdraw } from './use-complete-withdraw'; +import type { WithdrawalFields } from './__generated__/WithdrawalFields'; +import type { VerifyState } from './use-verify-withdrawal'; +import { ApprovalStatus, useVerifyWithdrawal } from './use-verify-withdrawal'; + +export const PendingWithdrawalsTable = ( + props: TypedDataAgGrid +) => { + const { ETHERSCAN_URL } = useEnvironment(); + const { + submit, + reset: resetTx, + Dialog: EthereumTransactionDialog, + } = useCompleteWithdraw(); + const { + verify, + state: verifyState, + reset: resetVerification, + } = useVerifyWithdrawal(); + + return ( + <> + + + ) => { + return addDecimalsFormatNumber(value, data.asset.decimals); + }} + /> + & { + ethUrl: string; + }) => ( + + {valueFormatted} + + )} + cellRendererParams={{ ethUrl: ETHERSCAN_URL }} + valueFormatter={({ + value, + }: VegaValueFormatterParams< + WithdrawalFields, + 'details.receiverAddress' + >) => { + if (!value) return '-'; + return truncateByChars(value); + }} + /> + ) => { + return getDateTimeFormat().format(new Date(value)); + }} + /> + { + const verified = await verify(withdrawal); + + if (!verified) { + return; + } + + submit(withdrawal.id); + }, + }} + cellRenderer="CompleteCell" + /> + + { + if (!isOpen) { + resetTx(); + resetVerification(); + } + }} + open={verifyState.dialogOpen} + size="small" + {...getVerifyDialogProps(verifyState.status)} + > + + + + + ); +}; + +export type CompleteCellProps = { + data: WithdrawalFields; + complete: (withdrawal: WithdrawalFields) => void; +}; +export const CompleteCell = ({ data, complete }: CompleteCellProps) => ( + +); + +const getVerifyDialogProps = (status: ApprovalStatus) => { + if (status === ApprovalStatus.Error) { + return { + intent: Intent.Danger, + icon: , + }; + } + + if (status === ApprovalStatus.Pending) { + return { intent: Intent.None, icon: }; + } + + if (status === ApprovalStatus.Delayed) { + return { intent: Intent.Warning, icon: }; + } + + return { intent: Intent.None }; +}; + +const VerificationStatus = ({ state }: { state: VerifyState }) => { + if (state.status === ApprovalStatus.Error) { + return

    {t('Something went wrong')}

    ; + } + + if (state.status === ApprovalStatus.Pending) { + return

    {t('Verifying...')}

    ; + } + + if (state.status === ApprovalStatus.Delayed && state.completeTimestamp) { + const formattedTime = getDateTimeFormat().format( + new Date(state.completeTimestamp) + ); + return ( + <> +

    + {t("The amount you're withdrawing has triggered a time delay")} +

    +

    {t(`Cannot be completed until ${formattedTime}`)}

    + + ); + } + + return null; +}; diff --git a/libs/withdraws/src/lib/test-helpers.ts b/libs/withdraws/src/lib/test-helpers.ts index 218d0a8ca..a5fc19964 100644 --- a/libs/withdraws/src/lib/test-helpers.ts +++ b/libs/withdraws/src/lib/test-helpers.ts @@ -1,4 +1,4 @@ -import type { Asset, AssetWithStatus } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import { AccountType, AssetStatus, @@ -6,15 +6,16 @@ import { } from '@vegaprotocol/types'; import merge from 'lodash/merge'; import type { PartialDeep } from 'type-fest'; -import type { Account } from './types'; +import type { AccountFieldsFragment } from '@vegaprotocol/accounts'; import type { Withdrawals_party_withdrawalsConnection_edges_node } from './__generated__/Withdrawals'; export const generateAsset = (override?: PartialDeep) => { - const defaultAsset: AssetWithStatus = { + const defaultAsset: Asset = { __typename: 'Asset', id: 'asset-id', symbol: 'asset-symbol', name: 'asset-name', + quantum: '', decimals: 5, status: AssetStatus.STATUS_ENABLED, source: { @@ -25,13 +26,14 @@ export const generateAsset = (override?: PartialDeep) => { return merge(defaultAsset, override); }; -export const generateAccount = (override?: PartialDeep) => { - const defaultAccount: Account = { +export const generateAccount = ( + override?: PartialDeep +) => { + const defaultAccount: AccountFieldsFragment = { type: AccountType.ACCOUNT_TYPE_GENERAL, balance: '100000', asset: { id: 'asset-id', - symbol: 'asset-symbol', }, }; return merge(defaultAccount, override); diff --git a/libs/withdraws/src/lib/types.ts b/libs/withdraws/src/lib/types.ts deleted file mode 100644 index 16b6cab16..000000000 --- a/libs/withdraws/src/lib/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { AccountType } from '@vegaprotocol/types'; - -export interface Account { - type: AccountType; - balance: string; - asset: { - id: string; - symbol: string; - }; -} diff --git a/libs/withdraws/src/lib/use-get-withdraw-threshold.tsx b/libs/withdraws/src/lib/use-get-withdraw-threshold.tsx index fff3a856d..3c9bf5748 100644 --- a/libs/withdraws/src/lib/use-get-withdraw-threshold.tsx +++ b/libs/withdraws/src/lib/use-get-withdraw-threshold.tsx @@ -1,7 +1,7 @@ import { useCallback } from 'react'; import { useBridgeContract } from '@vegaprotocol/web3'; import BigNumber from 'bignumber.js'; -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import { addDecimal } from '@vegaprotocol/react-helpers'; /** @@ -12,7 +12,7 @@ import { addDecimal } from '@vegaprotocol/react-helpers'; export const useGetWithdrawThreshold = () => { const contract = useBridgeContract(); const getThreshold = useCallback( - async (asset: Asset | undefined) => { + async (asset: Pick | undefined) => { if (!contract || asset?.source.__typename !== 'ERC20') { return new BigNumber(Infinity); } diff --git a/libs/withdraws/src/lib/use-withdraw-asset.tsx b/libs/withdraws/src/lib/use-withdraw-asset.tsx index f3e2e4763..7cf550c3f 100644 --- a/libs/withdraws/src/lib/use-withdraw-asset.tsx +++ b/libs/withdraws/src/lib/use-withdraw-asset.tsx @@ -1,17 +1,17 @@ import { captureException } from '@sentry/react'; -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import { addDecimal } from '@vegaprotocol/react-helpers'; import { AccountType } from '@vegaprotocol/types'; import BigNumber from 'bignumber.js'; import { useCallback, useEffect } from 'react'; -import type { Account } from './types'; +import type { AccountFieldsFragment } from '@vegaprotocol/accounts'; import { useGetWithdrawDelay } from './use-get-withdraw-delay'; import { useGetWithdrawThreshold } from './use-get-withdraw-threshold'; import { useWithdrawStore } from './withdraw-store'; export const useWithdrawAsset = ( assets: Asset[], - accounts: Account[], + accounts: AccountFieldsFragment[], assetId?: string ) => { const { asset, balance, min, threshold, delay, update } = useWithdrawStore(); diff --git a/libs/withdraws/src/lib/use-withdrawals.ts b/libs/withdraws/src/lib/use-withdrawals.ts index 18c6fbebf..98017daf4 100644 --- a/libs/withdraws/src/lib/use-withdrawals.ts +++ b/libs/withdraws/src/lib/use-withdrawals.ts @@ -111,11 +111,33 @@ export const useWithdrawals = () => { ); }, [data]); + /** + * withdrawals that have to be completed by a user. + */ + const pending = useMemo(() => { + return withdrawals.filter((w) => !w.txHash); + }, [withdrawals]); + + /** + * withdrawals that are completed or being completed + */ + const completed = useMemo(() => { + return withdrawals + .filter((w) => w.txHash) + .sort((a, b) => + (b.withdrawnTimestamp || b.createdTimestamp).localeCompare( + a.withdrawnTimestamp || a.createdTimestamp + ) + ); + }, [withdrawals]); + return { data, loading, error, withdrawals, + pending, + completed, }; }; diff --git a/libs/withdraws/src/lib/withdraw-form-container.tsx b/libs/withdraws/src/lib/withdraw-form-container.tsx index 043e92b09..1838f853f 100644 --- a/libs/withdraws/src/lib/withdraw-form-container.tsx +++ b/libs/withdraws/src/lib/withdraw-form-container.tsx @@ -1,52 +1,10 @@ -import { gql, useQuery } from '@apollo/client'; -import { getEnabledAssets, t } from '@vegaprotocol/react-helpers'; -import { useMemo } from 'react'; +import { useDataProvider } from '@vegaprotocol/react-helpers'; +import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; +import { enabledAssetsProvider } from '@vegaprotocol/assets'; +import { accountsOnlyDataProvider } from '@vegaprotocol/accounts'; import type { WithdrawalArgs } from './use-create-withdraw'; import { WithdrawManager } from './withdraw-manager'; -import type { WithdrawFormQuery } from './__generated__/WithdrawFormQuery'; - -export const ASSET_FRAGMENT = gql` - fragment AssetFields on Asset { - id - symbol - name - decimals - status - source { - ... on ERC20 { - contractAddress - } - } - } -`; - -const WITHDRAW_FORM_QUERY = gql` - ${ASSET_FRAGMENT} - query WithdrawFormQuery($partyId: ID!) { - party(id: $partyId) { - id - withdrawals { - id - txHash - } - accounts { - type - balance - asset { - id - symbol - } - } - } - assetsConnection { - edges { - node { - ...AssetFields - } - } - } - } -`; +import { useMemo } from 'react'; interface WithdrawFormContainerProps { partyId?: string; @@ -59,35 +17,35 @@ export const WithdrawFormContainer = ({ partyId, submit, }: WithdrawFormContainerProps) => { - const { data, loading, error } = useQuery( - WITHDRAW_FORM_QUERY, - { - variables: { partyId }, - } - ); + const variables = useMemo(() => ({ partyId }), [partyId]); + const { data, loading, error } = useDataProvider({ + dataProvider: accountsOnlyDataProvider, + variables, + noUpdate: true, + }); - const assets = useMemo(() => { - if (!data?.assetsConnection?.edges) { - return []; - } - - return getEnabledAssets(data); - }, [data]); - - if (loading || !data) { - return
    {t('Loading...')}
    ; - } - - if (error) { - return
    {t('Something went wrong')}
    ; - } + const { + data: assets, + loading: assetsLoading, + error: assetsError, + } = useDataProvider({ + dataProvider: enabledAssetsProvider, + }); return ( - + + {assets && data && ( + + )} + ); }; diff --git a/libs/withdraws/src/lib/withdraw-form.spec.tsx b/libs/withdraws/src/lib/withdraw-form.spec.tsx index 92bdc589b..a0e895cbd 100644 --- a/libs/withdraws/src/lib/withdraw-form.spec.tsx +++ b/libs/withdraws/src/lib/withdraw-form.spec.tsx @@ -4,7 +4,7 @@ import { useWeb3React } from '@web3-react/core'; import { WithdrawForm } from './withdraw-form'; import { generateAsset } from './test-helpers'; import type { WithdrawFormProps } from './withdraw-form'; -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; jest.mock('@web3-react/core'); diff --git a/libs/withdraws/src/lib/withdraw-form.tsx b/libs/withdraws/src/lib/withdraw-form.tsx index c8846568a..ccf90a0fd 100644 --- a/libs/withdraws/src/lib/withdraw-form.tsx +++ b/libs/withdraws/src/lib/withdraw-form.tsx @@ -1,4 +1,4 @@ -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import { formatNumber } from '@vegaprotocol/react-helpers'; import { ethereumAddress, @@ -6,8 +6,8 @@ import { t, removeDecimal, required, - isAssetTypeERC20, } from '@vegaprotocol/react-helpers'; +import { isAssetTypeERC20 } from '@vegaprotocol/assets'; import { Button, FormGroup, diff --git a/libs/withdraws/src/lib/withdraw-manager.spec.tsx b/libs/withdraws/src/lib/withdraw-manager.spec.tsx index 2ad994d2c..d179fc4bc 100644 --- a/libs/withdraws/src/lib/withdraw-manager.spec.tsx +++ b/libs/withdraws/src/lib/withdraw-manager.spec.tsx @@ -3,9 +3,9 @@ import userEvent from '@testing-library/user-event'; import { generateAccount, generateAsset } from './test-helpers'; import type { WithdrawManagerProps } from './withdraw-manager'; import { WithdrawManager } from './withdraw-manager'; -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import BigNumber from 'bignumber.js'; -import type { Account } from './types'; +import type { AccountFieldsFragment } from '@vegaprotocol/accounts'; const asset = generateAsset(); const ethereumAddress = '0x72c22822A19D20DE7e426fB84aa047399Ddd8853'; @@ -17,7 +17,7 @@ jest.mock('@web3-react/core', () => ({ jest.mock('./use-withdraw-asset', () => ({ useWithdrawAsset: ( assets: Asset[], - accounts: Account[], + accounts: AccountFieldsFragment[], assetId?: string ) => ({ asset, diff --git a/libs/withdraws/src/lib/withdraw-manager.tsx b/libs/withdraws/src/lib/withdraw-manager.tsx index 137d7de62..f20f7153d 100644 --- a/libs/withdraws/src/lib/withdraw-manager.tsx +++ b/libs/withdraws/src/lib/withdraw-manager.tsx @@ -1,13 +1,13 @@ import sortBy from 'lodash/sortBy'; import { WithdrawForm } from './withdraw-form'; import type { WithdrawalArgs } from './use-create-withdraw'; -import type { Asset } from '@vegaprotocol/react-helpers'; -import type { Account } from './types'; +import type { Asset } from '@vegaprotocol/assets'; +import type { AccountFieldsFragment } from '@vegaprotocol/accounts'; import { useWithdrawAsset } from './use-withdraw-asset'; export interface WithdrawManagerProps { assets: Asset[]; - accounts: Account[]; + accounts: AccountFieldsFragment[]; submit: (args: WithdrawalArgs) => void; assetId?: string; } diff --git a/libs/withdraws/src/lib/withdraw-store.ts b/libs/withdraws/src/lib/withdraw-store.ts index 176421fad..a8ce49275 100644 --- a/libs/withdraws/src/lib/withdraw-store.ts +++ b/libs/withdraws/src/lib/withdraw-store.ts @@ -1,4 +1,4 @@ -import type { Asset } from '@vegaprotocol/react-helpers'; +import type { Asset } from '@vegaprotocol/assets'; import BigNumber from 'bignumber.js'; import create from 'zustand'; diff --git a/libs/withdraws/src/lib/withdrawals-table.spec.tsx b/libs/withdraws/src/lib/withdrawals-table.spec.tsx index 69cf3496f..3e80f038b 100644 --- a/libs/withdraws/src/lib/withdrawals-table.spec.tsx +++ b/libs/withdraws/src/lib/withdrawals-table.spec.tsx @@ -1,24 +1,18 @@ import { MockedProvider } from '@apollo/client/testing'; -import { act, fireEvent, render, screen } from '@testing-library/react'; -import { - addDecimalsFormatNumber, - getDateTimeFormat, -} from '@vegaprotocol/react-helpers'; -import { WithdrawalStatus, WithdrawalStatusMapping } from '@vegaprotocol/types'; +import { act, render, screen } from '@testing-library/react'; +import { getTimeFormat } from '@vegaprotocol/react-helpers'; +import { WithdrawalStatus } from '@vegaprotocol/types'; +import type { TypedDataAgGrid } from '@vegaprotocol/ui-toolkit'; import { generateWithdrawal } from './test-helpers'; -import type { - StatusCellProps, - WithdrawalsTableProps, -} from './withdrawals-table'; import { StatusCell } from './withdrawals-table'; import { WithdrawalsTable } from './withdrawals-table'; -import type { Withdrawals_party_withdrawalsConnection_edges_node } from './__generated__/Withdrawals'; +import type { WithdrawalFields } from './__generated__/WithdrawalFields'; jest.mock('@web3-react/core', () => ({ useWeb3React: () => ({ provider: undefined }), })); -const generateJsx = (props: WithdrawalsTableProps) => ( +const generateJsx = (props: TypedDataAgGrid) => ( @@ -28,7 +22,7 @@ describe('renders the correct columns', () => { it('incomplete withdrawal', async () => { const withdrawal = generateWithdrawal(); await act(async () => { - render(generateJsx({ withdrawals: [withdrawal] })); + render(generateJsx({ rowData: [withdrawal] })); }); const headers = screen.getAllByRole('columnheader'); @@ -37,19 +31,19 @@ describe('renders the correct columns', () => { 'Asset', 'Amount', 'Recipient', - 'Created at', - 'TX hash', + 'Completed', 'Status', + 'Transaction', ]); const cells = screen.getAllByRole('gridcell'); const expectedValues = [ 'asset-symbol', - addDecimalsFormatNumber(withdrawal.amount, withdrawal.asset.decimals), - '123456\u2026123456', - getDateTimeFormat().format(new Date(withdrawal.createdTimestamp)), + '1.00', + '123456…123456', + '-', + 'Pending', '-', - WithdrawalStatusMapping[withdrawal.status], ]; cells.forEach((cell, i) => { expect(cell).toHaveTextContent(expectedValues[i]); @@ -59,21 +53,22 @@ describe('renders the correct columns', () => { it('completed withdrawal', async () => { const withdrawal = generateWithdrawal({ txHash: '0x1234567891011121314', + withdrawnTimestamp: '2022-04-21T00:00:00', status: WithdrawalStatus.STATUS_FINALIZED, }); await act(async () => { - render(generateJsx({ withdrawals: [withdrawal] })); + render(generateJsx({ rowData: [withdrawal] })); }); const cells = screen.getAllByRole('gridcell'); const expectedValues = [ 'asset-symbol', - addDecimalsFormatNumber(withdrawal.amount, withdrawal.asset.decimals), + '1.00', '123456…123456', - getDateTimeFormat().format(new Date(withdrawal.createdTimestamp)), + getTimeFormat().format(new Date(withdrawal.withdrawnTimestamp as string)), + 'Completed', '0x1234…121314', - WithdrawalStatusMapping[withdrawal.status], ]; cells.forEach((cell, i) => { expect(cell).toHaveTextContent(expectedValues[i]); @@ -82,51 +77,47 @@ describe('renders the correct columns', () => { }); describe('StatusCell', () => { - let props: StatusCellProps; - let withdrawal: Withdrawals_party_withdrawalsConnection_edges_node; - let mockComplete: jest.Mock; + let props: { data: WithdrawalFields }; + let withdrawal: WithdrawalFields; beforeEach(() => { withdrawal = generateWithdrawal(); - mockComplete = jest.fn(); - // @ts-ignore dont need full ICellRendererParams props = { - value: withdrawal.status, data: withdrawal, - complete: mockComplete, }; }); it('Open', () => { - props.value = WithdrawalStatus.STATUS_FINALIZED; props.data.pendingOnForeignChain = false; props.data.txHash = null; render(); - expect(screen.getByText('Open')).toBeInTheDocument(); - fireEvent.click(screen.getByText('Complete', { selector: 'button' })); - expect(mockComplete).toHaveBeenCalled(); + expect(screen.getByText('Pending')).toBeInTheDocument(); }); it('Pending', () => { - props.value = WithdrawalStatus.STATUS_FINALIZED; props.data.pendingOnForeignChain = true; props.data.txHash = '0x123'; render(); expect(screen.getByText('Pending')).toBeInTheDocument(); - expect(screen.getByText('View on Etherscan')).toHaveAttribute( - 'href', - expect.stringContaining(props.data.txHash) - ); }); - it('Finalized', () => { - props.value = WithdrawalStatus.STATUS_FINALIZED; + it('Completed', () => { props.data.pendingOnForeignChain = false; props.data.txHash = '0x123'; + props.data.status = WithdrawalStatus.STATUS_FINALIZED; render(); - expect(screen.getByText('Finalized')).toBeInTheDocument(); + expect(screen.getByText('Completed')).toBeInTheDocument(); + }); + + it('Rejected', () => { + props.data.pendingOnForeignChain = false; + props.data.txHash = '0x123'; + props.data.status = WithdrawalStatus.STATUS_REJECTED; + render(); + + expect(screen.getByText('Rejected')).toBeInTheDocument(); }); }); diff --git a/libs/withdraws/src/lib/withdrawals-table.tsx b/libs/withdraws/src/lib/withdrawals-table.tsx index 66994eeff..96e724437 100644 --- a/libs/withdraws/src/lib/withdrawals-table.tsx +++ b/libs/withdraws/src/lib/withdrawals-table.tsx @@ -6,181 +6,108 @@ import { addDecimalsFormatNumber, } from '@vegaprotocol/react-helpers'; import type { + TypedDataAgGrid, VegaICellRendererParams, VegaValueFormatterParams, } from '@vegaprotocol/ui-toolkit'; -import { - Dialog, - Link, - AgGridDynamic as AgGrid, - Intent, - Loader, - Icon, -} from '@vegaprotocol/ui-toolkit'; +import { Link, AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit'; import { useEnvironment } from '@vegaprotocol/environment'; -import { useCompleteWithdraw } from './use-complete-withdraw'; import type { WithdrawalFields } from './__generated__/WithdrawalFields'; -import type { VerifyState } from './use-verify-withdrawal'; -import { ApprovalStatus, useVerifyWithdrawal } from './use-verify-withdrawal'; +import { WithdrawalStatus } from '@vegaprotocol/types'; -export interface WithdrawalsTableProps { - withdrawals: WithdrawalFields[]; -} - -export const WithdrawalsTable = ({ withdrawals }: WithdrawalsTableProps) => { +export const WithdrawalsTable = (props: TypedDataAgGrid) => { const { ETHERSCAN_URL } = useEnvironment(); - const { - submit, - reset: resetTx, - Dialog: EthereumTransactionDialog, - } = useCompleteWithdraw(); - const { - verify, - state: verifyState, - reset: resetVerification, - } = useVerifyWithdrawal(); return ( - <> - - - ) => { - return addDecimalsFormatNumber(value, data.asset.decimals); - }} - /> - ) => { - if (!value) return '-'; - return truncateByChars(value); - }} - /> - ) => { - return getDateTimeFormat().format(new Date(value)); - }} - /> - ) => { - if (!value) return '-'; - return ( - - {truncateByChars(value)} - - ); - }} - /> - { - const verified = await verify(withdrawal); - - if (!verified) { - return; - } - - submit(withdrawal.id); - }, - ethUrl: ETHERSCAN_URL, - }} - /> - - { - if (!isOpen) { - resetTx(); - resetVerification(); - } + + + ) => { + return addDecimalsFormatNumber(value, data.asset.decimals); }} - open={verifyState.dialogOpen} - size="small" - {...getVerifyDialogProps(verifyState.status)} - > - - - - + /> + ) => { + if (!value) return '-'; + return truncateByChars(value); + }} + /> + ) => { + const ts = data.withdrawnTimestamp; + if (!ts) return '-'; + return getDateTimeFormat().format(new Date(ts)); + }} + /> + + ) => { + if (!value) return '-'; + return ( + + {truncateByChars(value)} + + ); + }} + /> + ); }; -export interface StatusCellProps - extends VegaICellRendererParams { - ethUrl: string; - complete: (withdrawal: WithdrawalFields) => void; -} - -export const StatusCell = ({ ethUrl, data, complete }: StatusCellProps) => { - if (data.pendingOnForeignChain) { - return ( -
    - {t('Pending')} - {data.txHash && ( - - {t('View on Etherscan')} - - )} -
    - ); +export const StatusCell = ({ data }: { data: WithdrawalFields }) => { + if (data.pendingOnForeignChain || !data.txHash) { + return {t('Pending')}; } - - if (!data.txHash) { - return ( -
    - {t('Open')} - -
    - ); + if (data.status === WithdrawalStatus.STATUS_FINALIZED) { + return {t('Completed')}; } - - return {t('Finalized')}; + if (data.status === WithdrawalStatus.STATUS_REJECTED) { + return {t('Rejected')}; + } + return {t('Failed')}; }; export interface RecipientCellProps @@ -204,48 +131,3 @@ const RecipientCell = ({ ); }; - -const getVerifyDialogProps = (status: ApprovalStatus) => { - if (status === ApprovalStatus.Error) { - return { - intent: Intent.Danger, - icon: , - }; - } - - if (status === ApprovalStatus.Pending) { - return { intent: Intent.None, icon: }; - } - - if (status === ApprovalStatus.Delayed) { - return { intent: Intent.Warning, icon: }; - } - - return { intent: Intent.None }; -}; - -const VerificationStatus = ({ state }: { state: VerifyState }) => { - if (state.status === ApprovalStatus.Error) { - return

    {t('Something went wrong')}

    ; - } - - if (state.status === ApprovalStatus.Pending) { - return

    {t('Verifying...')}

    ; - } - - if (state.status === ApprovalStatus.Delayed && state.completeTimestamp) { - const formattedTime = getDateTimeFormat().format( - new Date(state.completeTimestamp) - ); - return ( - <> -

    - {t("The amount you're withdrawing has triggered a time delay")} -

    -

    {t(`Cannot be completed until ${formattedTime}`)}

    - - ); - } - - return null; -}; diff --git a/vegacapsule/config.hcl b/vegacapsule/config.hcl index 34ae932cb..a6ceb9c7b 100644 --- a/vegacapsule/config.hcl +++ b/vegacapsule/config.hcl @@ -18,15 +18,12 @@ EOT } wallet "wallet-1" { - binary = "vegawallet" - template = <<-EOT Name = "DV" Level = "info" TokenExpiry = "168h0m0s" Port = 1789 Host = "0.0.0.0" - [API] [API.GRPC] Hosts = [{{range $i, $v := .Validators}}{{if ne $i 0}},{{end}}"127.0.0.1:30{{$i}}2"{{end}}] @@ -54,7 +51,7 @@ EOT auth_soft_fail = true } docker_service "postgres-1" { - image = "vegaprotocol/timescaledb:2.7.1-pg14" + image = "vegaprotocol/timescaledb:2.8.0-pg14" cmd = "postgres" args = [] env = { @@ -66,6 +63,11 @@ EOT value = 5232 to = 5432 } + resources { + cpu = 600 + memory = 900 + } + auth_soft_fail = true } } @@ -90,7 +92,7 @@ EOT node_set "full" { count = 1 mode = "full" - data_node_binary = "data-node" + use_data_node = true config_templates { vega_file = "./node_set_templates/default/vega_full.tmpl" @@ -98,4 +100,4 @@ EOT data_node_file = "./node_set_templates/default/data_node_full_external_postgres.tmpl" } } -} +} \ No newline at end of file diff --git a/vegacapsule/genesis.tmpl b/vegacapsule/genesis.tmpl index d590a9ca8..f3028d3dc 100644 --- a/vegacapsule/genesis.tmpl +++ b/vegacapsule/genesis.tmpl @@ -175,46 +175,114 @@ }, "network_parameters": { "blockchains.ethereumConfig": "{\"network_id\": \"{{ .NetworkID }}\", \"chain_id\": \"{{ .ChainID }}\", \"collateral_bridge_contract\": { \"address\": \"{{.GetEthContractAddr "erc20_bridge_1"}}\" }, \"confirmations\": 3, \"staking_bridge_contract\": { \"address\": \"{{.GetEthContractAddr "staking_bridge"}}\", \"deployment_block_height\": 0}, \"token_vesting_contract\": { \"address\": \"{{.GetEthContractAddr "erc20_vesting"}}\", \"deployment_block_height\": 0 }, \"multisig_control_contract\": { \"address\": \"{{.GetEthContractAddr "MultisigControl"}}\", \"deployment_block_height\": 0 }}", - "governance.proposal.asset.minClose": "2s", - "governance.proposal.asset.minEnact": "2s", - "governance.proposal.asset.requiredParticipation": "0.00000000000000000000000015", - "governance.proposal.freeform.minProposerBalance": "1", - "governance.proposal.freeform.minVoterBalance": "1", - "governance.proposal.freeform.requiredMajority": "0.66", - "governance.proposal.freeform.requiredParticipation": "0.00001", - "governance.proposal.freeform.maxClose": "8760h0m0s", - "governance.proposal.freeform.minClose": "48h0m0s", - "governance.proposal.market.minClose": "2s", - "governance.proposal.market.minEnact": "2s", - "governance.proposal.market.requiredParticipation": "0.00000000000000000000000015", - "governance.proposal.updateMarket.minClose": "2s", - "governance.proposal.updateMarket.minEnact": "2s", - "governance.proposal.updateMarket.requiredParticipation": "0.00000000000000000000000015", - "governance.proposal.updateNetParam.minClose": "2s", - "governance.proposal.updateNetParam.minEnact": "2s", - "governance.proposal.updateNetParam.requiredParticipation": "0.00000000000000000000000015", - "market.auction.minimumDuration": "3s", - "market.fee.factors.infrastructureFee": "0.001", - "market.fee.factors.makerFee": "0.004", - "market.liquidity.stakeToCcySiskas": "0.3", - "market.liquidity.targetstake.triggering.ratio": "0.7", + "governance.proposal.asset.maxClose":"8760h0m0s", + "governance.proposal.asset.maxEnact":"8760h0m0s", + "governance.proposal.asset.minClose":"2s", + "governance.proposal.asset.minEnact":"2s", + "governance.proposal.asset.minProposerBalance":"0", + "governance.proposal.asset.minVoterBalance":"0", + "governance.proposal.asset.requiredMajority":"0.66", + "governance.proposal.asset.requiredParticipation":"0.00000000000000000000000015", + "governance.proposal.freeform.maxClose":"8760h0m0s", + "governance.proposal.freeform.minClose":"48h0m0s", + "governance.proposal.freeform.minProposerBalance":"1", + "governance.proposal.freeform.minVoterBalance":"1", + "governance.proposal.freeform.requiredMajority":"0.66", + "governance.proposal.freeform.requiredParticipation":"0.00001", + "governance.proposal.market.maxClose":"8760h0m0s", + "governance.proposal.market.maxEnact":"8760h0m0s", + "governance.proposal.market.minClose":"2s", + "governance.proposal.market.minEnact":"2s", + "governance.proposal.market.minProposerBalance":"0", + "governance.proposal.market.minVoterBalance":"0", + "governance.proposal.market.requiredMajority":"0.66", + "governance.proposal.market.requiredParticipation":"0.00000000000000000000000015", + "governance.proposal.updateAsset.maxClose":"8760h0m0s", + "governance.proposal.updateAsset.maxEnact":"8760h0m0s", + "governance.proposal.updateAsset.minClose":"48h0m0s", + "governance.proposal.updateAsset.minEnact":"48h0m0s", + "governance.proposal.updateAsset.minProposerBalance":"0", + "governance.proposal.updateAsset.minVoterBalance":"0", + "governance.proposal.updateAsset.requiredMajority":"0.66", + "governance.proposal.updateAsset.requiredParticipation":"0.00001", + "governance.proposal.updateMarket.maxClose":"8760h0m0s", + "governance.proposal.updateMarket.maxEnact":"8760h0m0s", + "governance.proposal.updateMarket.minClose":"2s", + "governance.proposal.updateMarket.minEnact":"2s", + "governance.proposal.updateMarket.minProposerBalance":"0", + "governance.proposal.updateMarket.minProposerEquityLikeShare":"0.66", + "governance.proposal.updateMarket.minVoterBalance":"0", + "governance.proposal.updateMarket.requiredMajority":"0.66", + "governance.proposal.updateMarket.requiredMajorityLP":"0.66", + "governance.proposal.updateMarket.requiredParticipation":"0.00000000000000000000000015", + "governance.proposal.updateMarket.requiredParticipationLP":"0.00001", + "governance.proposal.updateNetParam.maxClose":"8760h0m0s", + "governance.proposal.updateNetParam.maxEnact":"8760h0m0s", + "governance.proposal.updateNetParam.minClose":"2s", + "governance.proposal.updateNetParam.minEnact":"2s", + "governance.proposal.updateNetParam.minProposerBalance":"0", + "governance.proposal.updateNetParam.minVoterBalance":"0", + "governance.proposal.updateNetParam.requiredMajority":"0.66", + "governance.proposal.updateNetParam.requiredParticipation":"0.00000000000000000000000015", + "limits.assets.proposeEnabledFrom":"2100-12-30T00:00:00Z", + "limits.markets.proposeEnabledFrom":"2100-12-30T00:00:00Z", + "market.auction.maximumDuration":"168h0m0s", + "market.auction.minimumDuration":"3s", + "market.fee.factors.infrastructureFee":"0.001", + "market.fee.factors.makerFee":"0.004", + "market.liquidity.bondPenaltyParameter":"1", + "market.liquidity.maximumLiquidityFeeFactorLevel":"1", + "market.liquidity.minimum.probabilityOfTrading.lpOrders":"1e-8", + "market.liquidity.probabilityOfTrading.tau.scaling":"1", + "market.liquidity.providers.fee.distributionTimeStep":"0s", + "market.liquidity.stakeToCcySiskas":"0.3", + "market.liquidity.targetstake.triggering.ratio":"0.7", + "market.liquidityProvision.minLpStakeQuantumMultiple":"1", + "market.liquidityProvision.shapes.maxSize":"100", + "market.margin.scalingFactors":"{\"search_level\": 1.1, \"initial_margin\": 1.2, \"collateral_release\": 1.4}", + "market.monitor.price.defaultParameters":"{\"triggers\": []}", + "market.stake.target.scalingFactor":"10", + "market.stake.target.timeWindow":"1h0m0s", + "market.value.windowLength":"168h0m0s", + "network.checkpoint.timeElapsedBetweenCheckpoints":"10s", + "network.floatingPointUpdates.delay":"5m", + "network.validators.ersatz.multipleOfTendermintValidators":"0.5", + "network.validators.ersatz.rewardFactor":"0.5", + "network.validators.incumbentBonus":"1", + "network.validators.minimumEthereumEventsForNewValidator":"3", + "network.validators.multisig.numberOfSigners":"13", + "network.validators.tendermint.number":"30", "network.checkpoint.timeElapsedBetweenCheckpoints": "10s", - "reward.asset": "{{.GetVegaContractID "VEGA"}}", - "reward.staking.delegation.competitionLevel": "3.1", - "reward.staking.delegation.delegatorShare": "0.883", - "reward.staking.delegation.maxPayoutPerParticipant": "700000000000000000000", - "reward.staking.delegation.minimumValidatorStake": "3000000000000000000000", - "reward.staking.delegation.payoutDelay": "5m", - "reward.staking.delegation.payoutFraction": "0.007", - "spam.protection.delegation.min.tokens": "1000000000000000000", - "spam.protection.max.delegations": "390", - "spam.protection.max.proposals": "100", - "spam.protection.max.votes": "100", - "spam.protection.proposal.min.tokens": "1000000000000000000", - "spam.protection.voting.min.tokens": "1000000000000000000", - "validators.delegation.minAmount": "100000000000000000", - "validators.epoch.length": "5s", - "validators.vote.required": "0.67" + "reward.asset":"{{.GetVegaContractID "VEGA"}}", + "reward.staking.delegation.competitionLevel":"3.1", + "reward.staking.delegation.delegatorShare":"0.883", + "reward.staking.delegation.maxPayoutPerEpoch":"7000000000000000000000", + "reward.staking.delegation.maxPayoutPerParticipant":"700000000000000000000", + "reward.staking.delegation.minValidators":"5", + "reward.staking.delegation.minimumValidatorStake":"3000000000000000000000", + "reward.staking.delegation.optimalStakeMultiplier":"3.0", + "reward.staking.delegation.payoutDelay":"5m", + "reward.staking.delegation.payoutFraction":"0.007", + "rewards.marketCreationQuantumMultiple":"10000000", + "snapshot.interval.length":"1000", + "spam.pow.difficulty":"15", + "spam.pow.hashFunction":"sha3_24_rounds", + "spam.pow.increaseDifficulty":"0", + "spam.pow.numberOfPastBlocks":"100", + "spam.pow.numberOfTxPerBlock":"2", + "spam.protection.delegation.min.tokens":"2000000000000000000", + "spam.protection.max.batchSize":"15", + "spam.protection.max.delegations":"390", + "spam.protection.max.proposals":"100", + "spam.protection.max.votes":"100", + "spam.protection.maxUserTransfersPerEpoch":"20", + "spam.protection.proposal.min.tokens":"1000000000000000000", + "spam.protection.voting.min.tokens":"1000000000000000000", + "transfer.fee.factor":"0.001", + "transfer.minTransferQuantumMultiple":"0.1", + "validators.delegation.minAmount":"100000000000000000", + "validators.epoch.length":"5s", + "validators.vote.required":"0.67" }, "network_limits": { "propose_asset_enabled": true,