diff --git a/.github/workflows/capsule-cypress-manual-trigger.yml b/.github/workflows/capsule-cypress-manual-trigger.yml index f34f3b717..6cb2b810d 100644 --- a/.github/workflows/capsule-cypress-manual-trigger.yml +++ b/.github/workflows/capsule-cypress-manual-trigger.yml @@ -47,6 +47,14 @@ jobs: ## Checkout capsule ####### + # Checkout front ends + - name: Checkout frontend mono repo + uses: actions/checkout@v2 + with: + ref: ${{ github.event.pull_request.head.ref }} + fetch-depth: 0 + path: './frontend-monorepo' + # Checkout capsule to build local network - name: Checkout capsule uses: actions/checkout@v2 @@ -70,7 +78,7 @@ jobs: uses: actions/checkout@v2 with: repository: vegaprotocol/vega - ref: develop + ref: v0.55.0 token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} path: './vega' @@ -120,18 +128,13 @@ jobs: ## Run some tests ###### - # Checkout front ends - - name: Checkout frontend mono repo - uses: actions/checkout@v2 - with: - ref: ${{ github.event.pull_request.head.ref }} - fetch-depth: 0 - - name: Install root dependencies run: yarn install + working-directory: frontend-monorepo - name: Run Cypress tests - run: yarn nx run ${{ github.event.inputs.project }}:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome + run: yarn nx run ${{ github.event.inputs.project }}:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} + working-directory: frontend-monorepo env: CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }} CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }} diff --git a/.github/workflows/capsule-cypress-night-run.yml b/.github/workflows/capsule-cypress-night-run.yml index dd130d132..b0ea14659 100644 --- a/.github/workflows/capsule-cypress-night-run.yml +++ b/.github/workflows/capsule-cypress-night-run.yml @@ -31,6 +31,14 @@ jobs: ## Checkout capsule ####### + # Checkout front ends + - name: Checkout frontend mono repo + uses: actions/checkout@v2 + with: + ref: ${{ github.event.pull_request.head.ref }} + fetch-depth: 0 + path: './frontend-monorepo' + # Checkout capsule to build local network - name: Checkout capsule uses: actions/checkout@v2 @@ -54,7 +62,7 @@ jobs: uses: actions/checkout@v2 with: repository: vegaprotocol/vega - ref: develop + ref: v0.55.0 token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} path: './vega' @@ -104,18 +112,13 @@ jobs: ## Run some tests ###### - # Checkout front ends - - name: Checkout frontend mono repo - uses: actions/checkout@v2 - with: - ref: master - fetch-depth: 0 - - name: Install root dependencies run: yarn install + working-directory: frontend-monorepo - name: Run Cypress tests - run: yarn nx run-many --target=e2e --all --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome + run: yarn nx run-many --target=e2e --all --record --key ${{ secrets.CYPRESS_RECORD_KEY }} + working-directory: frontend-monorepo env: CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }} CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }} diff --git a/.github/workflows/capsule-cypress.yml b/.github/workflows/capsule-cypress.yml index 0414d9258..a2eb2a4d1 100644 --- a/.github/workflows/capsule-cypress.yml +++ b/.github/workflows/capsule-cypress.yml @@ -69,7 +69,7 @@ jobs: uses: actions/checkout@v2 with: repository: vegaprotocol/vega - ref: develop + ref: v0.54.0 token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} path: './vega' @@ -130,7 +130,7 @@ jobs: working-directory: frontend-monorepo - name: Run Cypress tests - run: npx nx affected:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome + run: npx nx affected:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} working-directory: frontend-monorepo env: CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }} diff --git a/.husky/commit-msg b/.husky/commit-msg index 725ca26d0..b0dca9dee 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -6,7 +6,3 @@ yarn commitlint --edit "${1}" # Lint all staged files yarn lint-staged - -# Build & test affected apps -yarn nx affected:build --uncommitted -yarn nx affected:test --uncommitted diff --git a/.prettierignore b/.prettierignore index 6b83ad2e8..344ebc105 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,6 +3,7 @@ /dist /coverage __generated__ +__generated___ apps/static/src/assets/devnet-tranches.json apps/static/src/assets/mainnet-tranches.json diff --git a/README.md b/README.md index 8d68ec8ad..f0b231109 100644 --- a/README.md +++ b/README.md @@ -69,10 +69,10 @@ Run `nx serve my-app` for a dev server. Navigate to the port specified in `app/< ### Using Apollo GraphQL and Generate Types -In order to generate the schemas for your GraphQL queries, you can run `NX_VEGA_URL=[YOUR URL HERE] nx run types:generate`. +In order to generate the schemas for your GraphQL queries, you can run `GRAPHQL_SCHEMA_PATH=[YOUR SCHEMA FILE / API URL HERE] nx run types:generate`. ```bash -export NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql +export GRAPHQL_SCHEMA_PATH=https://api.n11.testnet.vega.xyz/graphql yarn nx run types:generate ``` diff --git a/apps/console-lite-e2e/src/integration/market-selector.test.ts b/apps/console-lite-e2e/src/integration/market-selector.test.ts index 352311f40..7b94eacb6 100644 --- a/apps/console-lite-e2e/src/integration/market-selector.test.ts +++ b/apps/console-lite-e2e/src/integration/market-selector.test.ts @@ -9,6 +9,7 @@ import { generatePartyBalance } from '../support/mocks/generate-party-balance'; import { generatePartyMarketData } from '../support/mocks/generate-party-market-data'; import { generateMarketMarkPrice } from '../support/mocks/generate-market-mark-price'; import { generateMarketNames } from '../support/mocks/generate-market-names'; +import { generateMarketDepth } from '../support/mocks/generate-market-depth'; describe('market selector', () => { let markets; @@ -23,6 +24,7 @@ describe('market selector', () => { aliasQuery(req, 'PartyMarketData', generatePartyMarketData()); aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice()); aliasQuery(req, 'MarketNames', generateMarketNames()); + aliasQuery(req, 'MarketDepth', generateMarketDepth()); }); cy.visit('/markets'); @@ -39,7 +41,7 @@ describe('market selector', () => { connectVegaWallet(); cy.get('input[placeholder="Search"]').should( 'have.value', - markets[0].name + markets[0].tradableInstrument.instrument.name ); cy.getByTestId('arrow-button').click(); cy.getByTestId('market-pane').should('be.visible'); @@ -47,7 +49,7 @@ describe('market selector', () => { .children() .find('[role="button"]') .first() - .should('contain.text', markets[0].name); + .should('contain.text', markets[0].tradableInstrument.instrument.name); cy.getByTestId('market-pane') .children() .find('[role="button"]') @@ -70,8 +72,8 @@ describe('market selector', () => { cy.get('input[placeholder="Search"]').type('aa'); const filtered = markets.filter( (market) => - market.data.market.state === 'STATE_ACTIVE' && - market.name.match(/aa/i) + market.state === 'STATE_ACTIVE' && + market.tradableInstrument.instrument.name.match(/aa/i) ); cy.getByTestId('market-pane') .children() @@ -88,7 +90,7 @@ describe('market selector', () => { ); cy.get('input[placeholder="Search"]').should( 'have.value', - filtered[filtered.length - 1].name + filtered[filtered.length - 1].tradableInstrument.instrument.name ); } }); @@ -131,7 +133,7 @@ describe('market selector', () => { cy.getByTestId('dialog-close').click(); cy.get('input[placeholder="Search"]').should( 'have.value', - markets[0].name + markets[0].tradableInstrument.instrument.name ); } }); 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 f4dc1dbb1..0e7cf03a7 100644 --- a/apps/console-lite-e2e/src/integration/market-trade.test.ts +++ b/apps/console-lite-e2e/src/integration/market-trade.test.ts @@ -1,5 +1,8 @@ import { aliasQuery } from '@vegaprotocol/cypress'; -import { generateSimpleMarkets } from '../support/mocks/generate-markets'; +import { + generateSimpleMarkets, + generateMarkets, +} from '../support/mocks/generate-markets'; import { generateDealTicket } from '../support/mocks/generate-deal-ticket'; import { generateMarketTags } from '../support/mocks/generate-market-tags'; import { generateMarketPositions } from '../support/mocks/generate-market-positions'; @@ -14,6 +17,7 @@ describe('Market trade', () => { let markets; beforeEach(() => { cy.mockGQL((req) => { + aliasQuery(req, 'Markets', generateMarkets()); aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets()); aliasQuery(req, 'DealTicketQuery', generateDealTicket()); aliasQuery(req, 'MarketTags', generateMarketTags()); @@ -170,7 +174,50 @@ describe('Market trade', () => { .find('button') .should('have.text', '2'); cy.get('button').contains('Max').click(); - cy.getByTestId('price-slippage-value').should('have.text', '0.02%'); + } + }); + + it('slippage value should be displayed', () => { + if (markets?.length) { + cy.visit(`/trading/${markets[1].id}`); + connectVegaWallet(); + cy.get('#step-1-control [aria-label^="Selected value"]').click(); + cy.get('button[aria-label="Open short position"]').click(); + cy.get('#step-2-control').click(); + cy.get('button').contains('Max').click(); + cy.get('#step-2-panel') + .find('dl') + .eq(2) + .find('dd') + .should('have.text', '0.02%'); + } + }); + + it('allow slippage value to be adjusted', () => { + if (markets?.length) { + cy.visit(`/trading/${markets[1].id}`); + connectVegaWallet(); + cy.get('#step-1-control [aria-label^="Selected value"]').click(); + cy.get('button[aria-label="Open short position"]').click(); + cy.get('#step-2-control').click(); + cy.get('button').contains('Max').click(); + cy.get('#step-2-panel') + .find('dl') + .eq(2) + .find('dd') + .should('have.text', '0.02%'); + cy.get('#step-2-panel').find('dl').eq(2).find('button').click(); + cy.get('#input-order-slippage') + .focus() + .type('{backspace}{backspace}{backspace}1'); + + cy.getByTestId('slippage-dialog').find('button').click(); + + cy.get('#step-2-panel') + .find('dl') + .eq(2) + .find('dd') + .should('have.text', '1%'); } }); @@ -195,9 +242,9 @@ describe('Market trade', () => { cy.get('#step-2-panel').find('dd').eq(0).find('button').click(); cy.get('#step-2-panel') .find('dt') - .eq(3) + .eq(2) .should('have.text', 'Est. Position Size (tDAI)'); - cy.get('#step-2-panel').find('dd').eq(3).should('have.text', '197.86012'); + cy.get('#step-2-panel').find('dd').eq(2).should('have.text', '197.86012'); } }); @@ -210,11 +257,11 @@ describe('Market trade', () => { cy.get('#step-2-control').click(); cy.get('#step-2-panel') .find('dt') - .eq(4) + .eq(3) .should('have.text', 'Est. Fees (tDAI)'); cy.get('#step-2-panel') .find('dd') - .eq(4) + .eq(3) .should('have.text', '3.00000 (3.03%)'); } }); diff --git a/apps/console-lite-e2e/src/support/mocks/commons.ts b/apps/console-lite-e2e/src/support/mocks/commons.ts index 0b7b90522..a80b9e4fe 100644 --- a/apps/console-lite-e2e/src/support/mocks/commons.ts +++ b/apps/console-lite-e2e/src/support/mocks/commons.ts @@ -75,18 +75,11 @@ const protoCandles = [ export const protoMarket = { id: 'first-btcusd-id', - name: 'AAVEDAI Monthly (30 Jun 2022)', - data: { - market: { - id: 'first-btcusd-id', - state: 'STATE_ACTIVE', - __typename: 'Market', - }, - __typename: 'MarketData', - }, + state: 'STATE_ACTIVE', tradableInstrument: { instrument: { code: 'AAVEDAI.MF21', + name: 'AAVEDAI Monthly (30 Jun 2022)', metadata: { tags: [ 'formerly:2839D9B2329C9E70', diff --git a/apps/console-lite-e2e/src/support/mocks/generate-deal-ticket.ts b/apps/console-lite-e2e/src/support/mocks/generate-deal-ticket.ts index e74c726e8..a99bd4603 100644 --- a/apps/console-lite-e2e/src/support/mocks/generate-deal-ticket.ts +++ b/apps/console-lite-e2e/src/support/mocks/generate-deal-ticket.ts @@ -2,13 +2,13 @@ export const generateDealTicket = () => { return { market: { id: 'first-btcusd-id', - name: 'AAVEDAI Monthly (30 Jun 2022)', decimalPlaces: 5, positionDecimalPlaces: 0, state: 'STATE_ACTIVE', tradingMode: 'Continuous', tradableInstrument: { instrument: { + name: 'AAVEDAI Monthly (30 Jun 2022)', product: { quoteName: 'DAI', settlementAsset: { diff --git a/apps/console-lite-e2e/src/support/mocks/generate-market-depth.ts b/apps/console-lite-e2e/src/support/mocks/generate-market-depth.ts index f8c60fead..d0342a6ea 100644 --- a/apps/console-lite-e2e/src/support/mocks/generate-market-depth.ts +++ b/apps/console-lite-e2e/src/support/mocks/generate-market-depth.ts @@ -1,24 +1,15 @@ -export const generateMarketDepth = () => { - return { +import merge from 'lodash/merge'; +import type { PartialDeep } from 'type-fest'; +// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries +import type { MarketDepth } from '../../../../../libs/market-depth/src/lib/__generated__/MarketDepth'; + +export const generateMarketDepth = ( + override?: PartialDeep +): MarketDepth => { + const defaultResult: MarketDepth = { market: { id: 'a46bd7e5277087723b7ab835844dec3cef8b4445738101269624bf5537d5d423', - decimalPlaces: 5, - positionDecimalPlaces: 0, - data: { - staticMidPrice: '9893006', - marketTradingMode: 'TRADING_MODE_CONTINUOUS', - indicativeVolume: '0', - indicativePrice: '0', - bestStaticBidPrice: '9893006', - bestStaticOfferPrice: '9893006', - market: { - id: 'a46bd7e5277087723b7ab835844dec3cef8b4445738101269624bf5537d5d423', - __typename: 'Market', - }, - __typename: 'MarketData', - }, depth: { - lastTrade: { price: '9893006', __typename: 'Trade' }, sell: [ { price: '9893007', @@ -215,4 +206,5 @@ export const generateMarketDepth = () => { __typename: 'Market', }, }; + return merge(defaultResult, override); }; diff --git a/apps/console-lite-e2e/src/support/mocks/generate-market-names.ts b/apps/console-lite-e2e/src/support/mocks/generate-market-names.ts index 9fd098070..07ad3bf48 100644 --- a/apps/console-lite-e2e/src/support/mocks/generate-market-names.ts +++ b/apps/console-lite-e2e/src/support/mocks/generate-market-names.ts @@ -6,11 +6,11 @@ export const generateMarketNames = () => { { ...protoMarket }, { id: '1d7ddf67dac4924db03f5bf58571a7bcb1908d70c66580467717aabc5345b68a', - name: 'Apple Monthly (30 Jun 2022)', state: 'STATE_SUSPENDED', tradableInstrument: { instrument: { code: 'AAPL.MF21', + name: 'Apple Monthly (30 Jun 2022)', metadata: { tags: [ 'formerly:4899E01009F1A721', @@ -32,11 +32,11 @@ export const generateMarketNames = () => { }, { id: '87ae87cd3244fc1fab4b0e2dad2437879864192bb969f3109b69293421644c8b', - name: 'Tesla Quarterly (30 Jun 2022)', state: 'STATE_SUSPENDED', tradableInstrument: { instrument: { code: 'TSLA.QM21', + name: 'Tesla Quarterly (30 Jun 2022)', metadata: { tags: [ 'formerly:5A86B190C384997F', @@ -58,11 +58,11 @@ export const generateMarketNames = () => { }, { id: '69205712a854f1bbfb69fa3d11b60e01a1e249bafb5ece88115e7451e8ef07b3', - name: 'BTCUSD Monthly (30 Jun 2022)', state: 'STATE_SUSPENDED', tradableInstrument: { instrument: { code: 'BTCUSD.MF21', + name: 'BTCUSD Monthly (30 Jun 2022)', metadata: { tags: [ 'formerly:076BB86A5AA41E3E', @@ -83,11 +83,11 @@ export const generateMarketNames = () => { }, { id: 'ethbtc-quaterly', - name: 'ETHBTC Quarterly (30 Jun 2022)', state: 'STATE_ACTIVE', tradableInstrument: { instrument: { code: 'ETHBTC.QM21', + name: 'ETHBTC Quarterly (30 Jun 2022)', metadata: { tags: [ 'formerly:1F0BB6EB5703B099', @@ -108,11 +108,11 @@ export const generateMarketNames = () => { }, { id: '3c62b2714c4332d1a689a5352bff090e6aabccfd6bd87ce018936b38372530c9', - name: 'UNIDAI Monthly (30 Jun 2022)', state: 'STATE_ACTIVE', tradableInstrument: { instrument: { code: 'UNIDAI.MF21', + name: 'UNIDAI Monthly (30 Jun 2022)', metadata: { tags: [ 'formerly:3C58ED2A4A6C5D7E', diff --git a/apps/console-lite-e2e/src/support/mocks/generate-markets.ts b/apps/console-lite-e2e/src/support/mocks/generate-markets.ts index 9a7b50bdd..16d39a83a 100644 --- a/apps/console-lite-e2e/src/support/mocks/generate-markets.ts +++ b/apps/console-lite-e2e/src/support/mocks/generate-markets.ts @@ -1,3 +1,5 @@ +import merge from 'lodash/merge'; +import { MarketState, MarketTradingMode } from '@vegaprotocol/types'; import { protoMarket } from './commons'; export const generateSimpleMarkets = () => { @@ -6,19 +8,11 @@ export const generateSimpleMarkets = () => { { ...protoMarket }, { id: '57fbaa322e97cfc8bb5f1de048c37e033c41b1ac1906d3aed9960912a067ef5a', - name: 'CELUSD (June 2022)', state: 'Active', - data: { - market: { - id: '57fbaa322e97cfc8bb5f1de048c37e033c41b1ac1906d3aed9960912a067ef5a', - state: 'STATE_PENDING', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'CELUSD', + name: 'CELUSD (June 2022)', metadata: { tags: [ 'base:CEL', @@ -43,19 +37,11 @@ export const generateSimpleMarkets = () => { }, { id: 'ccf2f04865e5951ac3405da6e16b7cbdb535a0ad32df4df2dbed4262cf473255', - name: 'XMRUSD market', state: 'Suspended', - data: { - market: { - id: 'ccf2f04865e5951ac3405da6e16b7cbdb535a0ad32df4df2dbed4262cf473255', - state: 'STATE_PROPOSED', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'XMRUSD', + name: 'XMRUSD market', metadata: { tags: [ 'base:monero', @@ -80,19 +66,11 @@ export const generateSimpleMarkets = () => { }, { id: '6030e5b4e0ca3297a26081e5af4d453f97f96baab2d74bf56f84efcffc4c382f', - name: 'UNIDAI Monthly (30 Jun 2022)', state: 'Active', - data: { - market: { - id: '6030e5b4e0ca3297a26081e5af4d453f97f96baab2d74bf56f84efcffc4c382f', - state: 'STATE_SUSPENDED', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'UNIDAI.MF21', + name: 'UNIDAI Monthly (30 Jun 2022)', metadata: { tags: [ 'formerly:3C58ED2A4A6C5D7E', @@ -191,19 +169,11 @@ export const generateSimpleMarkets = () => { }, { id: 'de74a5572045b300e8ec50d136896912ec76e7d7ec135bc305dfd4854d9363a4', - name: 'XMRUSD market', state: 'Pending', - data: { - market: { - id: 'de74a5572045b300e8ec50d136896912ec76e7d7ec135bc305dfd4854d9363a4', - state: 'STATE_ACTIVE', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'XMRUSD', + name: 'XMRUSD market', metadata: { tags: [ 'base:monero', @@ -301,19 +271,11 @@ export const generateSimpleMarkets = () => { }, { id: '31ea96284611771e486c820acb26a325a99664f9854b5a7e7ad99023efa8f9e6', - name: 'ApeCoin (18 Jul 2022)', state: 'Closed', - data: { - market: { - id: '31ea96284611771e486c820acb26a325a99664f9854b5a7e7ad99023efa8f9e6', - state: 'STATE_PROPOSED', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'APE/USD', + name: 'ApeCoin (18 Jul 2022)', metadata: { tags: [ 'quote:USD', @@ -337,19 +299,11 @@ export const generateSimpleMarkets = () => { }, { id: '34cff959cdc2ffdb0f167820d701fe8b51cc6b8588e650d93369aaa22d6f8b74', - name: 'BTCUSD Monthly (18 Jul 2022)', state: 'Settled', - data: { - market: { - id: '34cff959cdc2ffdb0f167820d701fe8b51cc6b8588e650d93369aaa22d6f8b74', - state: 'STATE_PROPOSED', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'BTCUSD.MF21', + name: 'BTCUSD Monthly (18 Jul 2022)', metadata: { tags: [ 'formerly:076BB86A5AA41E3E', @@ -375,19 +329,11 @@ export const generateSimpleMarkets = () => { }, { id: '87b0bbb3c171baa5d97dfc3852332829c91e5c5dc9f7c8fb584c6d8ac75aaaf2', - name: 'Builders Club x ETHcc', state: 'Settled', - data: { - market: { - id: '87b0bbb3c171baa5d97dfc3852332829c91e5c5dc9f7c8fb584c6d8ac75aaaf2', - state: 'STATE_ACTIVE', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'LTCUSD', + name: 'Builders Club x ETHcc', metadata: { tags: [ 'base:litecoin', @@ -473,19 +419,11 @@ export const generateSimpleMarkets = () => { }, { id: '45266143c6e9b58f4cff9b8906e971c531bb29ea7af01066973f9b77e8134823', - name: 'BTCUSD Monthly (18 Jul 2022)', state: 'Pending', - data: { - market: { - id: '45266143c6e9b58f4cff9b8906e971c531bb29ea7af01066973f9b77e8134823', - state: 'STATE_PROPOSED', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'BTCUSD.MF21', + name: 'BTCUSD Monthly (18 Jul 2022)', metadata: { tags: [ 'formerly:076BB86A5AA41E3E', @@ -511,19 +449,11 @@ export const generateSimpleMarkets = () => { }, { id: '65663ebdc96161162769c4d5c5508137416748178d7cb28e2cb0d07a151a2bc6', - name: 'ETHBTC Quarterly (30 Jun 2022)', state: 'Active', - data: { - market: { - id: '65663ebdc96161162769c4d5c5508137416748178d7cb28e2cb0d07a151a2bc6', - state: 'STATE_ACTIVE', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'ETHBTC.QM21', + name: 'ETHBTC Quarterly (30 Jun 2022)', metadata: { tags: [ 'formerly:1F0BB6EB5703B099', @@ -622,19 +552,11 @@ export const generateSimpleMarkets = () => { }, { id: '234afabd27e3bce1a879039c041f9f00f915d98459935ddafd0169d38dd13850', - name: 'Apple Monthly (30 Jun 2022)', state: 'Active', - data: { - market: { - id: '234afabd27e3bce1a879039c041f9f00f915d98459935ddafd0169d38dd13850', - state: 'STATE_ACTIVE', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'AAPL.MF21', + name: 'Apple Monthly (30 Jun 2022)', metadata: { tags: [ 'formerly:4899E01009F1A721', @@ -734,19 +656,11 @@ export const generateSimpleMarkets = () => { }, { id: '9f2a3c1caa67bb0773ec18d908d32b55b129b9ec2d106a8e9a87f6aa5c0375a6', - name: 'Tesla Quarterly (30 Jun 2022)', state: 'Active', - data: { - market: { - id: '9f2a3c1caa67bb0773ec18d908d32b55b129b9ec2d106a8e9a87f6aa5c0375a6', - state: 'STATE_ACTIVE', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'TSLA.QM21', + name: 'Tesla Quarterly (30 Jun 2022)', metadata: { tags: [ 'formerly:5A86B190C384997F', @@ -846,19 +760,11 @@ export const generateSimpleMarkets = () => { }, { id: '8a45ee934d3ddac4b036f9884df1064a5353c620a56f775ba36597d0edef9a7a', - name: 'Go big or Go home', state: 'Active', - data: { - market: { - id: '8a45ee934d3ddac4b036f9884df1064a5353c620a56f775ba36597d0edef9a7a', - state: 'STATE_SUSPENDED', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'LTCUSD', + name: 'Go big or Go home', metadata: { tags: [ 'base:litecoin', @@ -897,19 +803,11 @@ export const generateSimpleMarkets = () => { }, { id: 'aede7b9ac0c3b225004929c5455160a00f59864aad32ec366e8a2bff1b30fd0f', - name: 'BTCUSD Monthly (08 Jul 2022)', state: 'Active', - data: { - market: { - id: 'aede7b9ac0c3b225004929c5455160a00f59864aad32ec366e8a2bff1b30fd0f', - state: 'STATE_PROPOSED', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'BTCUSD.MF21', + name: 'BTCUSD Monthly (08 Jul 2022)', metadata: { tags: [ 'formerly:076BB86A5AA41E3E', @@ -935,19 +833,11 @@ export const generateSimpleMarkets = () => { }, { id: '9398707e01daa1a1f1ca6ff87cf8d6c03fe7373ce31121ce81b99a129e6bda47', - name: 'BTCUSD Monthly (18 Jul 2022)', state: 'Active', - data: { - market: { - id: '9398707e01daa1a1f1ca6ff87cf8d6c03fe7373ce31121ce81b99a129e6bda47', - state: 'STATE_PROPOSED', - __typename: 'Market', - }, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { code: 'BTCUSD.MF21', + name: 'BTCUSD Monthly (18 Jul 2022)', metadata: { tags: [ 'formerly:076BB86A5AA41E3E', @@ -978,16 +868,55 @@ export const generateSimpleMarkets = () => { export const generateLongListMarkets = (count: number) => { const markets = []; for (let i = 0; i < count; i++) { - const { id, name } = protoMarket; markets.push({ ...protoMarket, - id: id + i, - name: name + i, - data: { - ...protoMarket.data, - id: id + i, + id: protoMarket.id + i, + tradableInstrument: { + ...protoMarket.tradableInstrument, + instrument: { + ...protoMarket.tradableInstrument.instrument, + name: protoMarket.tradableInstrument.instrument.name + i, + }, }, }); } return { markets }; }; + +export const generateMarkets = (override?) => { + const markets = [ + { + ...protoMarket, + decimalPlaces: 5, + positionDecimalPlaces: 0, + tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, + state: MarketState.STATE_ACTIVE, + marketTimestamps: { + __typename: 'MarketTimestamps', + close: '', + open: '', + }, + fees: { + __typename: 'Fees', + factors: { + __typename: 'FeeFactors', + makerFee: '', + infrastructureFee: '', + liquidityFee: '', + }, + }, + }, + ]; + + const defaultResult = { + marketsConnection: { + __typename: 'MarketConnection', + edges: markets.map((node) => ({ + __typename: 'MarketEdge', + node, + })), + }, + }; + + return merge(defaultResult, override); +}; diff --git a/apps/console-lite/.eslintrc.json b/apps/console-lite/.eslintrc.json index db820c5d0..de2a9b877 100644 --- a/apps/console-lite/.eslintrc.json +++ b/apps/console-lite/.eslintrc.json @@ -1,6 +1,6 @@ { "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*", "__generated__"], + "ignorePatterns": ["!**/*", "__generated__", "__generated___"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], diff --git a/apps/console-lite/setup-tests.ts b/apps/console-lite/setup-tests.ts index adff1f883..9009d7b8c 100644 --- a/apps/console-lite/setup-tests.ts +++ b/apps/console-lite/setup-tests.ts @@ -1,7 +1,29 @@ import '@testing-library/jest-dom'; import { defaultFallbackInView } from 'react-intersection-observer'; +import ResizeObserver from 'resize-observer-polyfill'; defaultFallbackInView(true); +global.ResizeObserver = ResizeObserver; + +global.DOMRect = class DOMRect { + bottom = 0; + left = 0; + right = 0; + top = 0; + + constructor( + public x = 0, + public y = 0, + public width = 0, + public height = 0 + ) {} + static fromRect(other?: DOMRectInit): DOMRect { + return new DOMRect(other?.x, other?.y, other?.width, other?.height); + } + toJSON() { + return JSON.stringify(this); + } +}; Object.defineProperty(window, 'matchMedia', { writable: true, diff --git a/apps/console-lite/src/app/components/deal-ticket/MarketTags.graphql b/apps/console-lite/src/app/components/deal-ticket/MarketTags.graphql new file mode 100644 index 000000000..5026d5bd5 --- /dev/null +++ b/apps/console-lite/src/app/components/deal-ticket/MarketTags.graphql @@ -0,0 +1,11 @@ +query MarketTags($marketId: ID!) { + market(id: $marketId) { + tradableInstrument { + instrument { + metadata { + tags + } + } + } + } +} diff --git a/apps/console-lite/src/app/components/deal-ticket/PartyBalance.graphql b/apps/console-lite/src/app/components/deal-ticket/PartyBalance.graphql new file mode 100644 index 000000000..fc75976c0 --- /dev/null +++ b/apps/console-lite/src/app/components/deal-ticket/PartyBalance.graphql @@ -0,0 +1,14 @@ +query PartyBalanceQuery($partyId: ID!) { + party(id: $partyId) { + accounts { + type + balance + asset { + id + symbol + name + decimals + } + } + } +} diff --git a/apps/console-lite/src/app/components/deal-ticket/__generated___/MarketTags.ts b/apps/console-lite/src/app/components/deal-ticket/__generated___/MarketTags.ts new file mode 100644 index 000000000..d6b879f57 --- /dev/null +++ b/apps/console-lite/src/app/components/deal-ticket/__generated___/MarketTags.ts @@ -0,0 +1,54 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type MarketTagsQueryVariables = Types.Exact<{ + marketId: Types.Scalars['ID']; +}>; + + +export type MarketTagsQuery = { __typename?: 'Query', market?: { __typename?: 'Market', tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', metadata: { __typename?: 'InstrumentMetadata', tags?: Array | null } } } } | null }; + + +export const MarketTagsDocument = gql` + query MarketTags($marketId: ID!) { + market(id: $marketId) { + tradableInstrument { + instrument { + metadata { + tags + } + } + } + } +} + `; + +/** + * __useMarketTagsQuery__ + * + * To run a query within a React component, call `useMarketTagsQuery` and pass it any options that fit your needs. + * When your component renders, `useMarketTagsQuery` 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 } = useMarketTagsQuery({ + * variables: { + * marketId: // value for 'marketId' + * }, + * }); + */ +export function useMarketTagsQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(MarketTagsDocument, options); + } +export function useMarketTagsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(MarketTagsDocument, options); + } +export type MarketTagsQueryHookResult = ReturnType; +export type MarketTagsLazyQueryHookResult = ReturnType; +export type MarketTagsQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/console-lite/src/app/components/deal-ticket/__generated___/PartyBalance.ts b/apps/console-lite/src/app/components/deal-ticket/__generated___/PartyBalance.ts new file mode 100644 index 000000000..60fd8862f --- /dev/null +++ b/apps/console-lite/src/app/components/deal-ticket/__generated___/PartyBalance.ts @@ -0,0 +1,57 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type PartyBalanceQueryQueryVariables = Types.Exact<{ + partyId: Types.Scalars['ID']; +}>; + + +export type PartyBalanceQueryQuery = { __typename?: 'Query', party?: { __typename?: 'Party', accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } }> | null } | null }; + + +export const PartyBalanceQueryDocument = gql` + query PartyBalanceQuery($partyId: ID!) { + party(id: $partyId) { + accounts { + type + balance + asset { + id + symbol + name + decimals + } + } + } +} + `; + +/** + * __usePartyBalanceQueryQuery__ + * + * To run a query within a React component, call `usePartyBalanceQueryQuery` and pass it any options that fit your needs. + * When your component renders, `usePartyBalanceQueryQuery` 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 } = usePartyBalanceQueryQuery({ + * variables: { + * partyId: // value for 'partyId' + * }, + * }); + */ +export function usePartyBalanceQueryQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(PartyBalanceQueryDocument, options); + } +export function usePartyBalanceQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(PartyBalanceQueryDocument, options); + } +export type PartyBalanceQueryQueryHookResult = ReturnType; +export type PartyBalanceQueryLazyQueryHookResult = ReturnType; +export type PartyBalanceQueryQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/console-lite/src/app/components/deal-ticket/deal-ticket-estimates.tsx b/apps/console-lite/src/app/components/deal-ticket/deal-ticket-estimates.tsx index 97c450d29..21a842ffb 100644 --- a/apps/console-lite/src/app/components/deal-ticket/deal-ticket-estimates.tsx +++ b/apps/console-lite/src/app/components/deal-ticket/deal-ticket-estimates.tsx @@ -4,6 +4,7 @@ import { t } from '@vegaprotocol/react-helpers'; import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit'; import { IconNames } from '@blueprintjs/icons'; import * as constants from './constants'; +import { TrafficLight } from '../traffic-light'; interface DealTicketEstimatesProps { quoteName?: string; @@ -13,6 +14,7 @@ interface DealTicketEstimatesProps { fees?: string; notionalSize?: string; size?: string; + slippage?: string; } interface DataTitleProps { @@ -20,7 +22,7 @@ interface DataTitleProps { quoteName?: string; } -const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => ( +export const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => (
{children} {quoteName && ({quoteName})} @@ -28,14 +30,20 @@ const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => ( ); interface ValueTooltipProps { - value: string; + value?: string; + children?: ReactNode; description: string; id?: string; } -const ValueTooltipRow = ({ value, description, id }: ValueTooltipProps) => ( +export const ValueTooltipRow = ({ + value, + children, + description, + id, +}: ValueTooltipProps) => (
- {value} + {value || children}
(
{size && ( @@ -93,7 +102,7 @@ export const DealTicketEstimates = ({
)} {estMargin && ( -
+
{t('Est. Margin')} )} {estCloseOut && ( -
-
- {t('Est. Close out')} -   - ({quoteName}) -
+
+ {t('Est. Close out')}
)} + {slippage && ( +
+ {t('Est. Price Impact / Slippage')} + + + {slippage}% + + +
+ )} ); diff --git a/apps/console-lite/src/app/components/deal-ticket/deal-ticket-size-input.tsx b/apps/console-lite/src/app/components/deal-ticket/deal-ticket-size-input.tsx new file mode 100644 index 000000000..d3b594f38 --- /dev/null +++ b/apps/console-lite/src/app/components/deal-ticket/deal-ticket-size-input.tsx @@ -0,0 +1,149 @@ +import React, { useCallback, useState } from 'react'; +import { BigNumber } from 'bignumber.js'; +import { t } from '@vegaprotocol/react-helpers'; +import { + SliderRoot, + SliderThumb, + SliderTrack, + SliderRange, + FormGroup, +} from '@vegaprotocol/ui-toolkit'; +import { InputSetter } from '../input-setter'; + +interface DealTicketSizeInputProps { + step: number; + min: number; + max: number; + value: number; + onValueChange: (value: number) => void; + positionDecimalPlaces: number; +} + +const getSizeLabel = (value: number): string => { + const MIN_LABEL = 'Min'; + const MAX_LABEL = 'Max'; + if (value === 0) { + return MIN_LABEL; + } else if (value === 100) { + return MAX_LABEL; + } + + return `${value}%`; +}; + +export const DealTicketSizeInput = ({ + value, + step, + min, + max, + onValueChange, + positionDecimalPlaces, +}: DealTicketSizeInputProps) => { + const sizeRatios = [0, 25, 50, 75, 100]; + const [inputValue, setInputValue] = useState(value); + + const onInputValueChange = useCallback( + (event: React.ChangeEvent) => { + let value = parseFloat(event.target.value); + const isLessThanMin = value < min; + const isMoreThanMax = value > max; + if (isLessThanMin) { + value = min; + } else if (isMoreThanMax) { + value = max; + } + + if (value) { + onValueChange(value); + } + + setInputValue(value); + }, + [min, max, onValueChange, setInputValue] + ); + + const onButtonValueChange = (size: number) => { + const newVal = new BigNumber(size) + .decimalPlaces(positionDecimalPlaces) + .toNumber(); + onValueChange(newVal); + setInputValue(newVal); + }; + + const onSliderValueChange = useCallback( + (value: number[]) => { + const val = value[0]; + setInputValue(val); + onValueChange(val); + }, + [onValueChange] + ); + + return ( +
+
+ {min} + {max} +
+ + + + + + + +
+ {sizeRatios.map((size, index) => { + const proportionalSize = size ? (size / 100) * max : min; + return ( + + ); + })} +
+ +
+
+
{t('Contracts')}
+
+ + + {inputValue} + + +
+
+
+
+ ); +}; diff --git a/apps/console-lite/src/app/components/deal-ticket/deal-ticket-size.tsx b/apps/console-lite/src/app/components/deal-ticket/deal-ticket-size.tsx index 7ad66a31c..b95500df0 100644 --- a/apps/console-lite/src/app/components/deal-ticket/deal-ticket-size.tsx +++ b/apps/console-lite/src/app/components/deal-ticket/deal-ticket-size.tsx @@ -1,27 +1,13 @@ -import React, { useCallback, useState } from 'react'; -import classNames from 'classnames'; -import { IconNames } from '@blueprintjs/icons'; -import { t } from '@vegaprotocol/react-helpers'; -import { - SliderRoot, - SliderThumb, - SliderTrack, - SliderRange, - FormGroup, - Icon, - Tooltip, -} from '@vegaprotocol/ui-toolkit'; -import { BigNumber } from 'bignumber.js'; +import React from 'react'; import { DealTicketEstimates } from './deal-ticket-estimates'; -import { InputSetter } from '../input-setter'; -import * as constants from './constants'; +import { DealTicketSizeInput } from './deal-ticket-size-input'; interface DealTicketSizeProps { step: number; min: number; max: number; - value: number; - onValueChange: (value: number[]) => void; + size: number; + onSizeChange: (value: number) => void; name: string; quoteName: string; price: string; @@ -30,173 +16,33 @@ interface DealTicketSizeProps { fees: string; positionDecimalPlaces: number; notionalSize: string; - slippage: string | null; } -const getSizeLabel = (value: number): string => { - const MIN_LABEL = 'Min'; - const MAX_LABEL = 'Max'; - if (value === 0) { - return MIN_LABEL; - } else if (value === 100) { - return MAX_LABEL; - } - - return `${value}%`; -}; - export const DealTicketSize = ({ - value, step, min, max, price, quoteName, - onValueChange, + size, + onSizeChange, estCloseOut, positionDecimalPlaces, fees, notionalSize, - slippage, }: DealTicketSizeProps) => { - const sizeRatios = [0, 25, 50, 75, 100]; - const [inputValue, setInputValue] = useState(value); - - const onInputValueChange = useCallback( - (event: React.ChangeEvent) => { - const value = parseFloat(event.target.value); - const isLessThanMin = value < min; - const isMoreThanMax = value > max; - if (value) { - if (isLessThanMin) { - onValueChange([min]); - } else if (isMoreThanMax) { - onValueChange([max]); - } else { - onValueChange([value]); - } - } - setInputValue(value); - }, - [min, max, onValueChange, setInputValue] - ); - - const onButtonValueChange = useCallback( - (size: number) => { - const newVal = new BigNumber(size) - .decimalPlaces(positionDecimalPlaces) - .toNumber(); - onValueChange([newVal]); - setInputValue(newVal); - }, - [onValueChange, positionDecimalPlaces] - ); - - const onSliderValueChange = useCallback( - (value: number[]) => { - setInputValue(value[0]); - onValueChange(value); - }, - [onValueChange] - ); - return max === 0 ? (

Not enough balance to trade

) : (
-
- {min} - {max} -
- - - - - - - -
- {sizeRatios.map((size, index) => { - const proportionalSize = size ? (size / 100) * max : min; - return ( - - ); - })} -
- -
-
-
{t('Contracts')}
-
- - - -
-
-
- {slippage && ( -
-
-
{t('Est. Price Impact / Slippage')}
-
- = 1 && parseFloat(slippage) < 5, - 'text-vega-red': parseFloat(slippage) >= 5, - })} - > - {slippage}% - - -
- -
-
-
-
-
- )} + value={size} + onValueChange={onSizeChange} + positionDecimalPlaces={positionDecimalPlaces} + /> { + const [isDialogVisible, setIsDialogVisible] = useState(false); + + const onChange = useCallback( + (event: React.ChangeEvent) => { + const value = event.target.value; + const numericValue = parseFloat(value); + onValueChange(numericValue); + }, + [onValueChange] + ); + + const toggleDialog = useCallback(() => { + setIsDialogVisible(!isDialogVisible); + }, [isDialogVisible]); + + const formLabel = ( + + ); + + return ( + <> + +
+ {formLabel} + + {value}% + +
+
+
+
+ {t('Est. Price Impact / Slippage')} +
+
+ + + {value}% + + +
+ +
+
+
+ + ); +}; diff --git a/apps/console-lite/src/app/components/deal-ticket/deal-ticket-steps.tsx b/apps/console-lite/src/app/components/deal-ticket/deal-ticket-steps.tsx index e8b584fd2..078a50d76 100644 --- a/apps/console-lite/src/app/components/deal-ticket/deal-ticket-steps.tsx +++ b/apps/console-lite/src/app/components/deal-ticket/deal-ticket-steps.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useForm, Controller } from 'react-hook-form'; import { Stepper } from '../stepper'; @@ -10,7 +10,7 @@ import type { Order } from '@vegaprotocol/orders'; import { useVegaWallet, VegaTxStatus } from '@vegaprotocol/wallet'; import { t, - addDecimal, + addDecimalsFormatNumber, toDecimal, removeDecimal, } from '@vegaprotocol/react-helpers'; @@ -33,6 +33,8 @@ import useOrderCloseOut from '../../hooks/use-order-closeout'; import useOrderMargin from '../../hooks/use-order-margin'; import useMaximumPositionSize from '../../hooks/use-maximum-position-size'; import useCalculateSlippage from '../../hooks/use-calculate-slippage'; +import { Side, OrderType } from '@vegaprotocol/types'; +import { DealTicketSlippage } from './deal-ticket-slippage'; interface DealTicketMarketProps { market: DealTicketQuery_market; @@ -62,28 +64,26 @@ export const DealTicketSteps = ({ defaultValues: getDefaultOrder(market), }); - const [max, setMax] = useState(null); + const emptyString = ' - '; const step = toDecimal(market.positionDecimalPlaces); const orderType = watch('type'); const orderTimeInForce = watch('timeInForce'); const orderSide = watch('side'); const orderSize = watch('size'); const order = watch(); - const estCloseOut = useOrderCloseOut({ order, market, partyData }); + const { message: invalidText, isDisabled } = useOrderValidation({ + market, + orderType, + orderTimeInForce, + fieldErrors: errors, + }); + const { submit, transaction, finalizedOrder, Dialog } = useOrderSubmit(); const { keypair } = useVegaWallet(); const estMargin = useOrderMargin({ order, market, partyId: keypair?.pub || '', }); - const value = new BigNumber(orderSize).toNumber(); - const price = - market.depth.lastTrade && - addDecimal(market.depth.lastTrade.price, market.decimalPlaces); - const emptyString = ' - '; - - const [notionalSize, setNotionalSize] = useState(null); - const [fees, setFees] = useState(null); const maxTrade = useMaximumPositionSize({ partyId: keypair?.pub || '', @@ -94,46 +94,48 @@ export const DealTicketSteps = ({ price: market?.depth?.lastTrade?.price, order, }); + + const estCloseOut = useOrderCloseOut({ order, market, partyData }); const slippage = useCalculateSlippage({ marketId: market.id, order }); - useEffect(() => { - setMax( - new BigNumber(maxTrade) - .decimalPlaces(market.positionDecimalPlaces) - .toNumber() - ); - }, [maxTrade, market.positionDecimalPlaces]); - - const { message: invalidText, isDisabled } = useOrderValidation({ - market, - orderType, - orderTimeInForce, - fieldErrors: errors, - }); - - const { submit, transaction, finalizedOrder, TransactionDialog } = - useOrderSubmit(); - - const onSizeChange = (value: number[]) => { - const newVal = new BigNumber(value[0]) - .decimalPlaces(market.positionDecimalPlaces) - .toString(); - const isValid = validateSize(step)(newVal); - if (isValid !== 'step') { - setValue('size', newVal); - } - }; + const [slippageValue, setSlippageValue] = useState( + slippage ? parseFloat(slippage) : 0 + ); + const transactionStatus = + transaction.status === VegaTxStatus.Requested || + transaction.status === VegaTxStatus.Pending + ? 'pending' + : 'default'; useEffect(() => { - if (market?.depth?.lastTrade?.price) { - const size = new BigNumber(market.depth.lastTrade.price) - .multipliedBy(value) + setSlippageValue(slippage ? parseFloat(slippage) : 0); + }, [slippage]); + + const price = useMemo(() => { + if (slippage && market?.depth?.lastTrade?.price) { + const isLong = order.side === Side.SIDE_BUY; + const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus']( + parseFloat(slippage) / 100 + ); + return new BigNumber(market?.depth?.lastTrade?.price) + .multipliedBy(multiplier) .toNumber(); - - setNotionalSize(addDecimal(size, market.decimalPlaces)); } - }, [market, value]); + return null; + }, [market?.depth?.lastTrade?.price, order.side, slippage]); - useEffect(() => { + const formattedPrice = + price && addDecimalsFormatNumber(price, market.decimalPlaces); + + const notionalSize = useMemo(() => { + if (price) { + const size = new BigNumber(price).multipliedBy(orderSize).toNumber(); + + return addDecimalsFormatNumber(size, market.decimalPlaces); + } + return null; + }, [market.decimalPlaces, orderSize, price]); + + const fees = useMemo(() => { if (estMargin?.fees && notionalSize) { const percentage = new BigNumber(estMargin?.fees) .dividedBy(notionalSize) @@ -141,17 +143,66 @@ export const DealTicketSteps = ({ .decimalPlaces(2) .toString(); - setFees(`${estMargin.fees} (${percentage}%)`); + return `${estMargin.fees} (${percentage}%)`; } - }, [estMargin, notionalSize]); - const transactionStatus = - transaction.status === VegaTxStatus.Requested || - transaction.status === VegaTxStatus.Pending - ? 'pending' - : 'default'; + return null; + }, [estMargin?.fees, notionalSize]); - const onSubmit = React.useCallback( + const max = useMemo(() => { + return new BigNumber(maxTrade) + .decimalPlaces(market.positionDecimalPlaces) + .toNumber(); + }, [market.positionDecimalPlaces, maxTrade]); + + const onSizeChange = useCallback( + (value: number) => { + const newVal = new BigNumber(value) + .decimalPlaces(market.positionDecimalPlaces) + .toString(); + const isValid = validateSize(step)(newVal); + if (isValid !== 'step') { + setValue('size', newVal); + } + }, + [market.positionDecimalPlaces, setValue, step] + ); + + const onSlippageChange = useCallback( + (value: number) => { + if (market?.depth?.lastTrade?.price) { + if (value) { + const isLong = order.side === Side.SIDE_BUY; + const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus']( + value / 100 + ); + const bestAskPrice = new BigNumber(market?.depth?.lastTrade?.price) + .multipliedBy(multiplier) + .decimalPlaces(market.decimalPlaces) + .toString(); + + setValue('price', bestAskPrice); + + if (orderType === OrderType.TYPE_MARKET) { + setValue('type', OrderType.TYPE_LIMIT); + } + } else { + setValue('type', OrderType.TYPE_MARKET); + setValue('price', market?.depth?.lastTrade?.price); + } + } + setSlippageValue(value); + }, + [ + market.decimalPlaces, + market?.depth?.lastTrade?.price, + order.side, + orderType, + setValue, + ] + ); + + const onSubmit = useCallback( (order: Order) => { if (transactionStatus !== 'pending') { submit({ @@ -180,7 +231,7 @@ export const DealTicketSteps = ({ ItemRenderer={MarketNameRenderer} /> ), - value: market.name, + value: market.tradableInstrument.instrument.name, }, { label: t('Select Direction'), @@ -199,25 +250,30 @@ export const DealTicketSteps = ({ label: t('Choose Position Size'), component: max !== null ? ( - + <> + + + ) : ( 'loading...' ), @@ -241,21 +297,22 @@ export const DealTicketSteps = ({ order={order} estCloseOut={estCloseOut} estMargin={estMargin?.margin || emptyString} - price={price || emptyString} + price={formattedPrice || emptyString} quoteName={ market.tradableInstrument.instrument.product.settlementAsset .symbol } notionalSize={notionalSize || emptyString} fees={fees || emptyString} + slippage={slippageValue} /> - - +
), disabled: true, diff --git a/apps/console-lite/src/app/components/deal-ticket/review-trade.tsx b/apps/console-lite/src/app/components/deal-ticket/review-trade.tsx index 874d0cdd3..cfd0a50b5 100644 --- a/apps/console-lite/src/app/components/deal-ticket/review-trade.tsx +++ b/apps/console-lite/src/app/components/deal-ticket/review-trade.tsx @@ -43,6 +43,7 @@ interface Props { price: string; fees: string; notionalSize: string; + slippage: number; } export default ({ @@ -55,6 +56,7 @@ export default ({ fees, price, notionalSize, + slippage, }: Props) => { const { data: tagsData } = useQuery( MARKET_TAGS_QUERY, @@ -105,6 +107,7 @@ export default ({ fees={fees} estCloseOut={estCloseOut} notionalSize={notionalSize} + slippage={slippage.toString()} />
diff --git a/apps/console-lite/src/app/components/deposits/Deposits.graphql b/apps/console-lite/src/app/components/deposits/Deposits.graphql new file mode 100644 index 000000000..a60049458 --- /dev/null +++ b/apps/console-lite/src/app/components/deposits/Deposits.graphql @@ -0,0 +1,17 @@ +query Deposits { + assetsConnection { + edges { + node { + id + name + symbol + decimals + source { + ... on ERC20 { + contractAddress + } + } + } + } + } +} diff --git a/apps/console-lite/src/app/components/deposits/__generated__/Deposits.ts b/apps/console-lite/src/app/components/deposits/__generated__/Deposits.ts index f0b897c64..030cca1b1 100644 --- a/apps/console-lite/src/app/components/deposits/__generated__/Deposits.ts +++ b/apps/console-lite/src/app/components/deposits/__generated__/Deposits.ts @@ -3,6 +3,8 @@ // @generated // This file was automatically generated and should not be edited. +import { AssetStatus } from "@vegaprotocol/types"; + // ==================================================== // GraphQL query operation: Deposits // ==================================================== @@ -39,6 +41,10 @@ export interface Deposits_assetsConnection_edges_node { * 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) */ diff --git a/apps/console-lite/src/app/components/deposits/__generated___/Deposits.ts b/apps/console-lite/src/app/components/deposits/__generated___/Deposits.ts new file mode 100644 index 000000000..11720a480 --- /dev/null +++ b/apps/console-lite/src/app/components/deposits/__generated___/Deposits.ts @@ -0,0 +1,57 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type DepositsQueryVariables = Types.Exact<{ [key: string]: never; }>; + + +export type DepositsQuery = { __typename?: 'Query', assetsConnection: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string } } } | null> | null } }; + + +export const DepositsDocument = gql` + query Deposits { + assetsConnection { + edges { + node { + id + name + symbol + decimals + source { + ... on ERC20 { + contractAddress + } + } + } + } + } +} + `; + +/** + * __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: { + * }, + * }); + */ +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; \ No newline at end of file diff --git a/apps/console-lite/src/app/components/deposits/deposits.tsx b/apps/console-lite/src/app/components/deposits/deposits.tsx index c71f49d0f..ad2ed2d09 100644 --- a/apps/console-lite/src/app/components/deposits/deposits.tsx +++ b/apps/console-lite/src/app/components/deposits/deposits.tsx @@ -1,11 +1,10 @@ import { gql, useQuery } from '@apollo/client'; import { DepositManager } from '@vegaprotocol/deposits'; -import { t } from '@vegaprotocol/react-helpers'; +import { getEnabledAssets, t } 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 { assetsConnectionToAssets } from '@vegaprotocol/react-helpers'; import type { Deposits } from './__generated__/Deposits'; const DEPOSITS_QUERY = gql` @@ -17,6 +16,7 @@ const DEPOSITS_QUERY = gql` name symbol decimals + status source { ... on ERC20 { contractAddress @@ -40,7 +40,7 @@ export const DepositContainer = () => { skip: !keypair?.pub, }); - const assets = assetsConnectionToAssets(data?.assetsConnection); + const assets = getEnabledAssets(data); return ( data={data} loading={loading} error={error}> diff --git a/apps/console-lite/src/app/components/drawer/drawer.tsx b/apps/console-lite/src/app/components/drawer/drawer.tsx index 465124817..ef7fb9015 100644 --- a/apps/console-lite/src/app/components/drawer/drawer.tsx +++ b/apps/console-lite/src/app/components/drawer/drawer.tsx @@ -22,9 +22,8 @@ export const NavigationDrawer = ({ const width = 'w-full md:w-auto md:min-w-[15%] shrink-0'; const position = 'absolute inset-0 h-full z-10 md:static'; const background = 'bg-black/50 dark:bg-white/50'; - const border = 'border-r border-neutral-300 dark:border-neutral-700'; const flex = 'flex justify-end overflow-hidden'; - const joinedClasses = [flex, width, position, background, border].join(' '); + const joinedClasses = [flex, width, position, background].join(' '); const outerStyles = classNames(joinedClasses, { visible: isMenuOpen, diff --git a/apps/console-lite/src/app/components/header/header.tsx b/apps/console-lite/src/app/components/header/header.tsx index bb3586cfd..ebc7b8410 100644 --- a/apps/console-lite/src/app/components/header/header.tsx +++ b/apps/console-lite/src/app/components/header/header.tsx @@ -12,7 +12,7 @@ const Header = () => { } = useContext(LocalContext); return (
diff --git a/apps/console-lite/src/app/components/input-setter/input-setter.tsx b/apps/console-lite/src/app/components/input-setter/input-setter.tsx index 9e58f3f44..93a229d79 100644 --- a/apps/console-lite/src/app/components/input-setter/input-setter.tsx +++ b/apps/console-lite/src/app/components/input-setter/input-setter.tsx @@ -1,20 +1,19 @@ import React, { useCallback, useState } from 'react'; +import type { ReactNode } from 'react'; import { t } from '@vegaprotocol/react-helpers'; import { Input } from '@vegaprotocol/ui-toolkit'; import type { InputProps } from '@vegaprotocol/ui-toolkit'; interface InputSetterProps { buttonLabel?: string; - value: string | number; isInputVisible?: boolean; - onValueChange?: () => string; + children?: ReactNode; } export const InputSetter = ({ buttonLabel = t('set'), - value = '', isInputVisible = false, - onValueChange, + children, ...props }: InputSetterProps & InputProps) => { const [isInputToggled, setIsInputToggled] = useState(isInputVisible); @@ -35,7 +34,7 @@ export const InputSetter = ({ return isInputToggled ? (
- + ); }; diff --git a/apps/console-lite/src/app/components/nav/tab-bar.tsx b/apps/console-lite/src/app/components/nav/tab-bar.tsx index 25670222a..585967bd9 100644 --- a/apps/console-lite/src/app/components/nav/tab-bar.tsx +++ b/apps/console-lite/src/app/components/nav/tab-bar.tsx @@ -8,7 +8,7 @@ interface TabBarProps { export const TabBar = ({ className }: TabBarProps) => (
-
+
diff --git a/apps/console-lite/src/app/components/simple-market-list/Candles.graphql b/apps/console-lite/src/app/components/simple-market-list/Candles.graphql new file mode 100644 index 000000000..5ac33b8bc --- /dev/null +++ b/apps/console-lite/src/app/components/simple-market-list/Candles.graphql @@ -0,0 +1,5 @@ +subscription CandleLive($marketId: ID!) { + candles(marketId: $marketId, interval: INTERVAL_I1H) { + close + } +} diff --git a/apps/console-lite/src/app/components/simple-market-list/SimpleMarkets.graphql b/apps/console-lite/src/app/components/simple-market-list/SimpleMarkets.graphql new file mode 100644 index 000000000..ab6310ece --- /dev/null +++ b/apps/console-lite/src/app/components/simple-market-list/SimpleMarkets.graphql @@ -0,0 +1,44 @@ +fragment SimpleMarketDataFields on MarketData { + market { + id + state + } +} + +query SimpleMarkets($CandleSince: String!) { + markets { + id + name + state + data { + ...SimpleMarketDataFields + } + tradableInstrument { + instrument { + code + metadata { + tags + } + product { + __typename + ... on Future { + quoteName + settlementAsset { + symbol + } + } + } + } + } + candles(interval: INTERVAL_I1H, since: $CandleSince) { + open + close + } + } +} + +subscription SimpleMarketDataSub { + marketData { + ...SimpleMarketDataFields + } +} diff --git a/apps/console-lite/src/app/components/simple-market-list/__generated__/SimpleMarkets.ts b/apps/console-lite/src/app/components/simple-market-list/__generated__/SimpleMarkets.ts index 1e0ea0b65..97dc42767 100644 --- a/apps/console-lite/src/app/components/simple-market-list/__generated__/SimpleMarkets.ts +++ b/apps/console-lite/src/app/components/simple-market-list/__generated__/SimpleMarkets.ts @@ -9,26 +9,6 @@ import { MarketState } from "@vegaprotocol/types"; // GraphQL query operation: SimpleMarkets // ==================================================== -export interface SimpleMarkets_markets_data_market { - __typename: "Market"; - /** - * Market ID - */ - id: string; - /** - * Current state of the market - */ - state: MarketState; -} - -export interface SimpleMarkets_markets_data { - __typename: "MarketData"; - /** - * market ID of the associated mark price - */ - market: SimpleMarkets_markets_data_market; -} - export interface SimpleMarkets_markets_tradableInstrument_instrument_metadata { __typename: "InstrumentMetadata"; /** @@ -63,6 +43,10 @@ export interface SimpleMarkets_markets_tradableInstrument_instrument { * A short non necessarily unique code used to easily describe the instrument (e.g: FX:BTCUSD/DEC18) (string) */ code: string; + /** + * Full and fairly descriptive name for the instrument + */ + name: string; /** * Metadata for this instrument */ @@ -99,18 +83,10 @@ export interface SimpleMarkets_markets { * Market ID */ id: string; - /** - * Market full name - */ - name: string; /** * Current state of the market */ state: MarketState; - /** - * marketData for the given market - */ - data: SimpleMarkets_markets_data | null; /** * An instance of, or reference to, a tradable instrument. */ diff --git a/apps/console-lite/src/app/components/simple-market-list/__generated___/Candles.ts b/apps/console-lite/src/app/components/simple-market-list/__generated___/Candles.ts new file mode 100644 index 000000000..a69c128f3 --- /dev/null +++ b/apps/console-lite/src/app/components/simple-market-list/__generated___/Candles.ts @@ -0,0 +1,43 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type CandleLiveSubscriptionVariables = Types.Exact<{ + marketId: Types.Scalars['ID']; +}>; + + +export type CandleLiveSubscription = { __typename?: 'Subscription', candles: { __typename?: 'Candle', close: string } }; + + +export const CandleLiveDocument = gql` + subscription CandleLive($marketId: ID!) { + candles(marketId: $marketId, interval: INTERVAL_I1H) { + close + } +} + `; + +/** + * __useCandleLiveSubscription__ + * + * To run a query within a React component, call `useCandleLiveSubscription` and pass it any options that fit your needs. + * When your component renders, `useCandleLiveSubscription` 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 } = useCandleLiveSubscription({ + * variables: { + * marketId: // value for 'marketId' + * }, + * }); + */ +export function useCandleLiveSubscription(baseOptions: Apollo.SubscriptionHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useSubscription(CandleLiveDocument, options); + } +export type CandleLiveSubscriptionHookResult = ReturnType; +export type CandleLiveSubscriptionResult = Apollo.SubscriptionResult; \ No newline at end of file diff --git a/apps/console-lite/src/app/components/simple-market-list/__generated___/SimpleMarkets.ts b/apps/console-lite/src/app/components/simple-market-list/__generated___/SimpleMarkets.ts new file mode 100644 index 000000000..fa5e240ac --- /dev/null +++ b/apps/console-lite/src/app/components/simple-market-list/__generated___/SimpleMarkets.ts @@ -0,0 +1,117 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type SimpleMarketDataFieldsFragment = { __typename?: 'MarketData', market: { __typename?: 'Market', id: string, state: Types.MarketState } }; + +export type SimpleMarketsQueryVariables = Types.Exact<{ + CandleSince: Types.Scalars['String']; +}>; + + +export type SimpleMarketsQuery = { __typename?: 'Query', markets?: Array<{ __typename?: 'Market', id: string, name: string, state: Types.MarketState, data?: { __typename?: 'MarketData', market: { __typename?: 'Market', id: string, state: Types.MarketState } } | null, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array | null }, product: { __typename: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', symbol: string } } } }, candles?: Array<{ __typename?: 'Candle', open: string, close: string } | null> | null }> | null }; + +export type SimpleMarketDataSubSubscriptionVariables = Types.Exact<{ [key: string]: never; }>; + + +export type SimpleMarketDataSubSubscription = { __typename?: 'Subscription', marketData: { __typename?: 'MarketData', market: { __typename?: 'Market', id: string, state: Types.MarketState } } }; + +export const SimpleMarketDataFieldsFragmentDoc = gql` + fragment SimpleMarketDataFields on MarketData { + market { + id + state + } +} + `; +export const SimpleMarketsDocument = gql` + query SimpleMarkets($CandleSince: String!) { + markets { + id + name + state + data { + ...SimpleMarketDataFields + } + tradableInstrument { + instrument { + code + metadata { + tags + } + product { + __typename + ... on Future { + quoteName + settlementAsset { + symbol + } + } + } + } + } + candles(interval: INTERVAL_I1H, since: $CandleSince) { + open + close + } + } +} + ${SimpleMarketDataFieldsFragmentDoc}`; + +/** + * __useSimpleMarketsQuery__ + * + * To run a query within a React component, call `useSimpleMarketsQuery` and pass it any options that fit your needs. + * When your component renders, `useSimpleMarketsQuery` 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 } = useSimpleMarketsQuery({ + * variables: { + * CandleSince: // value for 'CandleSince' + * }, + * }); + */ +export function useSimpleMarketsQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(SimpleMarketsDocument, options); + } +export function useSimpleMarketsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(SimpleMarketsDocument, options); + } +export type SimpleMarketsQueryHookResult = ReturnType; +export type SimpleMarketsLazyQueryHookResult = ReturnType; +export type SimpleMarketsQueryResult = Apollo.QueryResult; +export const SimpleMarketDataSubDocument = gql` + subscription SimpleMarketDataSub { + marketData { + ...SimpleMarketDataFields + } +} + ${SimpleMarketDataFieldsFragmentDoc}`; + +/** + * __useSimpleMarketDataSubSubscription__ + * + * To run a query within a React component, call `useSimpleMarketDataSubSubscription` and pass it any options that fit your needs. + * When your component renders, `useSimpleMarketDataSubSubscription` 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 } = useSimpleMarketDataSubSubscription({ + * variables: { + * }, + * }); + */ +export function useSimpleMarketDataSubSubscription(baseOptions?: Apollo.SubscriptionHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useSubscription(SimpleMarketDataSubDocument, options); + } +export type SimpleMarketDataSubSubscriptionHookResult = ReturnType; +export type SimpleMarketDataSubSubscriptionResult = Apollo.SubscriptionResult; \ No newline at end of file diff --git a/apps/console-lite/src/app/components/simple-market-list/constants.ts b/apps/console-lite/src/app/components/simple-market-list/constants.ts index 523dca420..d834f7239 100644 --- a/apps/console-lite/src/app/components/simple-market-list/constants.ts +++ b/apps/console-lite/src/app/components/simple-market-list/constants.ts @@ -195,3 +195,5 @@ export const ROW_CLASS_RULES = { 'cursor-pointer': ({ data }: { data: SimpleMarkets_markets }) => IS_MARKET_TRADABLE(data || {}), }; + +export const LARGE_SCREENS = ['xl', 'xxl']; diff --git a/apps/console-lite/src/app/components/simple-market-list/data-provider.ts b/apps/console-lite/src/app/components/simple-market-list/data-provider.ts index 67a5d294e..5be5b70fe 100644 --- a/apps/console-lite/src/app/components/simple-market-list/data-provider.ts +++ b/apps/console-lite/src/app/components/simple-market-list/data-provider.ts @@ -10,28 +10,15 @@ import type { SimpleMarketDataSub_marketData, } from './__generated__/SimpleMarketDataSub'; -const MARKET_DATA_FRAGMENT = gql` - fragment SimpleMarketDataFields on MarketData { - market { - id - state - } - } -`; - export const MARKETS_QUERY = gql` - ${MARKET_DATA_FRAGMENT} query SimpleMarkets($CandleSince: String!) { markets { id - name state - data { - ...SimpleMarketDataFields - } tradableInstrument { instrument { code + name metadata { tags } @@ -55,10 +42,12 @@ export const MARKETS_QUERY = gql` `; const MARKET_DATA_SUB = gql` - ${MARKET_DATA_FRAGMENT} subscription SimpleMarketDataSub { marketData { - ...SimpleMarketDataFields + market { + id + state + } } } `; @@ -78,7 +67,7 @@ const update = ( return produce(data, (draft) => { const index = draft.findIndex((m) => m.id === delta.market.id); if (index !== -1) { - draft[index].data = delta; + draft[index].state = delta.market.state; } // @TODO - else push new market to draft }); diff --git a/apps/console-lite/src/app/components/simple-market-list/simple-market-list.spec.tsx b/apps/console-lite/src/app/components/simple-market-list/simple-market-list.spec.tsx index 22caa75ee..ff4ce6cc7 100644 --- a/apps/console-lite/src/app/components/simple-market-list/simple-market-list.spec.tsx +++ b/apps/console-lite/src/app/components/simple-market-list/simple-market-list.spec.tsx @@ -6,17 +6,19 @@ import { waitFor, cleanup, getAllByRole, + fireEvent, } from '@testing-library/react'; import { MockedProvider } from '@apollo/client/testing'; import type { MockedResponse } from '@apollo/client/testing'; import { BrowserRouter } from 'react-router-dom'; +import { MarketState } from '@vegaprotocol/types'; import SimpleMarketList from './simple-market-list'; import { MARKETS_QUERY } from './data-provider'; import type { SimpleMarkets_markets, SimpleMarkets, } from './__generated__/SimpleMarkets'; -import { MarketState } from '@vegaprotocol/types'; +import type { SimpleMarketDataSub_marketData } from './__generated__/SimpleMarketDataSub'; const mockedNavigate = jest.fn(); @@ -30,93 +32,85 @@ jest.mock('date-fns', () => ({ subDays: () => new Date('2022-06-02T11:11:21.721Z'), })); +let updateMock: ({ + delta, +}: { + delta: SimpleMarketDataSub_marketData; +}) => boolean; + +let mockData = [ + { + id: '1', + name: 'Market 1', + state: MarketState.STATE_ACTIVE, + tradableInstrument: { + instrument: { + product: { + settlementAsset: { + symbol: 'tUSD', + }, + }, + metadata: { + tags: [], + }, + }, + }, + }, + { + id: '2', + name: 'Market 2', + state: MarketState.STATE_ACTIVE, + tradableInstrument: { + instrument: { + product: { + settlementAsset: { + symbol: 'ETH', + }, + }, + metadata: { + tags: [], + }, + }, + }, + }, +] as unknown as SimpleMarkets_markets[]; + +const mockUseDataProvider = ({ update }: { update: () => boolean }) => { + updateMock = update; + return { data: mockData, loading: false, error: false }; +}; + +jest.mock('@vegaprotocol/react-helpers', () => ({ + ...jest.requireActual('@vegaprotocol/react-helpers'), + useDataProvider: jest.fn((args) => mockUseDataProvider(args)), +})); + +const mockIsTradable = jest.fn((_arg) => true); + +jest.mock('../../constants', () => ({ + ...jest.requireActual('../../constants'), + IS_MARKET_TRADABLE: jest.fn((arg) => mockIsTradable(arg)), +})); + describe('SimpleMarketList', () => { afterEach(() => { jest.clearAllMocks(); cleanup(); }); - it('should be properly renderer as empty', async () => { - const mocks: MockedResponse = { - request: { - query: MARKETS_QUERY, - variables: { - CandleSince: '2022-06-02T11:11:21.721Z', - }, + const mocks: MockedResponse = { + request: { + query: MARKETS_QUERY, + variables: { + CandleSince: '2022-06-02T11:11:21.721Z', }, - result: { - data: { markets: [] }, - }, - }; - await act(async () => { - render( - - - , - { wrapper: BrowserRouter } - ); - await new Promise((resolve) => setTimeout(resolve, 0)); - }); - await waitFor(() => { - expect(screen.getByText('No data to display')).toBeInTheDocument(); - }); - }); + }, + result: { + data: { markets: mockData }, + }, + }; it('should be properly rendered with some data', async () => { - const data = [ - { - id: '1', - data: { - market: { - state: MarketState.STATE_ACTIVE, - }, - }, - tradableInstrument: { - instrument: { - product: { - settlementAsset: { - symbol: 'tUSD', - }, - }, - metadata: { - tags: [], - }, - }, - }, - }, - { - id: '2', - data: { - market: { - state: MarketState.STATE_ACTIVE, - }, - }, - tradableInstrument: { - instrument: { - product: { - settlementAsset: { - symbol: 'ETH', - }, - }, - metadata: { - tags: [], - }, - }, - }, - }, - ] as unknown as SimpleMarkets_markets[]; - - const mocks: MockedResponse = { - request: { - query: MARKETS_QUERY, - variables: { - CandleSince: '2022-06-02T11:11:21.721Z', - }, - }, - result: { - data: { markets: data }, - }, - }; await act(async () => { render( @@ -136,4 +130,92 @@ describe('SimpleMarketList', () => { expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(2); }); }); + + it('update should return proper boolean value', async () => { + await act(async () => { + render( + + + , + { wrapper: BrowserRouter } + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + }); + await waitFor(() => { + expect( + document.querySelector('.ag-center-cols-container') + ).toBeInTheDocument(); + }); + + await expect( + updateMock({ + delta: { + __typename: 'MarketData', + market: { + __typename: 'Market', + id: '2', + state: MarketState.STATE_ACTIVE, + }, + }, + }) + ).toEqual(true); + + await expect( + updateMock({ + delta: { + __typename: 'MarketData', + market: { + __typename: 'Market', + id: '2', + state: MarketState.STATE_SUSPENDED, + }, + }, + }) + ).toEqual(false); + }); + + it('click on row should be properly handled', async () => { + await act(async () => { + render( + + + , + { wrapper: BrowserRouter } + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + }); + await waitFor(() => { + expect( + document.querySelector('.ag-center-cols-container') + ).toBeInTheDocument(); + }); + mockIsTradable.mockClear(); + const container = document.querySelector('.ag-center-cols-container'); + const firstRow = getAllByRole(container as HTMLDivElement, 'row')[0]; + expect(firstRow).toHaveAttribute('row-id', '1'); + fireEvent.click(firstRow); + await waitFor(() => { + expect(mockIsTradable).toHaveBeenCalledWith({ + ...mockData[0], + percentChange: '-', + }); + expect(mockedNavigate).toHaveBeenCalledWith(`/trading/${mockData[0].id}`); + }); + }); + + it('should be properly renderer as empty', async () => { + mockData = []; + await act(async () => { + render( + + + , + { wrapper: BrowserRouter } + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + }); + await waitFor(() => { + expect(screen.getByText('No data to display')).toBeInTheDocument(); + }); + }); }); 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 c42d935d3..0161cfaea 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 @@ -45,7 +45,7 @@ export type RouterParams = Partial<{ }>; const SimpleMarketList = () => { - const { isMobile } = useScreenDimensions(); + const { isMobile, screenSize } = useScreenDimensions(); const navigate = useNavigate(); const params = useParams(); const theme = useContext(ThemeContext); @@ -80,7 +80,7 @@ const SimpleMarketList = () => { useEffect(() => { const statuses: Record = {}; data?.forEach((market) => { - statuses[market.id] = market.data?.market.state || ''; + statuses[market.id] = market.state || ''; }); statusesRef.current = statuses; }, [data, statusesRef]); @@ -129,6 +129,10 @@ const SimpleMarketList = () => { [handleRowClicked] ); + const shouldSuppressHorizontalScroll = useMemo(() => { + return !isMobile && constants.LARGE_SCREENS.includes(screenSize); + }, [isMobile, screenSize]); + return (
@@ -156,6 +160,7 @@ const SimpleMarketList = () => { suppressRowTransform onCellKeyDown={onCellKeyDown} tabToNextCell={onTabToNextCell} + suppressHorizontalScroll={shouldSuppressHorizontalScroll} />
diff --git a/apps/console-lite/src/app/components/simple-market-list/simple-market-renderer.spec.tsx b/apps/console-lite/src/app/components/simple-market-list/simple-market-renderer.spec.tsx new file mode 100644 index 000000000..e880de146 --- /dev/null +++ b/apps/console-lite/src/app/components/simple-market-list/simple-market-renderer.spec.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import type { MarketNames_markets } from '@vegaprotocol/deal-ticket'; +import { MarketState } from '@vegaprotocol/types'; +import MarketNameRenderer from './simple-market-renderer'; + +describe('SimpleMarketRenderer', () => { + const market = { + id: 'marketId', + state: MarketState.STATE_ACTIVE, + tradableInstrument: { + instrument: { + code: 'Market code', + name: 'Market Name', + product: { + quoteName: 'Quote name', + }, + metadata: { + tags: null, + }, + }, + }, + } as MarketNames_markets; + + it('should properly render not mobile', () => { + render(); + expect(screen.getByText('Market Name')).toBeInTheDocument(); + expect(screen.getByText('Quote name')).toBeInTheDocument(); + }); + + it('should properly render mobile', () => { + render(); + expect(screen.getByText('Market code')).toBeInTheDocument(); + expect(screen.getByText('Quote name')).toBeInTheDocument(); + }); +}); diff --git a/apps/console-lite/src/app/components/simple-market-list/simple-market-renderer.tsx b/apps/console-lite/src/app/components/simple-market-list/simple-market-renderer.tsx index 0b68f24ea..9283f2972 100644 --- a/apps/console-lite/src/app/components/simple-market-list/simple-market-renderer.tsx +++ b/apps/console-lite/src/app/components/simple-market-list/simple-market-renderer.tsx @@ -17,7 +17,9 @@ const MarketNameRenderer = ({ market, isMobile }: Props) => { )} />
- {isMobile ? market.tradableInstrument.instrument.code : market.name}{' '} + {isMobile + ? market.tradableInstrument.instrument.code + : market.tradableInstrument.instrument.name}{' '} diff --git a/apps/console-lite/src/app/components/simple-market-list/simple-market-toolbar.spec.tsx b/apps/console-lite/src/app/components/simple-market-list/simple-market-toolbar.spec.tsx index 301fad0f9..f3a35acf5 100644 --- a/apps/console-lite/src/app/components/simple-market-list/simple-market-toolbar.spec.tsx +++ b/apps/console-lite/src/app/components/simple-market-list/simple-market-toolbar.spec.tsx @@ -1,11 +1,35 @@ import React from 'react'; -import { useLocation, useRoutes, BrowserRouter } from 'react-router-dom'; -import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { + useLocation, + useRoutes, + BrowserRouter, + useParams, +} from 'react-router-dom'; +import { + render, + screen, + fireEvent, + waitFor, + act, + getAllByText, +} from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; +import { MarketState } from '@vegaprotocol/types'; import SimpleMarketToolbar from './simple-market-toolbar'; import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets'; import { markets as filterData } from './mocks/market-filters.json'; +const mockedNavigate = jest.fn(); + +jest.mock('react-router-dom', () => { + const actualRouter = jest.requireActual('react-router-dom'); + return { + ...actualRouter, + useNavigate: () => mockedNavigate, + useParams: jest.fn(() => actualRouter.useParams()), + }; +}); + describe('SimpleMarketToolbar', () => { const WrappedCompForTest = () => { const routes = useRoutes([ @@ -60,9 +84,8 @@ describe('SimpleMarketToolbar', () => { ); }; - afterEach(() => { - jest.resetAllMocks(); + jest.clearAllMocks(); }); it('should be properly rendered', async () => { @@ -83,7 +106,7 @@ describe('SimpleMarketToolbar', () => { expect(screen.getByTestId('market-assets-menu').children).toHaveLength(6); }); fireEvent.click(screen.getByTestId('state-trigger')); - waitFor(() => { + await waitFor(() => { expect(screen.getByRole('menu')).toBeInTheDocument(); expect(screen.getByRole('menu').children).toHaveLength(10); }); @@ -104,7 +127,7 @@ describe('SimpleMarketToolbar', () => { await waitFor(() => { expect(screen.getByTestId('location-display')).toHaveTextContent( - '/markets/STATE_ACTIVE/Future' + `/markets/${MarketState.STATE_ACTIVE}/Future` ); }); @@ -115,17 +138,91 @@ describe('SimpleMarketToolbar', () => { ); await waitFor(() => { expect(screen.getByTestId('location-display')).toHaveTextContent( - '/markets/STATE_ACTIVE/Future/tEURO' + `/markets/${MarketState.STATE_ACTIVE}/Future/tEURO` ); }); fireEvent.click(screen.getByTestId('state-trigger')); - waitFor(() => { + await waitFor(() => { expect(screen.getByRole('menu')).toBeInTheDocument(); - fireEvent.click(screen.getByText('Pending')); - expect(screen.getByTestId('location-display')).toHaveTextContent( - '/markets/Pending/Future/tEURO' + }); + const menu = screen.getByRole('menu'); + const pending = getAllByText(menu, 'Pending')[0]; + await act(() => { + fireEvent.click(pending); + }); + await waitFor(() => { + expect(mockedNavigate).toHaveBeenCalledWith( + `/markets/${MarketState.STATE_PENDING}/Future/tEURO` ); }); }); + + it('stateChange callback should work well', async () => { + (useParams as jest.Mock).mockImplementation(() => ({ + asset: 'asset1', + product: 'product1', + state: 'state1', + })); + render( + + + , + { wrapper: BrowserRouter } + ); + fireEvent.click(screen.getByTestId('state-trigger')); + await waitFor(() => { + expect(screen.getByRole('menu')).toBeInTheDocument(); + }); + const menu = screen.getByRole('menu'); + const suspended = getAllByText(menu, 'Suspended')[0]; + fireEvent.click(suspended); + + expect(mockedNavigate).toHaveBeenCalledWith( + `/markets/${MarketState.STATE_SUSPENDED}/product1/asset1` + ); + }); + + it('stateChange callback should call navigate with url with state only', async () => { + (useParams as jest.Mock).mockImplementation(() => ({})); + render( + + + , + { wrapper: BrowserRouter } + ); + fireEvent.click(screen.getByTestId('state-trigger')); + await waitFor(() => { + expect(screen.getByRole('menu')).toBeInTheDocument(); + }); + const menu = screen.getByRole('menu'); + const closed = getAllByText(menu, 'Closed')[0]; + fireEvent.click(closed); + + expect(mockedNavigate).toHaveBeenCalledWith( + `/markets/${MarketState.STATE_CLOSED}` + ); + }); + + it('stateChange callback should call navigate with no asset', async () => { + (useParams as jest.Mock).mockImplementation(() => ({ + asset: 'all', + state: 'state1', + })); + render( + + + , + { wrapper: BrowserRouter } + ); + fireEvent.click(screen.getByTestId('state-trigger')); + await waitFor(() => { + expect(screen.getByRole('menu')).toBeInTheDocument(); + }); + + const menu = screen.getByRole('menu'); + const active = getAllByText(menu, 'Active')[0]; + fireEvent.click(active); + expect(mockedNavigate).toHaveBeenCalledWith('/markets'); + }); }); diff --git a/apps/console-lite/src/app/components/simple-market-list/simple-market-toolbar.tsx b/apps/console-lite/src/app/components/simple-market-list/simple-market-toolbar.tsx index b87dbddab..8b04978c7 100644 --- a/apps/console-lite/src/app/components/simple-market-list/simple-market-toolbar.tsx +++ b/apps/console-lite/src/app/components/simple-market-list/simple-market-toolbar.tsx @@ -75,7 +75,7 @@ const SimpleMarketToolbar = ({ data }: Props) => { ); return ( -
+
    { style={sliderStyles} />
-
-
- setOpen(open)}> +
+
+ setOpen(open)}> setOpen(!isOpen)} >
{STATES_FILTER.find( @@ -148,7 +149,7 @@ const SimpleMarketToolbar = ({ data }: Props) => { {STATES_FILTER.map(({ value, text }) => ( {
{activeNumber > 0 && (
    diff --git a/apps/console-lite/src/app/components/stepper/stepper.tsx b/apps/console-lite/src/app/components/stepper/stepper.tsx index 1cdfd35c8..91909d616 100644 --- a/apps/console-lite/src/app/components/stepper/stepper.tsx +++ b/apps/console-lite/src/app/components/stepper/stepper.tsx @@ -88,7 +88,7 @@ export const Stepper = ({ steps }: StepperProps) => { 'md:mt-0 font-alpha uppercase text-black dark:text-white', { 'mt-2 text-md md:text-2xl': isActive, - 'mt-4 text-sm md:text-lg md:ml-8': !isActive, + 'mt-4 text-sm md:text-lg md:ml-2': !isActive, } )} > diff --git a/apps/console-lite/src/app/components/traffic-light/index.ts b/apps/console-lite/src/app/components/traffic-light/index.ts new file mode 100644 index 000000000..f3a7e5c0c --- /dev/null +++ b/apps/console-lite/src/app/components/traffic-light/index.ts @@ -0,0 +1 @@ +export * from './traffic-light'; diff --git a/apps/console-lite/src/app/components/traffic-light/traffic-light.tsx b/apps/console-lite/src/app/components/traffic-light/traffic-light.tsx new file mode 100644 index 000000000..6d2e199bc --- /dev/null +++ b/apps/console-lite/src/app/components/traffic-light/traffic-light.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import type { ReactNode } from 'react'; +import classNames from 'classnames'; + +interface TrafficLightProps { + value: number; + q1: number; + q2: number; + children: ReactNode; +} + +export const TrafficLight = ({ + value, + q1, + q2, + children, +}: TrafficLightProps) => { + const slippageClassName = classNames({ + 'text-darkerGreen dark:text-lightGreen': value < q1, + 'text-amber': value >= q1 && value < q2, + 'text-vega-red': value >= q2, + }); + + return
    {children || value}
    ; +}; diff --git a/apps/console-lite/src/app/constants/index.ts b/apps/console-lite/src/app/constants/index.ts index feaea0f08..fc26ee723 100644 --- a/apps/console-lite/src/app/constants/index.ts +++ b/apps/console-lite/src/app/constants/index.ts @@ -10,7 +10,7 @@ export const TRADABLE_STATES = { }; export const IS_MARKET_TRADABLE = (market: SimpleMarkets_markets) => - Boolean((market.data?.market.state ?? '') in TRADABLE_STATES && market?.id); + Boolean((market.state ?? '') in TRADABLE_STATES && market?.id); export const MARKET_STATES_MAP: Record = { [MarketState.STATE_ACTIVE]: t('Active'), diff --git a/apps/console-lite/src/app/hooks/EstimateOrder.graphql b/apps/console-lite/src/app/hooks/EstimateOrder.graphql new file mode 100644 index 000000000..0f9ba762c --- /dev/null +++ b/apps/console-lite/src/app/hooks/EstimateOrder.graphql @@ -0,0 +1,30 @@ +query EstimateOrder( + $marketId: ID! + $partyId: ID! + $price: String + $size: String! + $side: Side! + $timeInForce: OrderTimeInForce! + $expiration: String + $type: OrderType! +) { + estimateOrder( + marketId: $marketId + partyId: $partyId + price: $price + size: $size + side: $side + timeInForce: $timeInForce + expiration: $expiration + type: $type + ) { + fee { + makerFee + infrastructureFee + liquidityFee + } + marginLevels { + initialLevel + } + } +} diff --git a/apps/console-lite/src/app/hooks/MarketMarkPrice.graphql b/apps/console-lite/src/app/hooks/MarketMarkPrice.graphql new file mode 100644 index 000000000..6cca545c8 --- /dev/null +++ b/apps/console-lite/src/app/hooks/MarketMarkPrice.graphql @@ -0,0 +1,8 @@ +query MarketMarkPrice($marketId: ID!) { + market(id: $marketId) { + decimalPlaces + data { + markPrice + } + } +} diff --git a/apps/console-lite/src/app/hooks/MarketPositions.graphql b/apps/console-lite/src/app/hooks/MarketPositions.graphql new file mode 100644 index 000000000..55b5323de --- /dev/null +++ b/apps/console-lite/src/app/hooks/MarketPositions.graphql @@ -0,0 +1,25 @@ +query MarketPositions($partyId: ID!) { + party(id: $partyId) { + id + accounts { + type + balance + asset { + decimals + } + market { + id + } + } + positionsConnection { + edges { + node { + openVolume + market { + id + } + } + } + } + } +} diff --git a/apps/console-lite/src/app/hooks/PartyMarketData.graphql b/apps/console-lite/src/app/hooks/PartyMarketData.graphql new file mode 100644 index 000000000..dfd7daff4 --- /dev/null +++ b/apps/console-lite/src/app/hooks/PartyMarketData.graphql @@ -0,0 +1,28 @@ +query PartyMarketData($partyId: ID!) { + party(id: $partyId) { + id + accounts { + type + balance + asset { + id + decimals + } + market { + id + } + } + marginsConnection { + edges { + node { + market { + id + } + initialLevel + maintenanceLevel + searchLevel + } + } + } + } +} diff --git a/apps/console-lite/src/app/hooks/__generated___/EstimateOrder.ts b/apps/console-lite/src/app/hooks/__generated___/EstimateOrder.ts new file mode 100644 index 000000000..8a51585dc --- /dev/null +++ b/apps/console-lite/src/app/hooks/__generated___/EstimateOrder.ts @@ -0,0 +1,78 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type EstimateOrderQueryVariables = Types.Exact<{ + marketId: Types.Scalars['ID']; + partyId: Types.Scalars['ID']; + price?: Types.InputMaybe; + size: Types.Scalars['String']; + side: Types.Side; + timeInForce: Types.OrderTimeInForce; + expiration?: Types.InputMaybe; + type: Types.OrderType; +}>; + + +export type EstimateOrderQuery = { __typename?: 'Query', estimateOrder: { __typename?: 'OrderEstimate', fee: { __typename?: 'TradeFee', makerFee: string, infrastructureFee: string, liquidityFee: string }, marginLevels: { __typename?: 'MarginLevels', initialLevel: string } } }; + + +export const EstimateOrderDocument = gql` + query EstimateOrder($marketId: ID!, $partyId: ID!, $price: String, $size: String!, $side: Side!, $timeInForce: OrderTimeInForce!, $expiration: String, $type: OrderType!) { + estimateOrder( + marketId: $marketId + partyId: $partyId + price: $price + size: $size + side: $side + timeInForce: $timeInForce + expiration: $expiration + type: $type + ) { + fee { + makerFee + infrastructureFee + liquidityFee + } + marginLevels { + initialLevel + } + } +} + `; + +/** + * __useEstimateOrderQuery__ + * + * To run a query within a React component, call `useEstimateOrderQuery` and pass it any options that fit your needs. + * When your component renders, `useEstimateOrderQuery` 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 } = useEstimateOrderQuery({ + * variables: { + * marketId: // value for 'marketId' + * partyId: // value for 'partyId' + * price: // value for 'price' + * size: // value for 'size' + * side: // value for 'side' + * timeInForce: // value for 'timeInForce' + * expiration: // value for 'expiration' + * type: // value for 'type' + * }, + * }); + */ +export function useEstimateOrderQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(EstimateOrderDocument, options); + } +export function useEstimateOrderLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(EstimateOrderDocument, options); + } +export type EstimateOrderQueryHookResult = ReturnType; +export type EstimateOrderLazyQueryHookResult = ReturnType; +export type EstimateOrderQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/console-lite/src/app/hooks/__generated___/MarketMarkPrice.ts b/apps/console-lite/src/app/hooks/__generated___/MarketMarkPrice.ts new file mode 100644 index 000000000..666870091 --- /dev/null +++ b/apps/console-lite/src/app/hooks/__generated___/MarketMarkPrice.ts @@ -0,0 +1,51 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type MarketMarkPriceQueryVariables = Types.Exact<{ + marketId: Types.Scalars['ID']; +}>; + + +export type MarketMarkPriceQuery = { __typename?: 'Query', market?: { __typename?: 'Market', decimalPlaces: number, data?: { __typename?: 'MarketData', markPrice: string } | null } | null }; + + +export const MarketMarkPriceDocument = gql` + query MarketMarkPrice($marketId: ID!) { + market(id: $marketId) { + decimalPlaces + data { + markPrice + } + } +} + `; + +/** + * __useMarketMarkPriceQuery__ + * + * To run a query within a React component, call `useMarketMarkPriceQuery` and pass it any options that fit your needs. + * When your component renders, `useMarketMarkPriceQuery` 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 } = useMarketMarkPriceQuery({ + * variables: { + * marketId: // value for 'marketId' + * }, + * }); + */ +export function useMarketMarkPriceQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(MarketMarkPriceDocument, options); + } +export function useMarketMarkPriceLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(MarketMarkPriceDocument, options); + } +export type MarketMarkPriceQueryHookResult = ReturnType; +export type MarketMarkPriceLazyQueryHookResult = ReturnType; +export type MarketMarkPriceQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/console-lite/src/app/hooks/__generated___/MarketPositions.ts b/apps/console-lite/src/app/hooks/__generated___/MarketPositions.ts new file mode 100644 index 000000000..e6dc12487 --- /dev/null +++ b/apps/console-lite/src/app/hooks/__generated___/MarketPositions.ts @@ -0,0 +1,68 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type MarketPositionsQueryVariables = Types.Exact<{ + partyId: Types.Scalars['ID']; +}>; + + +export type MarketPositionsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', decimals: number }, market?: { __typename?: 'Market', id: string } | null }> | null, positionsConnection: { __typename?: 'PositionConnection', edges?: Array<{ __typename?: 'PositionEdge', node: { __typename?: 'Position', openVolume: string, market: { __typename?: 'Market', id: string } } }> | null } } | null }; + + +export const MarketPositionsDocument = gql` + query MarketPositions($partyId: ID!) { + party(id: $partyId) { + id + accounts { + type + balance + asset { + decimals + } + market { + id + } + } + positionsConnection { + edges { + node { + openVolume + market { + id + } + } + } + } + } +} + `; + +/** + * __useMarketPositionsQuery__ + * + * To run a query within a React component, call `useMarketPositionsQuery` and pass it any options that fit your needs. + * When your component renders, `useMarketPositionsQuery` 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 } = useMarketPositionsQuery({ + * variables: { + * partyId: // value for 'partyId' + * }, + * }); + */ +export function useMarketPositionsQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(MarketPositionsDocument, options); + } +export function useMarketPositionsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(MarketPositionsDocument, options); + } +export type MarketPositionsQueryHookResult = ReturnType; +export type MarketPositionsLazyQueryHookResult = ReturnType; +export type MarketPositionsQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/console-lite/src/app/hooks/__generated___/PartyMarketData.ts b/apps/console-lite/src/app/hooks/__generated___/PartyMarketData.ts new file mode 100644 index 000000000..516fc6126 --- /dev/null +++ b/apps/console-lite/src/app/hooks/__generated___/PartyMarketData.ts @@ -0,0 +1,71 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type PartyMarketDataQueryVariables = Types.Exact<{ + partyId: Types.Scalars['ID']; +}>; + + +export type PartyMarketDataQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, decimals: number }, market?: { __typename?: 'Market', id: string } | null }> | null, marginsConnection: { __typename?: 'MarginConnection', edges?: Array<{ __typename?: 'MarginEdge', node: { __typename?: 'MarginLevels', initialLevel: string, maintenanceLevel: string, searchLevel: string, market: { __typename?: 'Market', id: string } } }> | null } } | null }; + + +export const PartyMarketDataDocument = gql` + query PartyMarketData($partyId: ID!) { + party(id: $partyId) { + id + accounts { + type + balance + asset { + id + decimals + } + market { + id + } + } + marginsConnection { + edges { + node { + market { + id + } + initialLevel + maintenanceLevel + searchLevel + } + } + } + } +} + `; + +/** + * __usePartyMarketDataQuery__ + * + * To run a query within a React component, call `usePartyMarketDataQuery` and pass it any options that fit your needs. + * When your component renders, `usePartyMarketDataQuery` 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 } = usePartyMarketDataQuery({ + * variables: { + * partyId: // value for 'partyId' + * }, + * }); + */ +export function usePartyMarketDataQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(PartyMarketDataDocument, options); + } +export function usePartyMarketDataLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(PartyMarketDataDocument, options); + } +export type PartyMarketDataQueryHookResult = ReturnType; +export type PartyMarketDataLazyQueryHookResult = ReturnType; +export type PartyMarketDataQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/console-lite/src/app/hooks/use-calculate-slippage.spec.tsx b/apps/console-lite/src/app/hooks/use-calculate-slippage.spec.tsx index 49b58dfd5..b5706cb88 100644 --- a/apps/console-lite/src/app/hooks/use-calculate-slippage.spec.tsx +++ b/apps/console-lite/src/app/hooks/use-calculate-slippage.spec.tsx @@ -64,6 +64,15 @@ jest.mock('@vegaprotocol/market-depth', () => ({ useOrderBookData: jest.fn(() => mockOrderBookData), })); +jest.mock('@vegaprotocol/react-helpers', () => ({ + ...jest.requireActual('@vegaprotocol/react-helpers'), + useDataProvider: jest.fn(() => ({ + data: { + marketsConnection: [], + }, + })), +})); + describe('useCalculateSlippage Hook', () => { describe('calculate proper result', () => { afterEach(() => { diff --git a/apps/console-lite/src/app/hooks/use-calculate-slippage.ts b/apps/console-lite/src/app/hooks/use-calculate-slippage.ts index 13520587a..ccf937a66 100644 --- a/apps/console-lite/src/app/hooks/use-calculate-slippage.ts +++ b/apps/console-lite/src/app/hooks/use-calculate-slippage.ts @@ -1,9 +1,15 @@ import { useMemo } from 'react'; import { Side } from '@vegaprotocol/types'; import { useOrderBookData } from '@vegaprotocol/market-depth'; +import { marketProvider } from '@vegaprotocol/market-list'; +import type { Market } from '@vegaprotocol/market-list'; import type { Order } from '@vegaprotocol/orders'; import { BigNumber } from 'bignumber.js'; -import { formatNumber, toBigNum } from '@vegaprotocol/react-helpers'; +import { + formatNumber, + toBigNum, + useDataProvider, +} from '@vegaprotocol/react-helpers'; interface Props { marketId: string; @@ -16,11 +22,16 @@ const useCalculateSlippage = ({ marketId, order }: Props) => { variables, throttleMilliseconds: 5000, }); + const { data: market } = useDataProvider({ + dataProvider: marketProvider, + noUpdate: true, + variables, + }); const volPriceArr = data?.depth[order.side === Side.SIDE_BUY ? 'sell' : 'buy'] || []; - if (volPriceArr.length) { - const decimals = data?.decimalPlaces ?? 0; - const positionDecimals = data?.positionDecimalPlaces ?? 0; + if (volPriceArr.length && market) { + const decimals = market.decimalPlaces ?? 0; + const positionDecimals = market.positionDecimalPlaces ?? 0; const bestPrice = toBigNum(volPriceArr[0].price, decimals); const { size } = order; let descSize = new BigNumber(size); diff --git a/apps/console-lite/src/app/hooks/use-column-definitions.tsx b/apps/console-lite/src/app/hooks/use-column-definitions.tsx index 5a8ea69c0..f5bbf8fcf 100644 --- a/apps/console-lite/src/app/hooks/use-column-definitions.tsx +++ b/apps/console-lite/src/app/hooks/use-column-definitions.tsx @@ -22,7 +22,7 @@ const useColumnDefinitions = ({ isMobile }: Props) => { headerName: t('Markets'), headerClass: 'uppercase', minWidth: isMobile ? 160 : 350, - field: 'name', + field: 'tradableInstrument.instrument.name', cellClass: 'overflow-visible', cellRenderer: ({ data }: { data: SimpleMarketsType }) => ( @@ -93,13 +93,13 @@ const useColumnDefinitions = ({ isMobile }: Props) => { { colId: 'status', headerName: t('Status'), - field: 'data.market.state', + field: 'state', headerClass: 'uppercase', minWidth: 100, cellRenderer: ({ data }: { data: SimpleMarkets_markets }) => (
    -
    - {MARKET_STATES_MAP[data.data?.market.state || '']} +
    + {MARKET_STATES_MAP[data.state || '']}
    ), diff --git a/apps/console-lite/src/app/hooks/use-markets-filter-data.ts b/apps/console-lite/src/app/hooks/use-markets-filter-data.ts index 7763209f1..71ca60f02 100644 --- a/apps/console-lite/src/app/hooks/use-markets-filter-data.ts +++ b/apps/console-lite/src/app/hooks/use-markets-filter-data.ts @@ -27,7 +27,7 @@ const useMarketsFilterData = ( : params.state ? params.state : MarketState.STATE_ACTIVE; - if (state && state !== item.data?.market.state) { + if (state && state !== item.state) { return false; } return true; diff --git a/apps/explorer/.eslintrc.json b/apps/explorer/.eslintrc.json index db820c5d0..de2a9b877 100644 --- a/apps/explorer/.eslintrc.json +++ b/apps/explorer/.eslintrc.json @@ -1,6 +1,6 @@ { "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*", "__generated__"], + "ignorePatterns": ["!**/*", "__generated__", "__generated___"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], diff --git a/apps/explorer/src/app/routes/assets/Assets.graphql b/apps/explorer/src/app/routes/assets/Assets.graphql new file mode 100644 index 000000000..00e113473 --- /dev/null +++ b/apps/explorer/src/app/routes/assets/Assets.graphql @@ -0,0 +1,27 @@ +query AssetsQuery { + assetsConnection { + edges { + node { + id + name + symbol + decimals + source { + ... on ERC20 { + contractAddress + } + ... on BuiltinAsset { + maxFaucetAmountMint + } + } + infrastructureFeeAccount { + type + balance + market { + id + } + } + } + } + } +} diff --git a/apps/explorer/src/app/routes/assets/__generated___/Assets.ts b/apps/explorer/src/app/routes/assets/__generated___/Assets.ts new file mode 100644 index 000000000..a7507a109 --- /dev/null +++ b/apps/explorer/src/app/routes/assets/__generated___/Assets.ts @@ -0,0 +1,67 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type AssetsQueryQueryVariables = Types.Exact<{ [key: string]: never; }>; + + +export type AssetsQueryQuery = { __typename?: 'Query', assetsConnection: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, source: { __typename?: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename?: 'ERC20', contractAddress: string }, infrastructureFeeAccount: { __typename?: 'Account', type: Types.AccountType, balance: string, market?: { __typename?: 'Market', id: string } | null } } } | null> | null } }; + + +export const AssetsQueryDocument = gql` + query AssetsQuery { + assetsConnection { + edges { + node { + id + name + symbol + decimals + source { + ... on ERC20 { + contractAddress + } + ... on BuiltinAsset { + maxFaucetAmountMint + } + } + infrastructureFeeAccount { + type + balance + market { + id + } + } + } + } + } +} + `; + +/** + * __useAssetsQueryQuery__ + * + * To run a query within a React component, call `useAssetsQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useAssetsQueryQuery` 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 } = useAssetsQueryQuery({ + * variables: { + * }, + * }); + */ +export function useAssetsQueryQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(AssetsQueryDocument, options); + } +export function useAssetsQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(AssetsQueryDocument, options); + } +export type AssetsQueryQueryHookResult = ReturnType; +export type AssetsQueryLazyQueryHookResult = ReturnType; +export type AssetsQueryQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/explorer/src/app/routes/assets/index.tsx b/apps/explorer/src/app/routes/assets/index.tsx index 326a4fb97..4243644fe 100644 --- a/apps/explorer/src/app/routes/assets/index.tsx +++ b/apps/explorer/src/app/routes/assets/index.tsx @@ -1,5 +1,5 @@ import { gql, useQuery } from '@apollo/client'; -import { assetsConnectionToAssets, t } from '@vegaprotocol/react-helpers'; +import { getAssets, t } from '@vegaprotocol/react-helpers'; import React from 'react'; import { RouteTitle } from '../../components/route-title'; import { SubHeading } from '../../components/sub-heading'; @@ -39,7 +39,7 @@ export const ASSETS_QUERY = gql` const Assets = () => { const { data } = useQuery(ASSETS_QUERY); - const assets = assetsConnectionToAssets(data?.assetsConnection); + const assets = getAssets(data); return (
    diff --git a/apps/explorer/src/app/routes/governance/Proposals.graphql b/apps/explorer/src/app/routes/governance/Proposals.graphql new file mode 100644 index 000000000..02aa5ee8c --- /dev/null +++ b/apps/explorer/src/app/routes/governance/Proposals.graphql @@ -0,0 +1,74 @@ +query ProposalsQuery { + proposals { + id + reference + state + datetime + rejectionReason + party { + id + } + terms { + closingDatetime + enactmentDatetime + change { + ... on NewMarket { + instrument { + name + } + } + ... on UpdateMarket { + marketId + } + ... on NewAsset { + __typename + symbol + source { + ... on BuiltinAsset { + maxFaucetAmountMint + } + ... on ERC20 { + contractAddress + } + } + } + ... on UpdateNetworkParameter { + networkParameter { + key + value + } + } + } + } + votes { + yes { + totalTokens + totalNumber + votes { + value + party { + id + stake { + currentStakeAvailable + } + } + datetime + } + } + no { + totalTokens + totalNumber + votes { + value + party { + id + stake { + currentStakeAvailable + } + } + datetime + } + } + } + } +} diff --git a/apps/explorer/src/app/routes/governance/__generated__/ProposalsQuery.ts b/apps/explorer/src/app/routes/governance/__generated__/ProposalsQuery.ts index 7e6d2b10b..249072d50 100644 --- a/apps/explorer/src/app/routes/governance/__generated__/ProposalsQuery.ts +++ b/apps/explorer/src/app/routes/governance/__generated__/ProposalsQuery.ts @@ -9,7 +9,23 @@ import { ProposalState, ProposalRejectionReason, VoteValue } from "@vegaprotocol // GraphQL query operation: ProposalsQuery // ==================================================== -export interface ProposalsQuery_proposals_party { +export interface ProposalsQuery_proposalsConnection_edges_node_rationale { + __typename: "ProposalRationale"; + /** + * Title to be used to give a short description of the proposal in lists. + * This is to be between 0 and 100 unicode characters. + * This is mandatory for all proposals. + */ + title: string; + /** + * Description to show a short title / something in case the link goes offline. + * This is to be between 0 and 20k unicode characters. + * This is mandatory for all proposals. + */ + description: string; +} + +export interface ProposalsQuery_proposalsConnection_edges_node_party { __typename: "Party"; /** * Party identifier @@ -17,11 +33,11 @@ export interface ProposalsQuery_proposals_party { id: string; } -export interface ProposalsQuery_proposals_terms_change_UpdateAsset { +export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateAsset { __typename: "UpdateAsset" | "NewFreeform"; } -export interface ProposalsQuery_proposals_terms_change_NewMarket_instrument { +export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_NewMarket_instrument { __typename: "InstrumentConfiguration"; /** * Full and fairly descriptive name for the instrument @@ -29,20 +45,20 @@ export interface ProposalsQuery_proposals_terms_change_NewMarket_instrument { name: string; } -export interface ProposalsQuery_proposals_terms_change_NewMarket { +export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_NewMarket { __typename: "NewMarket"; /** * New market instrument configuration */ - instrument: ProposalsQuery_proposals_terms_change_NewMarket_instrument; + instrument: ProposalsQuery_proposalsConnection_edges_node_terms_change_NewMarket_instrument; } -export interface ProposalsQuery_proposals_terms_change_UpdateMarket { +export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateMarket { __typename: "UpdateMarket"; marketId: string; } -export interface ProposalsQuery_proposals_terms_change_NewAsset_source_BuiltinAsset { +export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset_source_BuiltinAsset { __typename: "BuiltinAsset"; /** * Maximum amount that can be requested by a party through the built-in asset faucet at a time @@ -50,7 +66,7 @@ export interface ProposalsQuery_proposals_terms_change_NewAsset_source_BuiltinAs maxFaucetAmountMint: string; } -export interface ProposalsQuery_proposals_terms_change_NewAsset_source_ERC20 { +export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset_source_ERC20 { __typename: "ERC20"; /** * The address of the ERC20 contract @@ -58,9 +74,9 @@ export interface ProposalsQuery_proposals_terms_change_NewAsset_source_ERC20 { contractAddress: string; } -export type ProposalsQuery_proposals_terms_change_NewAsset_source = ProposalsQuery_proposals_terms_change_NewAsset_source_BuiltinAsset | ProposalsQuery_proposals_terms_change_NewAsset_source_ERC20; +export type ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset_source = ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset_source_BuiltinAsset | ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset_source_ERC20; -export interface ProposalsQuery_proposals_terms_change_NewAsset { +export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset { __typename: "NewAsset"; /** * The symbol of the asset (e.g: GBP) @@ -69,10 +85,10 @@ export interface ProposalsQuery_proposals_terms_change_NewAsset { /** * The source of the new asset */ - source: ProposalsQuery_proposals_terms_change_NewAsset_source; + source: ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset_source; } -export interface ProposalsQuery_proposals_terms_change_UpdateNetworkParameter_networkParameter { +export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateNetworkParameter_networkParameter { __typename: "NetworkParameter"; /** * The name of the network parameter @@ -84,14 +100,14 @@ export interface ProposalsQuery_proposals_terms_change_UpdateNetworkParameter_ne value: string; } -export interface ProposalsQuery_proposals_terms_change_UpdateNetworkParameter { +export interface ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateNetworkParameter { __typename: "UpdateNetworkParameter"; - networkParameter: ProposalsQuery_proposals_terms_change_UpdateNetworkParameter_networkParameter; + networkParameter: ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateNetworkParameter_networkParameter; } -export type ProposalsQuery_proposals_terms_change = ProposalsQuery_proposals_terms_change_UpdateAsset | ProposalsQuery_proposals_terms_change_NewMarket | ProposalsQuery_proposals_terms_change_UpdateMarket | ProposalsQuery_proposals_terms_change_NewAsset | ProposalsQuery_proposals_terms_change_UpdateNetworkParameter; +export type ProposalsQuery_proposalsConnection_edges_node_terms_change = ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateAsset | ProposalsQuery_proposalsConnection_edges_node_terms_change_NewMarket | ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateMarket | ProposalsQuery_proposalsConnection_edges_node_terms_change_NewAsset | ProposalsQuery_proposalsConnection_edges_node_terms_change_UpdateNetworkParameter; -export interface ProposalsQuery_proposals_terms { +export interface ProposalsQuery_proposalsConnection_edges_node_terms { __typename: "ProposalTerms"; /** * RFC3339Nano time and date when voting closes for this proposal. @@ -107,18 +123,18 @@ export interface ProposalsQuery_proposals_terms { /** * Actual change being introduced by the proposal - action the proposal triggers if passed and enacted. */ - change: ProposalsQuery_proposals_terms_change; + change: ProposalsQuery_proposalsConnection_edges_node_terms_change; } -export interface ProposalsQuery_proposals_votes_yes_votes_party_stake { - __typename: "PartyStake"; +export interface ProposalsQuery_proposalsConnection_edges_node_votes_yes_votes_party_stakingSummary { + __typename: "StakingSummary"; /** * The stake currently available for the party */ currentStakeAvailable: string; } -export interface ProposalsQuery_proposals_votes_yes_votes_party { +export interface ProposalsQuery_proposalsConnection_edges_node_votes_yes_votes_party { __typename: "Party"; /** * Party identifier @@ -127,10 +143,10 @@ export interface ProposalsQuery_proposals_votes_yes_votes_party { /** * The staking information for this Party */ - stake: ProposalsQuery_proposals_votes_yes_votes_party_stake; + stakingSummary: ProposalsQuery_proposalsConnection_edges_node_votes_yes_votes_party_stakingSummary; } -export interface ProposalsQuery_proposals_votes_yes_votes { +export interface ProposalsQuery_proposalsConnection_edges_node_votes_yes_votes { __typename: "Vote"; /** * The vote value cast @@ -139,14 +155,14 @@ export interface ProposalsQuery_proposals_votes_yes_votes { /** * The party casting the vote */ - party: ProposalsQuery_proposals_votes_yes_votes_party; + party: ProposalsQuery_proposalsConnection_edges_node_votes_yes_votes_party; /** * RFC3339Nano time and date when the vote reached Vega network */ datetime: string; } -export interface ProposalsQuery_proposals_votes_yes { +export interface ProposalsQuery_proposalsConnection_edges_node_votes_yes { __typename: "ProposalVoteSide"; /** * Total number of governance tokens from the votes cast for this side @@ -159,18 +175,18 @@ export interface ProposalsQuery_proposals_votes_yes { /** * All votes cast for this side */ - votes: ProposalsQuery_proposals_votes_yes_votes[] | null; + votes: ProposalsQuery_proposalsConnection_edges_node_votes_yes_votes[] | null; } -export interface ProposalsQuery_proposals_votes_no_votes_party_stake { - __typename: "PartyStake"; +export interface ProposalsQuery_proposalsConnection_edges_node_votes_no_votes_party_stakingSummary { + __typename: "StakingSummary"; /** * The stake currently available for the party */ currentStakeAvailable: string; } -export interface ProposalsQuery_proposals_votes_no_votes_party { +export interface ProposalsQuery_proposalsConnection_edges_node_votes_no_votes_party { __typename: "Party"; /** * Party identifier @@ -179,10 +195,10 @@ export interface ProposalsQuery_proposals_votes_no_votes_party { /** * The staking information for this Party */ - stake: ProposalsQuery_proposals_votes_no_votes_party_stake; + stakingSummary: ProposalsQuery_proposalsConnection_edges_node_votes_no_votes_party_stakingSummary; } -export interface ProposalsQuery_proposals_votes_no_votes { +export interface ProposalsQuery_proposalsConnection_edges_node_votes_no_votes { __typename: "Vote"; /** * The vote value cast @@ -191,14 +207,14 @@ export interface ProposalsQuery_proposals_votes_no_votes { /** * The party casting the vote */ - party: ProposalsQuery_proposals_votes_no_votes_party; + party: ProposalsQuery_proposalsConnection_edges_node_votes_no_votes_party; /** * RFC3339Nano time and date when the vote reached Vega network */ datetime: string; } -export interface ProposalsQuery_proposals_votes_no { +export interface ProposalsQuery_proposalsConnection_edges_node_votes_no { __typename: "ProposalVoteSide"; /** * Total number of governance tokens from the votes cast for this side @@ -211,27 +227,31 @@ export interface ProposalsQuery_proposals_votes_no { /** * All votes cast for this side */ - votes: ProposalsQuery_proposals_votes_no_votes[] | null; + votes: ProposalsQuery_proposalsConnection_edges_node_votes_no_votes[] | null; } -export interface ProposalsQuery_proposals_votes { +export interface ProposalsQuery_proposalsConnection_edges_node_votes { __typename: "ProposalVotes"; /** * Yes votes cast for this proposal */ - yes: ProposalsQuery_proposals_votes_yes; + yes: ProposalsQuery_proposalsConnection_edges_node_votes_yes; /** * No votes cast for this proposal */ - no: ProposalsQuery_proposals_votes_no; + no: ProposalsQuery_proposalsConnection_edges_node_votes_no; } -export interface ProposalsQuery_proposals { +export interface ProposalsQuery_proposalsConnection_edges_node { __typename: "Proposal"; /** * Proposal ID that is filled by Vega once proposal reaches the network */ id: string | null; + /** + * Rationale behind the proposal + */ + rationale: ProposalsQuery_proposalsConnection_edges_node_rationale; /** * A UUID reference to aid tracking proposals on Vega */ @@ -251,20 +271,36 @@ export interface ProposalsQuery_proposals { /** * Party that prepared the proposal */ - party: ProposalsQuery_proposals_party; + party: ProposalsQuery_proposalsConnection_edges_node_party; /** * Terms of the proposal */ - terms: ProposalsQuery_proposals_terms; + terms: ProposalsQuery_proposalsConnection_edges_node_terms; /** * Votes cast for this proposal */ - votes: ProposalsQuery_proposals_votes; + votes: ProposalsQuery_proposalsConnection_edges_node_votes; +} + +export interface ProposalsQuery_proposalsConnection_edges { + __typename: "ProposalEdge"; + /** + * The proposal data + */ + node: ProposalsQuery_proposalsConnection_edges_node; +} + +export interface ProposalsQuery_proposalsConnection { + __typename: "ProposalsConnection"; + /** + * List of proposals available for the connection + */ + edges: (ProposalsQuery_proposalsConnection_edges | null)[] | null; } export interface ProposalsQuery { /** * All governance proposals in the Vega network */ - proposals: ProposalsQuery_proposals[] | null; + proposalsConnection: ProposalsQuery_proposalsConnection; } diff --git a/apps/explorer/src/app/routes/governance/__generated___/Proposals.ts b/apps/explorer/src/app/routes/governance/__generated___/Proposals.ts new file mode 100644 index 000000000..7a9394f8f --- /dev/null +++ b/apps/explorer/src/app/routes/governance/__generated___/Proposals.ts @@ -0,0 +1,114 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type ProposalsQueryQueryVariables = Types.Exact<{ [key: string]: never; }>; + + +export type ProposalsQueryQuery = { __typename?: 'Query', proposals?: Array<{ __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: string, rejectionReason?: Types.ProposalRejectionReason | null, party: { __typename?: 'Party', id: string }, terms: { __typename?: 'ProposalTerms', closingDatetime: string, enactmentDatetime?: string | null, change: { __typename: 'NewAsset', symbol: string, source: { __typename?: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename?: 'ERC20', contractAddress: string } } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', instrument: { __typename?: 'InstrumentConfiguration', name: string } } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket', marketId: string } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null } } }> | null }; + + +export const ProposalsQueryDocument = gql` + query ProposalsQuery { + proposals { + id + reference + state + datetime + rejectionReason + party { + id + } + terms { + closingDatetime + enactmentDatetime + change { + ... on NewMarket { + instrument { + name + } + } + ... on UpdateMarket { + marketId + } + ... on NewAsset { + __typename + symbol + source { + ... on BuiltinAsset { + maxFaucetAmountMint + } + ... on ERC20 { + contractAddress + } + } + } + ... on UpdateNetworkParameter { + networkParameter { + key + value + } + } + } + } + votes { + yes { + totalTokens + totalNumber + votes { + value + party { + id + stake { + currentStakeAvailable + } + } + datetime + } + } + no { + totalTokens + totalNumber + votes { + value + party { + id + stake { + currentStakeAvailable + } + } + datetime + } + } + } + } +} + `; + +/** + * __useProposalsQueryQuery__ + * + * To run a query within a React component, call `useProposalsQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useProposalsQueryQuery` 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 } = useProposalsQueryQuery({ + * variables: { + * }, + * }); + */ +export function useProposalsQueryQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(ProposalsQueryDocument, options); + } +export function useProposalsQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(ProposalsQueryDocument, options); + } +export type ProposalsQueryQueryHookResult = ReturnType; +export type ProposalsQueryLazyQueryHookResult = ReturnType; +export type ProposalsQueryQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/explorer/src/app/routes/governance/index.tsx b/apps/explorer/src/app/routes/governance/index.tsx index b64bed16f..561bc6849 100644 --- a/apps/explorer/src/app/routes/governance/index.tsx +++ b/apps/explorer/src/app/routes/governance/index.tsx @@ -4,95 +4,90 @@ import React from 'react'; import { RouteTitle } from '../../components/route-title'; import { SubHeading } from '../../components/sub-heading'; import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit'; +import { getProposals } from '@vegaprotocol/governance'; import type { ProposalsQuery, - ProposalsQuery_proposals_terms_change, + ProposalsQuery_proposalsConnection_edges_node, } from './__generated__/ProposalsQuery'; -export function getProposalName(change: ProposalsQuery_proposals_terms_change) { - if (change.__typename === 'NewAsset') { - return t(`New asset: ${change.symbol}`); - } else if (change.__typename === 'NewMarket') { - return t(`New market: ${change.instrument.name}`); - } else if (change.__typename === 'UpdateMarket') { - return t(`Update market: ${change.marketId}`); - } else if (change.__typename === 'UpdateNetworkParameter') { - return t(`Update network: ${change.networkParameter.key}`); - } - - return t('Unknown proposal'); -} - -const PROPOSAL_QUERY = gql` +const PROPOSALS_QUERY = gql` query ProposalsQuery { - proposals { - id - reference - state - datetime - rejectionReason - party { - id - } - terms { - closingDatetime - enactmentDatetime - change { - ... on NewMarket { - instrument { - name - } + proposalsConnection { + edges { + node { + id + rationale { + title + description } - ... on UpdateMarket { - marketId + reference + state + datetime + rejectionReason + party { + id } - ... on NewAsset { - __typename - symbol - source { - ... on BuiltinAsset { - maxFaucetAmountMint + terms { + closingDatetime + enactmentDatetime + change { + ... on NewMarket { + instrument { + name + } } - ... on ERC20 { - contractAddress + ... on UpdateMarket { + marketId + } + ... on NewAsset { + __typename + symbol + source { + ... on BuiltinAsset { + maxFaucetAmountMint + } + ... on ERC20 { + contractAddress + } + } + } + ... on UpdateNetworkParameter { + networkParameter { + key + value + } } } } - ... on UpdateNetworkParameter { - networkParameter { - key - value - } - } - } - } - votes { - yes { - totalTokens - totalNumber votes { - value - party { - id - stake { - currentStakeAvailable + yes { + totalTokens + totalNumber + votes { + value + party { + id + stakingSummary { + currentStakeAvailable + } + } + datetime } } - datetime - } - } - no { - totalTokens - totalNumber - votes { - value - party { - id - stake { - currentStakeAvailable + no { + totalTokens + totalNumber + votes { + value + party { + id + stakingSummary { + currentStakeAvailable + } + } + datetime } } - datetime } } } @@ -101,9 +96,12 @@ const PROPOSAL_QUERY = gql` `; const Governance = () => { - const { data } = useQuery(PROPOSAL_QUERY, { + const { data } = useQuery(PROPOSALS_QUERY, { errorPolicy: 'ignore', }); + const proposals = getProposals( + data + ) as ProposalsQuery_proposalsConnection_edges_node[]; if (!data) return null; return ( @@ -111,9 +109,11 @@ const Governance = () => { {t('Governance Proposals')} - {data.proposals?.map((p) => ( + {proposals.map((p) => ( - {getProposalName(p.terms.change)} + + {p.rationale.title || p.rationale.description} + ))} diff --git a/apps/explorer/src/app/routes/markets/Markets.graphql b/apps/explorer/src/app/routes/markets/Markets.graphql new file mode 100644 index 000000000..2b17af4ce --- /dev/null +++ b/apps/explorer/src/app/routes/markets/Markets.graphql @@ -0,0 +1,134 @@ +query MarketsQuery { + markets { + id + name + fees { + factors { + makerFee + infrastructureFee + liquidityFee + } + } + tradableInstrument { + instrument { + name + metadata { + tags + } + id + code + product { + ... on Future { + settlementAsset { + id + name + decimals + globalRewardPoolAccount { + balance + } + } + } + } + } + riskModel { + ... on LogNormalRiskModel { + tau + riskAversionParameter + params { + r + sigma + mu + } + } + ... on SimpleRiskModel { + params { + factorLong + factorShort + } + } + } + marginCalculator { + scalingFactors { + searchLevel + initialMargin + collateralRelease + } + } + } + decimalPlaces + openingAuction { + durationSecs + volume + } + priceMonitoringSettings { + parameters { + triggers { + horizonSecs + probability + auctionExtensionSecs + } + } + } + liquidityMonitoringParameters { + triggeringRatio + targetStakeParameters { + timeWindow + scalingFactor + } + } + tradingMode + state + proposal { + id + } + state + accounts { + asset { + id + name + } + balance + type + } + data { + markPrice + bestBidPrice + bestBidVolume + bestOfferPrice + bestOfferVolume + bestStaticBidPrice + bestStaticBidVolume + bestStaticOfferPrice + bestStaticOfferVolume + midPrice + staticMidPrice + timestamp + openInterest + auctionEnd + auctionStart + indicativePrice + indicativeVolume + trigger + extensionTrigger + targetStake + suppliedStake + priceMonitoringBounds { + minValidPrice + maxValidPrice + trigger { + auctionExtensionSecs + probability + } + referencePrice + } + marketValueProxy + liquidityProviderFeeShare { + party { + id + } + equityLikeShare + averageEntryValuation + } + } + } +} diff --git a/apps/explorer/src/app/routes/markets/__generated__/MarketsQuery.ts b/apps/explorer/src/app/routes/markets/__generated__/MarketsQuery.ts index 8d6afc124..9896efed9 100644 --- a/apps/explorer/src/app/routes/markets/__generated__/MarketsQuery.ts +++ b/apps/explorer/src/app/routes/markets/__generated__/MarketsQuery.ts @@ -465,10 +465,6 @@ export interface MarketsQuery_markets { * Market ID */ id: string; - /** - * Market full name - */ - name: string; /** * Fees related data */ diff --git a/apps/explorer/src/app/routes/markets/__generated___/Markets.ts b/apps/explorer/src/app/routes/markets/__generated___/Markets.ts new file mode 100644 index 000000000..e5e1c1a43 --- /dev/null +++ b/apps/explorer/src/app/routes/markets/__generated___/Markets.ts @@ -0,0 +1,174 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type MarketsQueryQueryVariables = Types.Exact<{ [key: string]: never; }>; + + +export type MarketsQueryQuery = { __typename?: 'Query', markets?: Array<{ __typename?: 'Market', id: string, name: string, decimalPlaces: number, tradingMode: Types.MarketTradingMode, state: Types.MarketState, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, id: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array | null }, product: { __typename?: 'Future', settlementAsset: { __typename?: 'Asset', id: string, name: string, decimals: number, globalRewardPoolAccount?: { __typename?: 'Account', balance: string } | null } } }, riskModel: { __typename?: 'LogNormalRiskModel', tau: number, riskAversionParameter: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, marginCalculator?: { __typename?: 'MarginCalculator', scalingFactors: { __typename?: 'ScalingFactors', searchLevel: number, initialMargin: number, collateralRelease: number } } | null }, openingAuction: { __typename?: 'AuctionDuration', durationSecs: number, volume: number }, priceMonitoringSettings: { __typename?: 'PriceMonitoringSettings', parameters?: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null } | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: number, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, proposal?: { __typename?: 'Proposal', id?: string | null } | null, accounts?: Array<{ __typename?: 'Account', balance: string, type: Types.AccountType, asset: { __typename?: 'Asset', id: string, name: string } }> | null, data?: { __typename?: 'MarketData', markPrice: string, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, midPrice: string, staticMidPrice: string, timestamp: string, openInterest: string, auctionEnd?: string | null, auctionStart?: string | null, indicativePrice: string, indicativeVolume: string, trigger: Types.AuctionTrigger, extensionTrigger: Types.AuctionTrigger, targetStake?: string | null, suppliedStake?: string | null, marketValueProxy: string, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', auctionExtensionSecs: number, probability: number } }> | null, liquidityProviderFeeShare?: Array<{ __typename?: 'LiquidityProviderFeeShare', equityLikeShare: string, averageEntryValuation: string, party: { __typename?: 'Party', id: string } }> | null } | null }> | null }; + + +export const MarketsQueryDocument = gql` + query MarketsQuery { + markets { + id + name + fees { + factors { + makerFee + infrastructureFee + liquidityFee + } + } + tradableInstrument { + instrument { + name + metadata { + tags + } + id + code + product { + ... on Future { + settlementAsset { + id + name + decimals + globalRewardPoolAccount { + balance + } + } + } + } + } + riskModel { + ... on LogNormalRiskModel { + tau + riskAversionParameter + params { + r + sigma + mu + } + } + ... on SimpleRiskModel { + params { + factorLong + factorShort + } + } + } + marginCalculator { + scalingFactors { + searchLevel + initialMargin + collateralRelease + } + } + } + decimalPlaces + openingAuction { + durationSecs + volume + } + priceMonitoringSettings { + parameters { + triggers { + horizonSecs + probability + auctionExtensionSecs + } + } + } + liquidityMonitoringParameters { + triggeringRatio + targetStakeParameters { + timeWindow + scalingFactor + } + } + tradingMode + state + proposal { + id + } + state + accounts { + asset { + id + name + } + balance + type + } + data { + markPrice + bestBidPrice + bestBidVolume + bestOfferPrice + bestOfferVolume + bestStaticBidPrice + bestStaticBidVolume + bestStaticOfferPrice + bestStaticOfferVolume + midPrice + staticMidPrice + timestamp + openInterest + auctionEnd + auctionStart + indicativePrice + indicativeVolume + trigger + extensionTrigger + targetStake + suppliedStake + priceMonitoringBounds { + minValidPrice + maxValidPrice + trigger { + auctionExtensionSecs + probability + } + referencePrice + } + marketValueProxy + liquidityProviderFeeShare { + party { + id + } + equityLikeShare + averageEntryValuation + } + } + } +} + `; + +/** + * __useMarketsQueryQuery__ + * + * To run a query within a React component, call `useMarketsQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useMarketsQueryQuery` 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 } = useMarketsQueryQuery({ + * variables: { + * }, + * }); + */ +export function useMarketsQueryQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(MarketsQueryDocument, options); + } +export function useMarketsQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(MarketsQueryDocument, options); + } +export type MarketsQueryQueryHookResult = ReturnType; +export type MarketsQueryLazyQueryHookResult = ReturnType; +export type MarketsQueryQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/explorer/src/app/routes/markets/index.tsx b/apps/explorer/src/app/routes/markets/index.tsx index 5f8fe8f4d..22b7ad466 100644 --- a/apps/explorer/src/app/routes/markets/index.tsx +++ b/apps/explorer/src/app/routes/markets/index.tsx @@ -11,7 +11,6 @@ const MARKETS_QUERY = gql` query MarketsQuery { markets { id - name fees { factors { makerFee @@ -154,7 +153,9 @@ const Markets = () => { {data?.markets ? data.markets.map((m) => ( - {m.name} + + {m.tradableInstrument.instrument.name} + )) diff --git a/apps/explorer/src/app/routes/network-parameters/NetworkParameters.graphql b/apps/explorer/src/app/routes/network-parameters/NetworkParameters.graphql new file mode 100644 index 000000000..7fbac2c00 --- /dev/null +++ b/apps/explorer/src/app/routes/network-parameters/NetworkParameters.graphql @@ -0,0 +1,6 @@ +query NetworkParametersQuery { + networkParameters { + key + value + } +} diff --git a/apps/explorer/src/app/routes/network-parameters/__generated___/NetworkParameters.ts b/apps/explorer/src/app/routes/network-parameters/__generated___/NetworkParameters.ts new file mode 100644 index 000000000..dd1045c07 --- /dev/null +++ b/apps/explorer/src/app/routes/network-parameters/__generated___/NetworkParameters.ts @@ -0,0 +1,46 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type NetworkParametersQueryQueryVariables = Types.Exact<{ [key: string]: never; }>; + + +export type NetworkParametersQueryQuery = { __typename?: 'Query', networkParameters?: Array<{ __typename?: 'NetworkParameter', key: string, value: string }> | null }; + + +export const NetworkParametersQueryDocument = gql` + query NetworkParametersQuery { + networkParameters { + key + value + } +} + `; + +/** + * __useNetworkParametersQueryQuery__ + * + * To run a query within a React component, call `useNetworkParametersQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useNetworkParametersQueryQuery` 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 } = useNetworkParametersQueryQuery({ + * variables: { + * }, + * }); + */ +export function useNetworkParametersQueryQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(NetworkParametersQueryDocument, options); + } +export function useNetworkParametersQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(NetworkParametersQueryDocument, options); + } +export type NetworkParametersQueryQueryHookResult = ReturnType; +export type NetworkParametersQueryLazyQueryHookResult = ReturnType; +export type NetworkParametersQueryQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/explorer/src/app/routes/oracles/OracleSpecs.graphql b/apps/explorer/src/app/routes/oracles/OracleSpecs.graphql new file mode 100644 index 000000000..a6d2c122d --- /dev/null +++ b/apps/explorer/src/app/routes/oracles/OracleSpecs.graphql @@ -0,0 +1,22 @@ +query OracleSpecs { + oracleSpecs { + status + id + createdAt + updatedAt + pubKeys + filters { + key { + name + type + } + conditions { + value + operator + } + } + data { + pubKeys + } + } +} diff --git a/apps/explorer/src/app/routes/oracles/__generated___/OracleSpecs.ts b/apps/explorer/src/app/routes/oracles/__generated___/OracleSpecs.ts new file mode 100644 index 000000000..f146c789a --- /dev/null +++ b/apps/explorer/src/app/routes/oracles/__generated___/OracleSpecs.ts @@ -0,0 +1,62 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type OracleSpecsQueryVariables = Types.Exact<{ [key: string]: never; }>; + + +export type OracleSpecsQuery = { __typename?: 'Query', oracleSpecs?: Array<{ __typename?: 'OracleSpec', status: Types.OracleSpecStatus, id: string, createdAt: string, updatedAt?: string | null, pubKeys?: Array | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null, data: Array<{ __typename?: 'OracleData', pubKeys?: Array | null }> }> | null }; + + +export const OracleSpecsDocument = gql` + query OracleSpecs { + oracleSpecs { + status + id + createdAt + updatedAt + pubKeys + filters { + key { + name + type + } + conditions { + value + operator + } + } + data { + pubKeys + } + } +} + `; + +/** + * __useOracleSpecsQuery__ + * + * To run a query within a React component, call `useOracleSpecsQuery` and pass it any options that fit your needs. + * When your component renders, `useOracleSpecsQuery` 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 } = useOracleSpecsQuery({ + * variables: { + * }, + * }); + */ +export function useOracleSpecsQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(OracleSpecsDocument, options); + } +export function useOracleSpecsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(OracleSpecsDocument, options); + } +export type OracleSpecsQueryHookResult = ReturnType; +export type OracleSpecsLazyQueryHookResult = ReturnType; +export type OracleSpecsQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/explorer/src/app/routes/parties/PartyAssets.graphql b/apps/explorer/src/app/routes/parties/PartyAssets.graphql new file mode 100644 index 000000000..344ac3660 --- /dev/null +++ b/apps/explorer/src/app/routes/parties/PartyAssets.graphql @@ -0,0 +1,32 @@ +query PartyAssetsQuery($partyId: ID!) { + party(id: $partyId) { + id + delegations { + amount + node { + id + name + } + epoch + } + stake { + currentStakeAvailable + } + accounts { + asset { + name + id + decimals + symbol + source { + __typename + ... on ERC20 { + contractAddress + } + } + } + type + balance + } + } +} diff --git a/apps/explorer/src/app/routes/parties/__generated___/PartyAssets.ts b/apps/explorer/src/app/routes/parties/__generated___/PartyAssets.ts new file mode 100644 index 000000000..c3b1c42f0 --- /dev/null +++ b/apps/explorer/src/app/routes/parties/__generated___/PartyAssets.ts @@ -0,0 +1,75 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type PartyAssetsQueryQueryVariables = Types.Exact<{ + partyId: Types.Scalars['ID']; +}>; + + +export type PartyAssetsQueryQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, delegations?: Array<{ __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string, name: string } }> | null, stake: { __typename?: 'PartyStake', currentStakeAvailable: string }, accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } } }> | null } | null }; + + +export const PartyAssetsQueryDocument = gql` + query PartyAssetsQuery($partyId: ID!) { + party(id: $partyId) { + id + delegations { + amount + node { + id + name + } + epoch + } + stake { + currentStakeAvailable + } + accounts { + asset { + name + id + decimals + symbol + source { + __typename + ... on ERC20 { + contractAddress + } + } + } + type + balance + } + } +} + `; + +/** + * __usePartyAssetsQueryQuery__ + * + * To run a query within a React component, call `usePartyAssetsQueryQuery` and pass it any options that fit your needs. + * When your component renders, `usePartyAssetsQueryQuery` 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 } = usePartyAssetsQueryQuery({ + * variables: { + * partyId: // value for 'partyId' + * }, + * }); + */ +export function usePartyAssetsQueryQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(PartyAssetsQueryDocument, options); + } +export function usePartyAssetsQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(PartyAssetsQueryDocument, options); + } +export type PartyAssetsQueryQueryHookResult = ReturnType; +export type PartyAssetsQueryLazyQueryHookResult = ReturnType; +export type PartyAssetsQueryQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/explorer/src/app/routes/validators/Nodes.graphql b/apps/explorer/src/app/routes/validators/Nodes.graphql new file mode 100644 index 000000000..413ef2944 --- /dev/null +++ b/apps/explorer/src/app/routes/validators/Nodes.graphql @@ -0,0 +1,23 @@ +query NodesQuery { + nodes { + id + name + infoUrl + avatarUrl + pubkey + tmPubkey + ethereumAddress + location + stakedByOperator + stakedByDelegates + stakedTotal + pendingStake + epochData { + total + offline + online + } + status + name + } +} diff --git a/apps/explorer/src/app/routes/validators/__generated___/Nodes.ts b/apps/explorer/src/app/routes/validators/__generated___/Nodes.ts new file mode 100644 index 000000000..ddcb8e34f --- /dev/null +++ b/apps/explorer/src/app/routes/validators/__generated___/Nodes.ts @@ -0,0 +1,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 NodesQueryQueryVariables = Types.Exact<{ [key: string]: never; }>; + + +export type NodesQueryQuery = { __typename?: 'Query', nodes?: Array<{ __typename?: 'Node', id: string, name: string, infoUrl: string, avatarUrl?: string | null, pubkey: string, tmPubkey: string, ethereumAddress: string, location: string, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, status: Types.NodeStatus, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null }> | null }; + + +export const NodesQueryDocument = gql` + query NodesQuery { + nodes { + id + name + infoUrl + avatarUrl + pubkey + tmPubkey + ethereumAddress + location + stakedByOperator + stakedByDelegates + stakedTotal + pendingStake + epochData { + total + offline + online + } + status + name + } +} + `; + +/** + * __useNodesQueryQuery__ + * + * To run a query within a React component, call `useNodesQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useNodesQueryQuery` 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 } = useNodesQueryQuery({ + * variables: { + * }, + * }); + */ +export function useNodesQueryQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(NodesQueryDocument, options); + } +export function useNodesQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(NodesQueryDocument, options); + } +export type NodesQueryQueryHookResult = ReturnType; +export type NodesQueryLazyQueryHookResult = ReturnType; +export type NodesQueryQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/static/src/assets/mainnet-tranches.json b/apps/static/src/assets/mainnet-tranches.json index 17af2e84d..94c81a870 100644 --- a/apps/static/src/assets/mainnet-tranches.json +++ b/apps/static/src/assets/mainnet-tranches.json @@ -177,10 +177,15 @@ "tranche_id": 34, "tranche_start": "2023-02-01T00:00:00.000Z", "tranche_end": "2023-08-01T00:00:00.000Z", - "total_added": "30000", + "total_added": "37500", "total_removed": "0", - "locked_amount": "30000", + "locked_amount": "37500", "deposits": [ + { + "amount": "7500", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0x1a8578ff6c2531d666b92690b7fc02e0512588dae82a44a163f25010224b6272" + }, { "amount": "30000", "user": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600", @@ -189,6 +194,21 @@ ], "withdrawals": [], "users": [ + { + "address": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "deposits": [ + { + "amount": "7500", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 34, + "tx": "0x1a8578ff6c2531d666b92690b7fc02e0512588dae82a44a163f25010224b6272" + } + ], + "withdrawals": [], + "total_tokens": "7500", + "withdrawn_tokens": "0", + "remaining_tokens": "7500" + }, { "address": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600", "deposits": [ @@ -212,7 +232,7 @@ "tranche_end": "2023-12-05T00:00:00.000Z", "total_added": "129999.45", "total_removed": "0", - "locked_amount": "107996.023348302538472835", + "locked_amount": "106098.1360429719255366", "deposits": [ { "amount": "129999.45", @@ -278,7 +298,7 @@ "tranche_end": "2023-09-03T00:00:00.000Z", "total_added": "52600", "total_removed": "0", - "locked_amount": "52203.22326864535972", + "locked_amount": "51050.29485032978276", "deposits": [ { "amount": "2600", @@ -662,7 +682,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "97499.58", "total_removed": "0", - "locked_amount": "49156.240242964405462782", + "locked_amount": "47294.5895926345761588126", "deposits": [ { "amount": "97499.58", @@ -695,7 +715,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "135173.4239508", "total_removed": "0", - "locked_amount": "67188.09394129019011339723764", + "locked_amount": "64643.53890286602609186297228", "deposits": [ { "amount": "135173.4239508", @@ -728,7 +748,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "32499.86", "total_removed": "0", - "locked_amount": "20679.181387351489634202", + "locked_amount": "19896.017107744868930832", "deposits": [ { "amount": "32499.86", @@ -761,7 +781,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "10833.29", "total_removed": "0", - "locked_amount": "6730.87287555657587691", + "locked_amount": "6475.960502190905203881", "deposits": [ { "amount": "10833.29", @@ -867,10 +887,15 @@ "tranche_id": 32, "tranche_start": "2022-05-01T00:00:00.000Z", "tranche_end": "2022-11-01T00:00:00.000Z", - "total_added": "22500", + "total_added": "30000", "total_removed": "0", - "locked_amount": "6877.99337635869525", + "locked_amount": "7866.2515096618368", "deposits": [ + { + "amount": "7500", + "user": "0xd481bCC42265089abEA41Efdb655EDCF8fF9068c", + "tx": "0xef4f76136a4f364a8f6f6a66bbbf905542bdc8c988f54628df9d408a06c290b1" + }, { "amount": "15000", "user": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1", @@ -884,6 +909,27 @@ ], "withdrawals": [], "users": [ + { + "address": "0xd481bCC42265089abEA41Efdb655EDCF8fF9068c", + "deposits": [ + { + "amount": "7500", + "user": "0xd481bCC42265089abEA41Efdb655EDCF8fF9068c", + "tranche_id": 32, + "tx": "0xef4f76136a4f364a8f6f6a66bbbf905542bdc8c988f54628df9d408a06c290b1" + }, + { + "amount": "7500", + "user": "0xd481bCC42265089abEA41Efdb655EDCF8fF9068c", + "tranche_id": 32, + "tx": "0x72aca81fa924e10e855192abff443242225b9853f730feee595acdc1f500b139" + } + ], + "withdrawals": [], + "total_tokens": "15000", + "withdrawn_tokens": "0", + "remaining_tokens": "15000" + }, { "address": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1", "deposits": [ @@ -898,21 +944,6 @@ "total_tokens": "15000", "withdrawn_tokens": "0", "remaining_tokens": "15000" - }, - { - "address": "0xd481bCC42265089abEA41Efdb655EDCF8fF9068c", - "deposits": [ - { - "amount": "7500", - "user": "0xd481bCC42265089abEA41Efdb655EDCF8fF9068c", - "tranche_id": 32, - "tx": "0x72aca81fa924e10e855192abff443242225b9853f730feee595acdc1f500b139" - } - ], - "withdrawals": [], - "total_tokens": "7500", - "withdrawn_tokens": "0", - "remaining_tokens": "7500" } ] }, @@ -920,10 +951,15 @@ "tranche_id": 33, "tranche_start": "2022-11-01T00:00:00.000Z", "tranche_end": "2023-05-01T00:00:00.000Z", - "total_added": "15000", + "total_added": "22500", "total_removed": "0", - "locked_amount": "15000", + "locked_amount": "22500", "deposits": [ + { + "amount": "7500", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0x1a8578ff6c2531d666b92690b7fc02e0512588dae82a44a163f25010224b6272" + }, { "amount": "15000", "user": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1", @@ -932,6 +968,21 @@ ], "withdrawals": [], "users": [ + { + "address": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "deposits": [ + { + "amount": "7500", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 33, + "tx": "0x1a8578ff6c2531d666b92690b7fc02e0512588dae82a44a163f25010224b6272" + } + ], + "withdrawals": [], + "total_tokens": "7500", + "withdrawn_tokens": "0", + "remaining_tokens": "7500" + }, { "address": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1", "deposits": [ @@ -955,7 +1006,7 @@ "tranche_end": "2023-06-02T00:00:00.000Z", "total_added": "1939928.38", "total_removed": "479504.6187210477481", - "locked_amount": "1431011.82807038631089486", + "locked_amount": "1388490.942922118064795974", "deposits": [ { "amount": "1852091.69", @@ -1241,7 +1292,7 @@ "tranche_end": "2023-02-01T00:00:00.000Z", "total_added": "42500", "total_removed": "0", - "locked_amount": "34241.76526645531325", + "locked_amount": "32393.8563053542705", "deposits": [ { "amount": "12500", @@ -2107,8 +2158,8 @@ "tranche_start": "2021-09-05T00:00:00.000Z", "tranche_end": "2022-09-30T00:00:00.000Z", "total_added": "60916.66666633337", - "total_removed": "20356.27207904634556896", - "locked_amount": "3787.2518622181223065369776702388", + "total_removed": "20696.25757434884556896", + "locked_amount": "2537.6231698974791687009338450295", "deposits": [ { "amount": "2833.333333", @@ -2212,6 +2263,11 @@ "user": "0x5D39036947e83862cE5f3DB351cC64E3D4592cD5", "tx": "0xf2b3af016afc01b1c8b2a3a5199c9c0cd24253fa77dbf68463cd28eeeb8d9464" }, + { + "amount": "339.9854953025", + "user": "0x1887D97F9C875108Aa6bE109B282f87A666472f2", + "tx": "0xc9a2adf607544c56be07d99cd336298e81f16220a3cac0d25f9b606c54cd9169" + }, { "amount": "279.862130034666196311", "user": "0x832cfD8fD4a1791b5eF5BD18a677beb7731Aa18E", @@ -2898,6 +2954,12 @@ } ], "withdrawals": [ + { + "amount": "339.9854953025", + "user": "0x1887D97F9C875108Aa6bE109B282f87A666472f2", + "tranche_id": 13, + "tx": "0xc9a2adf607544c56be07d99cd336298e81f16220a3cac0d25f9b606c54cd9169" + }, { "amount": "326.9768073225", "user": "0x1887D97F9C875108Aa6bE109B282f87A666472f2", @@ -2978,8 +3040,8 @@ } ], "total_tokens": "4250", - "withdrawn_tokens": "3668.79837368", - "remaining_tokens": "581.20162632" + "withdrawn_tokens": "4008.7838689825", + "remaining_tokens": "241.2161310175" }, { "address": "0x9fd50776F133751E8Ae6abE1Be124638Bb917E05", @@ -5830,10 +5892,35 @@ "tranche_id": 11, "tranche_start": "2021-09-03T00:00:00.000Z", "tranche_end": "2022-09-03T00:00:00.000Z", - "total_added": "35910.000000000000000003", - "total_removed": "16162.59106856284", + "total_added": "35972.000000000000000003", + "total_removed": "17098.49537348884", "locked_amount": "0", "deposits": [ + { + "amount": "20", + "user": "0x9e02d57941833BB800cF0343b65A3D9dCa935b91", + "tx": "0xff09c5e98e22a7b1d26e68f44124c6bfca8c49fb0a7c704ba309def7ac50f4be" + }, + { + "amount": "12", + "user": "0xBdEF6D978a33cC8E7cf06E659dEd1487953355D2", + "tx": "0xf4cf2b397b085b21cbb4bc9213de71bb6fe310704e39e61b9bcb7b2b0602f2f4" + }, + { + "amount": "2", + "user": "0xEED071df0b6f8C4088b9CfD9f2ADE131C8591613", + "tx": "0x0d569e9b901099d43f017945635ad8c2b566ce2290abb2583b018e83df34642b" + }, + { + "amount": "2", + "user": "0x60901F5a6a66BCaD910A97e85373A00996B361f5", + "tx": "0xa87cd2caf4f27d7a60443ec952b831b005a809803fc899c4bcc3ca12016299eb" + }, + { + "amount": "12", + "user": "0x60901F5a6a66BCaD910A97e85373A00996B361f5", + "tx": "0x056bbadf095fbbee4dc0ccac4431c998c65ad3e714a76844c71bdb0509b0ced5" + }, { "amount": "15", "user": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f", @@ -7354,6 +7441,26 @@ "user": "0xaaaaFd67947Ef241D8C24C863893800083855Ed6", "tx": "0xd5947eb1f6aca62cd34eaee000f7b0508530096a2aaf6b1b83a78485b8600aeb" }, + { + "amount": "5", + "user": "0xd7F6bad6Fc716b889F84a94fEE046188f08988ce", + "tx": "0x5526139947d7ddefa84e8ec476916c897754efb459d268e27086d8a6f0aeebf9" + }, + { + "amount": "2", + "user": "0xd7F6bad6Fc716b889F84a94fEE046188f08988ce", + "tx": "0xbdbedb936d857d6897aeb89be44c8dbfdc87993d69b0e9a3cf6aa6fed0fb9e2b" + }, + { + "amount": "5", + "user": "0x5c95482329D44397d88AC5e1AcE402cFA56837bD", + "tx": "0x51ee75107b429e4b28d03503d87dfb8b5989118c14496e2ead9639eccc35a871" + }, + { + "amount": "2", + "user": "0x5c95482329D44397d88AC5e1AcE402cFA56837bD", + "tx": "0x6a2277eca905e60445ee11479edfe603a63c86d2fadb8aae244b314f40986e6a" + }, { "amount": "30", "user": "0x9646850641B15535e9e46646fbb98907eba83c6c", @@ -11761,6 +11868,21 @@ } ], "withdrawals": [ + { + "amount": "44.915525116", + "user": "0x3f626D48C2a6104976A03009cFDB4A48F32fd282", + "tx": "0x2d81729f37b9abefd460e8439566e1afd19b395ae58102a523dc192a4d57666a" + }, + { + "amount": "9.565809234", + "user": "0x9a563fbC59C9058414f89172DA667B2b337215B1", + "tx": "0xb25834209752fdf0186cc3d71002fb315cf8dc16f70aad0efe6185d5d6f400b7" + }, + { + "amount": "252.422970576", + "user": "0x95175E9AEF72e1c5cEbE2766216FD6dAd2B9cDE6", + "tx": "0x427c4a75b78bd0988ab9f5f0d65ce4af60f2b1f67a38f7f01ae6306f64ae7498" + }, { "amount": "13.82033422112", "user": "0xb1169C6daAc76bAcaf0D8f87641Fc38fbabe569F", @@ -11896,6 +12018,21 @@ "user": "0xaaaaFd67947Ef241D8C24C863893800083855Ed6", "tx": "0x26f83e1b57a646b5266f07b00f13f47d3983978d96e921349b24a8b2df0fbc3d" }, + { + "amount": "570", + "user": "0x33Ce1D9E53AFb7367E34749517C086405a651a95", + "tx": "0x818a1a6d0d22a088d468459803255b5f698843f7a89829991e2dc7920d8e8be6" + }, + { + "amount": "14", + "user": "0x78F9D0EcdDE97c1cAa507E49a3B5b22d1b60a674", + "tx": "0x7aa284f9f9772a9fd308d4d1208dd02228428dfe8630020b8e841131b8647a46" + }, + { + "amount": "45", + "user": "0x5CB43a4d38714B23112F884D6c8B4725c6fc4534", + "tx": "0x0430c0285ab80a4afe7d9ec9c5f6d744fca47ffb40da848a6a1313ac70d6023a" + }, { "amount": "3.678519786", "user": "0xc5467213593778E528f0eB8117cc7AFBC5b7491b", @@ -12358,6 +12495,72 @@ } ], "users": [ + { + "address": "0x9e02d57941833BB800cF0343b65A3D9dCa935b91", + "deposits": [ + { + "amount": "20", + "user": "0x9e02d57941833BB800cF0343b65A3D9dCa935b91", + "tranche_id": 11, + "tx": "0xff09c5e98e22a7b1d26e68f44124c6bfca8c49fb0a7c704ba309def7ac50f4be" + } + ], + "withdrawals": [], + "total_tokens": "20", + "withdrawn_tokens": "0", + "remaining_tokens": "20" + }, + { + "address": "0xBdEF6D978a33cC8E7cf06E659dEd1487953355D2", + "deposits": [ + { + "amount": "12", + "user": "0xBdEF6D978a33cC8E7cf06E659dEd1487953355D2", + "tranche_id": 11, + "tx": "0xf4cf2b397b085b21cbb4bc9213de71bb6fe310704e39e61b9bcb7b2b0602f2f4" + } + ], + "withdrawals": [], + "total_tokens": "12", + "withdrawn_tokens": "0", + "remaining_tokens": "12" + }, + { + "address": "0xEED071df0b6f8C4088b9CfD9f2ADE131C8591613", + "deposits": [ + { + "amount": "2", + "user": "0xEED071df0b6f8C4088b9CfD9f2ADE131C8591613", + "tranche_id": 11, + "tx": "0x0d569e9b901099d43f017945635ad8c2b566ce2290abb2583b018e83df34642b" + } + ], + "withdrawals": [], + "total_tokens": "2", + "withdrawn_tokens": "0", + "remaining_tokens": "2" + }, + { + "address": "0x60901F5a6a66BCaD910A97e85373A00996B361f5", + "deposits": [ + { + "amount": "2", + "user": "0x60901F5a6a66BCaD910A97e85373A00996B361f5", + "tranche_id": 11, + "tx": "0xa87cd2caf4f27d7a60443ec952b831b005a809803fc899c4bcc3ca12016299eb" + }, + { + "amount": "12", + "user": "0x60901F5a6a66BCaD910A97e85373A00996B361f5", + "tranche_id": 11, + "tx": "0x056bbadf095fbbee4dc0ccac4431c998c65ad3e714a76844c71bdb0509b0ced5" + } + ], + "withdrawals": [], + "total_tokens": "14", + "withdrawn_tokens": "0", + "remaining_tokens": "14" + }, { "address": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f", "deposits": [ @@ -14583,10 +14786,17 @@ "tx": "0x2368becf6a676e7a6a866d621fc7d6f321b70463f1d7fd00e2f88802d3c8807c" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "570", + "user": "0x33Ce1D9E53AFb7367E34749517C086405a651a95", + "tranche_id": 11, + "tx": "0x818a1a6d0d22a088d468459803255b5f698843f7a89829991e2dc7920d8e8be6" + } + ], "total_tokens": "570", - "withdrawn_tokens": "0", - "remaining_tokens": "570" + "withdrawn_tokens": "570", + "remaining_tokens": "0" }, { "address": "0x94097462EF7c43D0aC732E7B18f830096D95207C", @@ -15794,6 +16004,48 @@ "withdrawn_tokens": "3467", "remaining_tokens": "0" }, + { + "address": "0xd7F6bad6Fc716b889F84a94fEE046188f08988ce", + "deposits": [ + { + "amount": "5", + "user": "0xd7F6bad6Fc716b889F84a94fEE046188f08988ce", + "tranche_id": 11, + "tx": "0x5526139947d7ddefa84e8ec476916c897754efb459d268e27086d8a6f0aeebf9" + }, + { + "amount": "2", + "user": "0xd7F6bad6Fc716b889F84a94fEE046188f08988ce", + "tranche_id": 11, + "tx": "0xbdbedb936d857d6897aeb89be44c8dbfdc87993d69b0e9a3cf6aa6fed0fb9e2b" + } + ], + "withdrawals": [], + "total_tokens": "7", + "withdrawn_tokens": "0", + "remaining_tokens": "7" + }, + { + "address": "0x5c95482329D44397d88AC5e1AcE402cFA56837bD", + "deposits": [ + { + "amount": "5", + "user": "0x5c95482329D44397d88AC5e1AcE402cFA56837bD", + "tranche_id": 11, + "tx": "0x51ee75107b429e4b28d03503d87dfb8b5989118c14496e2ead9639eccc35a871" + }, + { + "amount": "2", + "user": "0x5c95482329D44397d88AC5e1AcE402cFA56837bD", + "tranche_id": 11, + "tx": "0x6a2277eca905e60445ee11479edfe603a63c86d2fadb8aae244b314f40986e6a" + } + ], + "withdrawals": [], + "total_tokens": "7", + "withdrawn_tokens": "0", + "remaining_tokens": "7" + }, { "address": "0x9646850641B15535e9e46646fbb98907eba83c6c", "deposits": [ @@ -16303,10 +16555,17 @@ "tx": "0x998b804da42b26f962aea89fe7e7545a3b12c2ea33620f015d6af7baa00eca43" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "45", + "user": "0x5CB43a4d38714B23112F884D6c8B4725c6fc4534", + "tranche_id": 11, + "tx": "0x0430c0285ab80a4afe7d9ec9c5f6d744fca47ffb40da848a6a1313ac70d6023a" + } + ], "total_tokens": "45", - "withdrawn_tokens": "0", - "remaining_tokens": "45" + "withdrawn_tokens": "45", + "remaining_tokens": "0" }, { "address": "0xb99dE8d636Be333Ec5C8Ce1476e9b6FE7877F02a", @@ -19061,6 +19320,12 @@ } ], "withdrawals": [ + { + "amount": "9.565809234", + "user": "0x9a563fbC59C9058414f89172DA667B2b337215B1", + "tranche_id": 11, + "tx": "0xb25834209752fdf0186cc3d71002fb315cf8dc16f70aad0efe6185d5d6f400b7" + }, { "amount": "5.1102869736", "user": "0x9a563fbC59C9058414f89172DA667B2b337215B1", @@ -19075,8 +19340,8 @@ } ], "total_tokens": "20", - "withdrawn_tokens": "10.434190766", - "remaining_tokens": "9.565809234" + "withdrawn_tokens": "20", + "remaining_tokens": "0" }, { "address": "0xF1bfCb79a510faC196c4Da74009Ea67e0926b25f", @@ -19574,10 +19839,17 @@ "tx": "0xd22eddc248147913179e4e423aaa27c8c1716173210ad6d51c2e83c8c0a816e0" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "14", + "user": "0x78F9D0EcdDE97c1cAa507E49a3B5b22d1b60a674", + "tranche_id": 11, + "tx": "0x7aa284f9f9772a9fd308d4d1208dd02228428dfe8630020b8e841131b8647a46" + } + ], "total_tokens": "14", - "withdrawn_tokens": "0", - "remaining_tokens": "14" + "withdrawn_tokens": "14", + "remaining_tokens": "0" }, { "address": "0x2EF021a31E666Bd0D3Fb39771B7A70C55d3B3749", @@ -21961,6 +22233,12 @@ } ], "withdrawals": [ + { + "amount": "44.915525116", + "user": "0x3f626D48C2a6104976A03009cFDB4A48F32fd282", + "tranche_id": 11, + "tx": "0x2d81729f37b9abefd460e8439566e1afd19b395ae58102a523dc192a4d57666a" + }, { "amount": "36.75952562", "user": "0x3f626D48C2a6104976A03009cFDB4A48F32fd282", @@ -21987,8 +22265,8 @@ } ], "total_tokens": "200", - "withdrawn_tokens": "155.084474884", - "remaining_tokens": "44.915525116" + "withdrawn_tokens": "200", + "remaining_tokens": "0" }, { "address": "0x6f5EBA1eCc26B8f1203a1D32116f286fAd383a2d", @@ -22031,6 +22309,12 @@ } ], "withdrawals": [ + { + "amount": "252.422970576", + "user": "0x95175E9AEF72e1c5cEbE2766216FD6dAd2B9cDE6", + "tranche_id": 11, + "tx": "0x427c4a75b78bd0988ab9f5f0d65ce4af60f2b1f67a38f7f01ae6306f64ae7498" + }, { "amount": "100.94326484", "user": "0x95175E9AEF72e1c5cEbE2766216FD6dAd2B9cDE6", @@ -22045,8 +22329,8 @@ } ], "total_tokens": "400", - "withdrawn_tokens": "147.577029424", - "remaining_tokens": "252.422970576" + "withdrawn_tokens": "400", + "remaining_tokens": "0" }, { "address": "0xc5467213593778E528f0eB8117cc7AFBC5b7491b", @@ -22201,8 +22485,8 @@ "tranche_start": "2022-03-05T00:00:00.000Z", "tranche_end": "2023-06-05T00:00:00.000Z", "total_added": "3732368.4671", - "total_removed": "202112.7281627920977", - "locked_amount": "2223468.2790719446818264312", + "total_removed": "204390.7646836173642", + "locked_amount": "2158128.48279889755415607996", "deposits": [ { "amount": "1998.95815", @@ -22391,6 +22675,11 @@ "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", "tx": "0x8d749e9b03d9656e6bb458d20f0ef55b1778785744415241b12f4875b1dc4749" }, + { + "amount": "2278.0365208252665", + "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", + "tx": "0x6c2bbcd7abbfd0627b6dc419214ae9d52c3f6755ed5b2ab867ff0aa504ebe70a" + }, { "amount": "10764.1909763241854", "user": "0xf110D577F07ED846D2308050cc0D6CCC2bf9fb2C", @@ -22544,6 +22833,12 @@ "tranche_id": 1, "tx": "0x8d749e9b03d9656e6bb458d20f0ef55b1778785744415241b12f4875b1dc4749" }, + { + "amount": "2278.0365208252665", + "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", + "tranche_id": 1, + "tx": "0x6c2bbcd7abbfd0627b6dc419214ae9d52c3f6755ed5b2ab867ff0aa504ebe70a" + }, { "amount": "9453.4744822303375", "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", @@ -22576,8 +22871,8 @@ } ], "total_tokens": "187637.95", - "withdrawn_tokens": "74870.259332725684", - "remaining_tokens": "112767.690667274316" + "withdrawn_tokens": "77148.2958535509505", + "remaining_tokens": "110489.6541464490495" }, { "address": "0x1A71e3ED1996CAbB91bB043f880CE963D601707e", @@ -23057,10 +23352,20 @@ "tranche_id": 2, "tranche_start": "2022-06-05T00:00:00.000Z", "tranche_end": "2023-12-05T00:00:00.000Z", - "total_added": "15788853.065470999700000001", - "total_removed": "188731.5544957414143694", - "locked_amount": "13116465.8335210202174881886663000658191403", + "total_added": "15870102.715470999700000001", + "total_removed": "203595.9963255265343694", + "locked_amount": "12952272.620553243128136100283526560935388", "deposits": [ + { + "amount": "16249.93", + "user": "0x2c49f0C25B9195254eEE5d055F07E3bb96c4408a", + "tx": "0x584b243629e46fc25f8cb79481a2cdcc5cf06eabe498fee89910367b6ff88c47" + }, + { + "amount": "64999.72", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0xd69f6d2ce85154dc321c43f1eb099f9eee07c1ecfd59142d40ea2ed42f90f75a" + }, { "amount": "16249.93", "user": "0x2c49f0C25B9195254eEE5d055F07E3bb96c4408a", @@ -23553,6 +23858,41 @@ } ], "withdrawals": [ + { + "amount": "504.652814859004625", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0xaa8f8f3648686e5e54cd714feec5dcbafd6c41cb2bc6fd62ef19466a74b11ab4" + }, + { + "amount": "425.14391486681125", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0xc2f65321097ea346926566cb1b8dc49ecc68fd085a86316d5a6bb96408c21332" + }, + { + "amount": "425.187841678854375", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0xa75ec8ccff824d09c109e9fdcd99aac9a0eb34562500cd450ed205d57ac8ae45" + }, + { + "amount": "262.71599547386325", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0xb4d350dd5fcd3f1617fb1eaac7f77fd973f0275bcc35003934ccc9a4e6140cdb" + }, + { + "amount": "226.87960521292", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0xe0040011ab92c3d951d3449fa6159e095b1893639c47fdb1a72aa87c741bdf56" + }, + { + "amount": "208.439735314624", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0xa2cf8d5f7caa97b4c6804c0bce8003115d61772edf6ab6f8c9b3de503eafd2f5" + }, + { + "amount": "337.211316118483125", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0x1e6bd91941381b74b4bec158b2366838830987396925340281bce36d0a75a514" + }, { "amount": "305.8599694076328", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -23638,6 +23978,26 @@ "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", "tx": "0xc8f2fce1918c3ab277e3150dd0a85466501c7c324d49286baa8bf0d509dcded3" }, + { + "amount": "275.724948211541775", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0x60b78351e0667b1c1cff667a84e4b0b1cd29b1c5ecee8e3de592ea81166958fe" + }, + { + "amount": "176.8234276967589", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0xf37aa848c357e251da436706cf8976171a8141e31fe3d2b6b90c519fb5e28c6e" + }, + { + "amount": "11896.4978839940612", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0xf59861d62aa335573fa03b596b554b43fd958e759ad23301f7cffffb52945c0d" + }, + { + "amount": "125.1643463581975", + "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", + "tx": "0x87eaac3c9200157a9a8af51edba2a22a199a057e57c7a22c8af0909d5a608f6d" + }, { "amount": "253.966945001875125", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -24033,6 +24393,12 @@ { "address": "0x2c49f0C25B9195254eEE5d055F07E3bb96c4408a", "deposits": [ + { + "amount": "16249.93", + "user": "0x2c49f0C25B9195254eEE5d055F07E3bb96c4408a", + "tranche_id": 2, + "tx": "0x584b243629e46fc25f8cb79481a2cdcc5cf06eabe498fee89910367b6ff88c47" + }, { "amount": "16249.93", "user": "0x2c49f0C25B9195254eEE5d055F07E3bb96c4408a", @@ -24053,13 +24419,19 @@ } ], "withdrawals": [], - "total_tokens": "81249.65", + "total_tokens": "97499.58", "withdrawn_tokens": "0", - "remaining_tokens": "81249.65" + "remaining_tokens": "97499.58" }, { "address": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", "deposits": [ + { + "amount": "64999.72", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0xd69f6d2ce85154dc321c43f1eb099f9eee07c1ecfd59142d40ea2ed42f90f75a" + }, { "amount": "64999.7225", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -24074,6 +24446,48 @@ } ], "withdrawals": [ + { + "amount": "504.652814859004625", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0xaa8f8f3648686e5e54cd714feec5dcbafd6c41cb2bc6fd62ef19466a74b11ab4" + }, + { + "amount": "425.14391486681125", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0xc2f65321097ea346926566cb1b8dc49ecc68fd085a86316d5a6bb96408c21332" + }, + { + "amount": "425.187841678854375", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0xa75ec8ccff824d09c109e9fdcd99aac9a0eb34562500cd450ed205d57ac8ae45" + }, + { + "amount": "262.71599547386325", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0xb4d350dd5fcd3f1617fb1eaac7f77fd973f0275bcc35003934ccc9a4e6140cdb" + }, + { + "amount": "226.87960521292", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0xe0040011ab92c3d951d3449fa6159e095b1893639c47fdb1a72aa87c741bdf56" + }, + { + "amount": "208.439735314624", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0xa2cf8d5f7caa97b4c6804c0bce8003115d61772edf6ab6f8c9b3de503eafd2f5" + }, + { + "amount": "337.211316118483125", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0x1e6bd91941381b74b4bec158b2366838830987396925340281bce36d0a75a514" + }, { "amount": "305.8599694076328", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -24140,6 +24554,24 @@ "tranche_id": 2, "tx": "0xc8f2fce1918c3ab277e3150dd0a85466501c7c324d49286baa8bf0d509dcded3" }, + { + "amount": "275.724948211541775", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0x60b78351e0667b1c1cff667a84e4b0b1cd29b1c5ecee8e3de592ea81166958fe" + }, + { + "amount": "176.8234276967589", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0xf37aa848c357e251da436706cf8976171a8141e31fe3d2b6b90c519fb5e28c6e" + }, + { + "amount": "11896.4978839940612", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0xf59861d62aa335573fa03b596b554b43fd958e759ad23301f7cffffb52945c0d" + }, { "amount": "253.966945001875125", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -24513,9 +24945,9 @@ "tx": "0x42428fc448690e236a517d10ecc478b21a8519a8305c56a04c76ddbafe5764f8" } ], - "total_tokens": "194999.1675", - "withdrawn_tokens": "32941.973362763306625", - "remaining_tokens": "162057.194137236693375" + "total_tokens": "259998.8875", + "withdrawn_tokens": "47681.250846190229125", + "remaining_tokens": "212317.636653809770875" }, { "address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c", @@ -25409,6 +25841,12 @@ "tranche_id": 2, "tx": "0x512e9f05b8acfc34d562ab3fa128a36e4f212b3c53bbcfb8bd0270bc81800da0" }, + { + "amount": "125.1643463581975", + "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", + "tranche_id": 2, + "tx": "0x87eaac3c9200157a9a8af51edba2a22a199a057e57c7a22c8af0909d5a608f6d" + }, { "amount": "519.4281860825575", "user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0", @@ -25429,8 +25867,8 @@ } ], "total_tokens": "12362.05", - "withdrawn_tokens": "2038.1690775099675", - "remaining_tokens": "10323.8809224900325" + "withdrawn_tokens": "2163.333423868165", + "remaining_tokens": "10198.716576131835" }, { "address": "0xb091D456d0dFCB94dcba6f355379056C5bb995fC", @@ -26054,8 +26492,8 @@ "tranche_start": "2021-11-05T00:00:00.000Z", "tranche_end": "2023-05-05T00:00:00.000Z", "total_added": "14597706.0446472999", - "total_removed": "2723422.352074488493348197", - "locked_amount": "6449905.55149414870763985024766746", + "total_removed": "2765441.081300436948788147", + "locked_amount": "6236010.1559629377107703982051563", "deposits": [ { "amount": "129284.449", @@ -26264,6 +26702,41 @@ } ], "withdrawals": [ + { + "amount": "700.967684681521309", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x90b39e5e04dcd5d2462bebe30b4439f85471a37ca0ee2f8f9b38662544591604" + }, + { + "amount": "588.2239383228802295", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x774bb17750d10bb5c5222b6546f8d2cf224accd19753cb62fecbc74eba2221f7" + }, + { + "amount": "589.51048019645918825", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x6516c57ea0a2048d0ca87cbc0bee8a7a4fd0ec7a58bc7fbc33bf56e8fe02593d" + }, + { + "amount": "365.035475050653914", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x3f54acc3bba8d596eea3553509f34983148ff873565c53d993b2248a89d8c057" + }, + { + "amount": "313.53571506354713525", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x5940c1d1266c4aee837eb2a10ea1a42f52182c5fb2d9f4ca10752ec099ddc239" + }, + { + "amount": "288.65748698602475075", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x0fb5472a41850ad312926ca6a39df1901579d075b0b8836459e2cd7f96353a8b" + }, + { + "amount": "469.0627058402196405", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x6e6546452d57d7d58c5fd0671b8a43c2c6024bf845d085fc3133c6851ab18620" + }, { "amount": "551.363354573845008", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -26329,6 +26802,26 @@ "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", "tx": "0xf9105de9d07cbdcb51de4eb487d7c2d5690e3fc4ddd340ad51557884e655cf1e" }, + { + "amount": "511.807886761710812", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x5afda258c29ba6cd1e54d2b04fe6ebadc2a5d7650dd477b25291bdeeea468c8b" + }, + { + "amount": "325.43433032442447375", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x453738b2f8fbd7d2c25f32200d27bbd13c15bb92a38879cd6ea854805a5b38bd" + }, + { + "amount": "36806.4510907456099182", + "user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8", + "tx": "0x812fe72d2aa855b5035e0a691d365682ccab0e0160d77e6405f4481841ac70cb" + }, + { + "amount": "1060.04243197540406875", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x98bccb30eb3a5a92c35444e40f36bc89cdbf17b9508fa05845a8ca9478aacd9a" + }, { "amount": "469.2149598263806575", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -28315,6 +28808,48 @@ } ], "withdrawals": [ + { + "amount": "700.967684681521309", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x90b39e5e04dcd5d2462bebe30b4439f85471a37ca0ee2f8f9b38662544591604" + }, + { + "amount": "588.2239383228802295", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x774bb17750d10bb5c5222b6546f8d2cf224accd19753cb62fecbc74eba2221f7" + }, + { + "amount": "589.51048019645918825", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x6516c57ea0a2048d0ca87cbc0bee8a7a4fd0ec7a58bc7fbc33bf56e8fe02593d" + }, + { + "amount": "365.035475050653914", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x3f54acc3bba8d596eea3553509f34983148ff873565c53d993b2248a89d8c057" + }, + { + "amount": "313.53571506354713525", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x5940c1d1266c4aee837eb2a10ea1a42f52182c5fb2d9f4ca10752ec099ddc239" + }, + { + "amount": "288.65748698602475075", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x0fb5472a41850ad312926ca6a39df1901579d075b0b8836459e2cd7f96353a8b" + }, + { + "amount": "469.0627058402196405", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x6e6546452d57d7d58c5fd0671b8a43c2c6024bf845d085fc3133c6851ab18620" + }, { "amount": "551.363354573845008", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -28393,6 +28928,24 @@ "tranche_id": 3, "tx": "0xf9105de9d07cbdcb51de4eb487d7c2d5690e3fc4ddd340ad51557884e655cf1e" }, + { + "amount": "511.807886761710812", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x5afda258c29ba6cd1e54d2b04fe6ebadc2a5d7650dd477b25291bdeeea468c8b" + }, + { + "amount": "325.43433032442447375", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x453738b2f8fbd7d2c25f32200d27bbd13c15bb92a38879cd6ea854805a5b38bd" + }, + { + "amount": "1060.04243197540406875", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x98bccb30eb3a5a92c35444e40f36bc89cdbf17b9508fa05845a8ca9478aacd9a" + }, { "amount": "469.2149598263806575", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -30033,8 +30586,8 @@ } ], "total_tokens": "359123.469575", - "withdrawn_tokens": "200329.155688339931396", - "remaining_tokens": "158794.313886660068604" + "withdrawn_tokens": "205541.43382354277691775", + "remaining_tokens": "153582.03575145722308225" }, { "address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB", @@ -30233,6 +30786,12 @@ } ], "withdrawals": [ + { + "amount": "36806.4510907456099182", + "user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8", + "tranche_id": 3, + "tx": "0x812fe72d2aa855b5035e0a691d365682ccab0e0160d77e6405f4481841ac70cb" + }, { "amount": "137101.36006182319864782", "user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8", @@ -30451,8 +31010,8 @@ } ], "total_tokens": "1266324.603486", - "withdrawn_tokens": "675973.69081026210943794", - "remaining_tokens": "590350.91267573789056206" + "withdrawn_tokens": "712780.14190100771935614", + "remaining_tokens": "553544.46158499228064386" }, { "address": "0xC5d9221EB9c28A69859264c0A2Fe0d3272228296", @@ -31115,8 +31674,8 @@ "tranche_start": "2021-10-05T00:00:00.000Z", "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "5778205.3912159303", - "total_removed": "1733643.914423703455421207", - "locked_amount": "2231493.288559158210914140485303645", + "total_removed": "1773434.744647395163801354", + "locked_amount": "2146981.92415619473594330314378902", "deposits": [ { "amount": "552496.6455", @@ -31260,6 +31819,26 @@ } ], "withdrawals": [ + { + "amount": "6706.456487239706063047", + "user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d", + "tx": "0x16d7023014cfb5e7562d6f583c5354dd9f2988ca3a5766539acb3fa0652828bd" + }, + { + "amount": "5857.0305210567902251", + "user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D", + "tx": "0xb2b7e68756635897d3d0cc97221a6c9abedce9da7a431baeee6620f15125a7ae" + }, + { + "amount": "18665.776068468384566", + "user": "0x5565d64f29Ea17355106DF3bA5903Eb793B3e139", + "tx": "0x0954f744fc48cdb36187ba72505a5ca1c053d05da816b41230b35d86069fdcb0" + }, + { + "amount": "3639.282239117673375", + "user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90", + "tx": "0x2a7ebd8748742d3bf0ce4f1ee46c575aa744f0d83915583bbd262f504044d462" + }, { "amount": "8456.402651116281081", "user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90", @@ -31280,6 +31859,11 @@ "user": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75", "tx": "0xfb1b77baaf2cbb53d3bf17c91c3dd1da059cd4b99413598693606a4f1a2d4199" }, + { + "amount": "4922.284907809154151", + "user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90", + "tx": "0xb34ad795d45f3428f8447ab1573fe696a946897cc7a6f5e2e2c17441821ad8d0" + }, { "amount": "1729.052213861087673", "user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90", @@ -32000,6 +32584,12 @@ } ], "withdrawals": [ + { + "amount": "5857.0305210567902251", + "user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D", + "tranche_id": 4, + "tx": "0xb2b7e68756635897d3d0cc97221a6c9abedce9da7a431baeee6620f15125a7ae" + }, { "amount": "3732.88753415684792995", "user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D", @@ -32044,8 +32634,8 @@ } ], "total_tokens": "92082.572555", - "withdrawn_tokens": "51310.4888289328312056", - "remaining_tokens": "40772.0837260671687944" + "withdrawn_tokens": "57167.5193499896214307", + "remaining_tokens": "34915.0532050103785693" }, { "address": "0x1dC9B91DE003fd503F25cB5d114cf0fc68F7aFe6", @@ -32073,6 +32663,12 @@ } ], "withdrawals": [ + { + "amount": "6706.456487239706063047", + "user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d", + "tranche_id": 4, + "tx": "0x16d7023014cfb5e7562d6f583c5354dd9f2988ca3a5766539acb3fa0652828bd" + }, { "amount": "22577.531268180478865098", "user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d", @@ -32135,8 +32731,8 @@ } ], "total_tokens": "460415.072915097", - "withdrawn_tokens": "279128.566868329684778032", - "remaining_tokens": "181286.506046767315221968" + "withdrawn_tokens": "285835.023355569390841079", + "remaining_tokens": "174580.049559527609158921" }, { "address": "0xd66e4853c0880df150e7329974715BFC8d2da47D", @@ -32238,6 +32834,12 @@ } ], "withdrawals": [ + { + "amount": "18665.776068468384566", + "user": "0x5565d64f29Ea17355106DF3bA5903Eb793B3e139", + "tranche_id": 4, + "tx": "0x0954f744fc48cdb36187ba72505a5ca1c053d05da816b41230b35d86069fdcb0" + }, { "amount": "8992.6333376158479344", "user": "0x5565d64f29Ea17355106DF3bA5903Eb793B3e139", @@ -32246,8 +32848,8 @@ } ], "total_tokens": "44199.81164", - "withdrawn_tokens": "8992.6333376158479344", - "remaining_tokens": "35207.1783023841520656" + "withdrawn_tokens": "27658.4094060842325004", + "remaining_tokens": "16541.4022339157674996" }, { "address": "0xF5Fb27b912D987B5b6e02A1B1BE0C1F0740E2c6f", @@ -32296,12 +32898,24 @@ } ], "withdrawals": [ + { + "amount": "3639.282239117673375", + "user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90", + "tranche_id": 4, + "tx": "0x2a7ebd8748742d3bf0ce4f1ee46c575aa744f0d83915583bbd262f504044d462" + }, { "amount": "8456.402651116281081", "user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90", "tranche_id": 4, "tx": "0xf5651536b3fb0d1978a524b696a0fc8ce860afae23b42e7bc2a9601816c5c24b" }, + { + "amount": "4922.284907809154151", + "user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90", + "tranche_id": 4, + "tx": "0xb34ad795d45f3428f8447ab1573fe696a946897cc7a6f5e2e2c17441821ad8d0" + }, { "amount": "1729.052213861087673", "user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90", @@ -32424,8 +33038,8 @@ } ], "total_tokens": "331498.5873", - "withdrawn_tokens": "199075.693782538816896", - "remaining_tokens": "132422.893517461183104" + "withdrawn_tokens": "207637.260929465644422", + "remaining_tokens": "123861.326370534355578" }, { "address": "0x16da609341ed67750A8BCC5AAa2005471006Cd77", @@ -32513,8 +33127,8 @@ "tranche_start": "2022-06-05T00:00:00.000Z", "tranche_end": "2023-06-05T00:00:00.000Z", "total_added": "472355.6199999996", - "total_removed": "2932.49091410726", - "locked_amount": "352321.25870548864931294453272452", + "total_removed": "3216.01601557326", + "locked_amount": "341967.79448782570701567102181632", "deposits": [ { "amount": "3000", @@ -39133,6 +39747,16 @@ } ], "withdrawals": [ + { + "amount": "52.731139014", + "user": "0x28FC83947F02f59Cb36b40f97f2D32BBC5D00585", + "tx": "0xea18c5a1b637f62c07a366ee4622d008e932fdc1cbd0dc2283dc6e623f063381" + }, + { + "amount": "26.406887368", + "user": "0x4eD2b3c68BB4fda084ce1591a210F4aC8b71234A", + "tx": "0x4b4681ea3dedccd5e579f8f32e4d1a35456a1c354f6767d2528edc558034b29a" + }, { "amount": "44.069926432", "user": "0xfb393Ad714e8014947d9887912DfFB921E8aE74a", @@ -39243,6 +39867,16 @@ "user": "0xfeF4b56A370135A17Eef5ba8f5c308451a64Cf86", "tx": "0x81e9c325aed64b826afc0bb413245ee51468bb5238310bcdb1d4149d7cf3e713" }, + { + "amount": "102.190930996", + "user": "0x256274a216e0a349dC18cae08Ca45631176AF437", + "tx": "0x8a46d0c86f1676570dc3a867c85fc7d645551af2287f1cd115fba15d65618dc3" + }, + { + "amount": "102.196144088", + "user": "0xB3ae40b11af91BbD456022Bd42B4f36A8C0AEA9D", + "tx": "0x881dab195eb46b51f46181384e17fa7488b55ebae7bcb78eaeddf5c9375db4db" + }, { "amount": "35.252308472", "user": "0xFBD4E1d0D89632c279F06a1d9bb9438647D99a29", @@ -51309,6 +51943,12 @@ } ], "withdrawals": [ + { + "amount": "26.406887368", + "user": "0x4eD2b3c68BB4fda084ce1591a210F4aC8b71234A", + "tranche_id": 5, + "tx": "0x4b4681ea3dedccd5e579f8f32e4d1a35456a1c354f6767d2528edc558034b29a" + }, { "amount": "19.736364788", "user": "0x4eD2b3c68BB4fda084ce1591a210F4aC8b71234A", @@ -51329,8 +51969,8 @@ } ], "total_tokens": "400", - "withdrawn_tokens": "79.770915776", - "remaining_tokens": "320.229084224" + "withdrawn_tokens": "106.177803144", + "remaining_tokens": "293.822196856" }, { "address": "0x5c90765F50629570738fEe7b7FA82ae118f81Ed1", @@ -57913,10 +58553,17 @@ "tx": "0xb59405747c8088945a412703637a7b422f3639439ec2ee15e180c0a2a0d71ee4" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "52.731139014", + "user": "0x28FC83947F02f59Cb36b40f97f2D32BBC5D00585", + "tranche_id": 5, + "tx": "0xea18c5a1b637f62c07a366ee4622d008e932fdc1cbd0dc2283dc6e623f063381" + } + ], "total_tokens": "200", - "withdrawn_tokens": "0", - "remaining_tokens": "200" + "withdrawn_tokens": "52.731139014", + "remaining_tokens": "147.268860986" }, { "address": "0xBef628af8547cE5264835F32487055a7e3dF393D", @@ -58646,10 +59293,17 @@ "tx": "0xe32a466fc780a0fb3fd84a804f622931ebfaf3f428bff0dc6d141270410e75f8" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "102.196144088", + "user": "0xB3ae40b11af91BbD456022Bd42B4f36A8C0AEA9D", + "tranche_id": 5, + "tx": "0x881dab195eb46b51f46181384e17fa7488b55ebae7bcb78eaeddf5c9375db4db" + } + ], "total_tokens": "400", - "withdrawn_tokens": "0", - "remaining_tokens": "400" + "withdrawn_tokens": "102.196144088", + "remaining_tokens": "297.803855912" }, { "address": "0x256274a216e0a349dC18cae08Ca45631176AF437", @@ -58661,10 +59315,17 @@ "tx": "0xe32a466fc780a0fb3fd84a804f622931ebfaf3f428bff0dc6d141270410e75f8" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "102.190930996", + "user": "0x256274a216e0a349dC18cae08Ca45631176AF437", + "tranche_id": 5, + "tx": "0x8a46d0c86f1676570dc3a867c85fc7d645551af2287f1cd115fba15d65618dc3" + } + ], "total_tokens": "400", - "withdrawn_tokens": "0", - "remaining_tokens": "400" + "withdrawn_tokens": "102.190930996", + "remaining_tokens": "297.809069004" }, { "address": "0xB0473C4FeBd722a6d7eE561329d3134030318132", @@ -58973,7 +59634,7 @@ "tranche_start": "2021-12-05T00:00:00.000Z", "tranche_end": "2022-06-05T00:00:00.000Z", "total_added": "171288.42", - "total_removed": "51854.1080369557989", + "total_removed": "53419.8425587307989", "locked_amount": "0", "deposits": [ { @@ -63198,6 +63859,16 @@ } ], "withdrawals": [ + { + "amount": "250", + "user": "0x1f2c5E955082614F062b5BaC23DB5C2d345A4701", + "tx": "0x25132ae8c2d9315e5810b2fb8fba4de7538d946a71f215e66ba0c6e8fbdbbeab" + }, + { + "amount": "250", + "user": "0x15908B3180e311a9499CeA6a72961FdAB10B0fAC", + "tx": "0x9e63b6aa30c9ba99f6baed25ebda205734c77f687426385a6ab51ddac5861bb2" + }, { "amount": "50", "user": "0xd69d5334Ec0f1B762e869a42f6C2634238B3BE6A", @@ -63253,6 +63924,21 @@ "user": "0x962b86Bd4F921187F730457FE2F8335e263e6B2F", "tx": "0xd8aa0f4a543639c76c1e72d550d83c1bdb628058901938b39b24a5b967f89cee" }, + { + "amount": "250", + "user": "0x7E9bA4D3654ae2a8C4B15AAdee8f144Ba7eD68c4", + "tx": "0x66f286158f3b5ba4b16688b1841ebde4060fc14ce3b5c163b5c58c1806b1f221" + }, + { + "amount": "749.71", + "user": "0x389f68402c3355Af05566faC84914f8E7caabc52", + "tx": "0xc50cc4a5edea8eb1aa5ba128913f946b2d549e22fda7923f7d99d2f5250abb5d" + }, + { + "amount": "66.024521775", + "user": "0x94FB32e3D5b9DDc3DDcaf6F174CAEeF2BCc6a83d", + "tx": "0x743ce7162e9552d56cdafbde274472b2165b38b89e356e17df8c68ececa980ba" + }, { "amount": "250", "user": "0x9A453696D38e0e42b11AC30Be8C3A100eDDA5f53", @@ -65901,10 +66587,17 @@ "tx": "0x23a584d4881de8a7fdac91afaf0fd834e84ddcad95a0bc420020032bbeae8f50" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "749.71", + "user": "0x389f68402c3355Af05566faC84914f8E7caabc52", + "tranche_id": 6, + "tx": "0xc50cc4a5edea8eb1aa5ba128913f946b2d549e22fda7923f7d99d2f5250abb5d" + } + ], "total_tokens": "749.71", - "withdrawn_tokens": "0", - "remaining_tokens": "749.71" + "withdrawn_tokens": "749.71", + "remaining_tokens": "0" }, { "address": "0x6470BcDf3c0e99362003BEE5BC356Aa10b45e9c6", @@ -69028,6 +69721,12 @@ } ], "withdrawals": [ + { + "amount": "66.024521775", + "user": "0x94FB32e3D5b9DDc3DDcaf6F174CAEeF2BCc6a83d", + "tranche_id": 6, + "tx": "0x743ce7162e9552d56cdafbde274472b2165b38b89e356e17df8c68ececa980ba" + }, { "amount": "33.975478225", "user": "0x94FB32e3D5b9DDc3DDcaf6F174CAEeF2BCc6a83d", @@ -69036,8 +69735,8 @@ } ], "total_tokens": "100", - "withdrawn_tokens": "33.975478225", - "remaining_tokens": "66.024521775" + "withdrawn_tokens": "100", + "remaining_tokens": "0" }, { "address": "0x66014aEc97135793135FDEE169Ed826Ef421d81f", @@ -73231,10 +73930,17 @@ "tx": "0x06dfa508f6d82e3ebfc0ff5f3deeab5e36f69c3258e2264b29d3bad4d075c808" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "250", + "user": "0x1f2c5E955082614F062b5BaC23DB5C2d345A4701", + "tranche_id": 6, + "tx": "0x25132ae8c2d9315e5810b2fb8fba4de7538d946a71f215e66ba0c6e8fbdbbeab" + } + ], "total_tokens": "250", - "withdrawn_tokens": "0", - "remaining_tokens": "250" + "withdrawn_tokens": "250", + "remaining_tokens": "0" }, { "address": "0x40447e8eDee2F8D0088844E35Ff7aD2Bb5fCabfb", @@ -77724,10 +78430,17 @@ "tx": "0x3a0390dffa4280c286016566b29c62e4cec36c6504f7ac3d1de80d22b2903008" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "250", + "user": "0x7E9bA4D3654ae2a8C4B15AAdee8f144Ba7eD68c4", + "tranche_id": 6, + "tx": "0x66f286158f3b5ba4b16688b1841ebde4060fc14ce3b5c163b5c58c1806b1f221" + } + ], "total_tokens": "250", - "withdrawn_tokens": "0", - "remaining_tokens": "250" + "withdrawn_tokens": "250", + "remaining_tokens": "0" }, { "address": "0x57972Ce9730F16a9ef636fD34429f69Bc0F353De", @@ -79423,10 +80136,17 @@ "tx": "0xe32a466fc780a0fb3fd84a804f622931ebfaf3f428bff0dc6d141270410e75f8" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "250", + "user": "0x15908B3180e311a9499CeA6a72961FdAB10B0fAC", + "tranche_id": 6, + "tx": "0x9e63b6aa30c9ba99f6baed25ebda205734c77f687426385a6ab51ddac5861bb2" + } + ], "total_tokens": "250", - "withdrawn_tokens": "0", - "remaining_tokens": "250" + "withdrawn_tokens": "250", + "remaining_tokens": "0" }, { "address": "0x48e589D7B3088E571c8D17C03736f482747AD1Ff", diff --git a/apps/static/src/assets/testnet-tranches.json b/apps/static/src/assets/testnet-tranches.json index 35c7dc1f2..2268420b7 100644 --- a/apps/static/src/assets/testnet-tranches.json +++ b/apps/static/src/assets/testnet-tranches.json @@ -89,7 +89,7 @@ "tranche_end": "2022-10-12T00:53:20.000Z", "total_added": "1010.000000000000000001", "total_removed": "668.4622323651", - "locked_amount": "100.40186580416034230009940778792491123", + "locked_amount": "78.26388666920349680007748899670218168", "deposits": [ { "amount": "1000", diff --git a/apps/token-e2e/src/fixtures/proposals/freeform.json b/apps/token-e2e/src/fixtures/proposals/freeform.json index e3726769f..8643b7649 100644 --- a/apps/token-e2e/src/fixtures/proposals/freeform.json +++ b/apps/token-e2e/src/fixtures/proposals/freeform.json @@ -1,6 +1,6 @@ { "rationale": { - "title": "An example freeform proposal", + "title": "An example freeform 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/integration/flow/governance-flow.cy.js b/apps/token-e2e/src/integration/flow/governance-flow.cy.js index 37319f0ac..1f17cfbfc 100644 --- a/apps/token-e2e/src/integration/flow/governance-flow.cy.js +++ b/apps/token-e2e/src/integration/flow/governance-flow.cy.js @@ -23,6 +23,8 @@ const proposalVoteProgressForTokens = const proposalVoteProgressAgainstTokens = '[data-testid="vote-progress-indicator-tokens-against"]'; const changeVoteButton = '[data-testid="change-vote-button"]'; +const proposalDetailsTitle = '[data-testid="proposal-title"]'; +const proposalDetailsDescription = '[data-testid="proposal-description"]'; const voteButtons = '[data-testid="vote-buttons"]'; const rejectProposalsLink = '[href="/governance/rejected"]'; const feedbackError = '[data-testid="Error"]'; @@ -170,7 +172,7 @@ context('Governance flow - with eth and vega wallets connected', function () { cy.get(dialogCloseButton).click(); }); - it('Newly created freeform proposal - able to filter by proposalID to show it in list', function () { + 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 ); @@ -196,15 +198,11 @@ context('Governance flow - with eth and vega wallets connected', function () { .then((proposalId) => { cy.get('[data-testid="set-proposals-filter-visible"]').click(); cy.get('[data-testid="filter-input"]').type(proposalId); - cy.get(`#${proposalId}`).should( - 'contain', - `Freeform proposal: ${proposalId}`, - txTimeout - ); + cy.get(`#${proposalId}`).should('contain', proposalId); }); }); - it('Newly created freeform proposal - able to filter by proposerID to show it in list', function () { + 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 ); @@ -230,15 +228,57 @@ context('Governance flow - with eth and vega wallets connected', function () { let proposalId = proposal.response.body.data.busEvents[0].event.id; cy.get('[data-testid="set-proposals-filter-visible"]').click(); cy.get('[data-testid="filter-input"]').type(proposerId); - cy.get(`#${proposalId}`).should( - 'contain', - `Freeform proposal: ${proposalId}`, - txTimeout - ); + cy.get(`#${proposalId}`).should('contain', proposalId); }); }); - it('Newly created freeform proposal - shows in an open state', function () { + 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('governance'); + cy.wait_for_spinner(); + cy.get(newProposalButton).should('be.visible').click(); + cy.create_ten_digit_unix_timestamp_for_specified_days('8').then( + (closingDateTimestamp) => { + cy.enter_unique_freeform_proposal_body(closingDateTimestamp).as( + 'freeformProposal' + ); + } + ); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.contains('Awaiting network confirmation', epochTimeout).should( + 'be.visible' + ); + cy.contains('Proposal submitted', epochTimeout).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('@freeformProposal').then((freeformProposal) => { + // 1004-VOTE-008 + // 1004-VOTE-034 + cy.get(`#${proposalId}`) + .should('contain', freeformProposal.rationale.title) + .and('be.visible'); + cy.get(`#${proposalId}`) + .should( + 'contain', + freeformProposal.rationale.description.substring(0, 59) + ) + .and('be.visible'); + }); + }); + }); + }); + + it('Newly created freeform 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 ); @@ -263,13 +303,131 @@ context('Governance flow - with eth and vega wallets connected', function () { .its(proposalResponseProposalIdPath) .then((proposalId) => { cy.get(openProposals).within(() => { + // 1004-VOTE-035 cy.get(`#${proposalId}`) - .should('contain', `Freeform proposal: ${proposalId}`, txTimeout) + .should('contain', proposalId) .and('contain', 'Open') - .and('be.visible') - .within(() => { - cy.get(viewProposalButton).should('be.visible').click(); - }); + .and('be.visible'); + }); + }); + }); + + it('Newly created freeform proposal details - shows proposal title and full description', function () { + cy.ensure_specified_unstaked_tokens_are_associated( + this.minProposerBalance + ); + cy.navigate_to('governance'); + cy.wait_for_spinner(); + cy.get(newProposalButton).should('be.visible').click(); + cy.create_ten_digit_unix_timestamp_for_specified_days('8').then( + (closingDateTimestamp) => { + cy.enter_unique_freeform_proposal_body(closingDateTimestamp).as( + 'freeformProposal' + ); + } + ); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.contains('Awaiting network confirmation', epochTimeout).should( + 'be.visible' + ); + cy.contains('Proposal submitted', epochTimeout).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('@freeformProposal').then((freeformProposal) => { + // 1004-VOTE-054 + cy.get(proposalDetailsTitle) + .should('contain', freeformProposal.rationale.title) + .and('be.visible'); + cy.get(proposalDetailsDescription) + .should('contain', freeformProposal.rationale.description) + .and('be.visible'); + }); + }); + }); + + it('Newly created freeform proposal details - shows full link included in description', function () { + cy.ensure_specified_unstaked_tokens_are_associated( + this.minProposerBalance + ); + cy.navigate_to('governance'); + cy.wait_for_spinner(); + cy.get(newProposalButton).should('be.visible').click(); + cy.create_ten_digit_unix_timestamp_for_specified_days('8').then( + (closingDateTimestamp) => { + cy.enter_unique_freeform_proposal_body(closingDateTimestamp).as( + 'freeformProposal' + ); + } + ); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.contains('Awaiting network confirmation', epochTimeout).should( + 'be.visible' + ); + cy.contains('Proposal submitted', epochTimeout).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('@freeformProposal').then((freeformProposal) => { + // 1004-VOTE-055 + cy.get(proposalDetailsDescription) + .should('contain', freeformProposal.rationale.description) + .and('have.attr', 'href') + .and( + 'equal', + 'https://dweb.link/ipfs/bafybeigwwctpv37xdcwacqxvekr6e4kaemqsrv34em6glkbiceo3fcy4si' + ) + .and('be.visible'); + }); + }); + }); + + 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('governance'); + cy.wait_for_spinner(); + cy.get(newProposalButton).should('be.visible').click(); + cy.create_ten_digit_unix_timestamp_for_specified_days('8').then( + (closingDateTimestamp) => { + cy.enter_unique_freeform_proposal_body(closingDateTimestamp); + } + ); + cy.get(newProposalSubmitButton).should('be.visible').click(); + cy.contains('Awaiting network confirmation', epochTimeout).should( + 'be.visible' + ); + cy.contains('Proposal submitted', epochTimeout).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) @@ -283,7 +441,7 @@ context('Governance flow - with eth and vega wallets connected', function () { }); }); - it('Newly created freeform proposal - shows proposed and closing dates', function () { + it('Newly created freeform proposal details - shows proposed and closing dates', function () { cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance ); @@ -322,10 +480,14 @@ context('Governance flow - with eth and vega wallets connected', function () { .should('be.visible'); } ); + // 1004-VOTE-043 cy.contains('9 days left to vote').should('be.visible'); }); - it('Newly created freeform proposal - shows default status set to fail', function () { + it('Newly created freeform proposal details - shows default status set to fail', function () { + // 1004-VOTE-037 + // 1004-VOTE-039 + // 1004-VOTE-040 cy.ensure_specified_unstaked_tokens_are_associated( this.minProposerBalance ); @@ -356,6 +518,7 @@ context('Governance flow - with eth and vega wallets connected', function () { cy.get_proposal_information_from_table('Will pass') .contains('👎') .should('be.visible'); + // 1004-VOTE-062 cy.get_proposal_information_from_table('Majority met') .contains('👎') .should('be.visible'); @@ -364,7 +527,7 @@ context('Governance flow - with eth and vega wallets connected', function () { .should('be.visible'); }); - it('Newly created freeform proposal - ability to vote for proposal - with minimum required tokens associated', function () { + 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 ); @@ -393,6 +556,8 @@ context('Governance flow - with eth and vega wallets connected', function () { '0', 'shortMonth' ).then((votedDate) => { + // 1004-VOTE-051 + // 1004-VOTE-093 cy.contains('You voted:') .siblings() .contains('For') @@ -416,9 +581,11 @@ context('Governance flow - with eth and vega wallets connected', function () { cy.get_proposal_information_from_table('Tokens against proposal') .should('have.text', '0.00') .and('be.visible'); + // 1004-VOTE-061 cy.get_proposal_information_from_table('Participation required') .contains(`${this.requiredParticipation}%`) .should('be.visible'); + // 1004-VOTE-066 cy.get_proposal_information_from_table('Majority Required') .contains(`${parseFloat(this.requiredMajority).toFixed(2)}%`) .should('be.visible'); @@ -427,7 +594,7 @@ context('Governance flow - with eth and vega wallets connected', function () { .and('be.visible'); }); - it('Newly created freeform proposal - ability to vote against proposal - with minimum required tokens associated', function () { + 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 ); @@ -456,6 +623,7 @@ context('Governance flow - with eth and vega wallets connected', function () { '0', 'shortMonth' ).then((votedDate) => { + // 1004-VOTE-051 cy.contains('You voted:') .siblings() .contains('Against') @@ -490,7 +658,7 @@ context('Governance flow - with eth and vega wallets connected', function () { .and('be.visible'); }); - it('Newly created freeform proposal - ability to change vote from against to for - with minimum required tokens associated', function () { + 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 ); @@ -515,6 +683,7 @@ context('Governance flow - with eth and vega wallets connected', function () { .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'); @@ -528,6 +697,7 @@ context('Governance flow - with eth and vega wallets connected', function () { 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'); @@ -545,7 +715,7 @@ context('Governance flow - with eth and vega wallets connected', function () { .and('be.visible'); }); - it('Newly created freeform proposal - ability to change vote from for to against - with minimum required tokens associated', function () { + 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 ); @@ -572,6 +742,7 @@ context('Governance flow - with eth and vega wallets connected', function () { cy.vote_for_proposal('for'); cy.get(changeVoteButton).should('be.visible').click(); cy.wait_for_spinner(); + // 1004-VOTE-080 cy.vote_for_proposal('against'); cy.get(proposalVoteProgressForPercentage) .contains('0.00%') @@ -600,7 +771,7 @@ context('Governance flow - with eth and vega wallets connected', function () { .and('be.visible'); }); - it('Newly created freeform proposal - ability to increase associated tokens - so that vote sways result', function () { + 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 ); @@ -624,6 +795,7 @@ context('Governance flow - with eth and vega wallets connected', function () { cy.get_submitted_proposal_from_proposal_list() .as('submittedProposal') .within(() => cy.get(viewProposalButton).click()); + // 1004-VOTE-080 cy.vote_for_proposal('for'); cy.get_proposal_information_from_table('Total Supply') .invoke('text') @@ -645,6 +817,8 @@ context('Governance flow - with eth and vega wallets connected', function () { cy.get(proposalVoteProgressAgainstPercentage) .contains('0.00%') .and('be.visible'); + // 1004-VOTE-065 + // 1004-VOTE-079 cy.get(proposalVoteProgressForTokens) .contains(tokensRequiredToAcheiveResult) .and('be.visible'); @@ -660,6 +834,22 @@ context('Governance flow - with eth and vega wallets connected', function () { cy.get_proposal_information_from_table('Number of voting parties') .should('have.text', '1') .and('be.visible'); + cy.get_proposal_information_from_table('Will pass') + .contains('👍') + .should('be.visible'); + // 1004-VOTE-062 + cy.get_proposal_information_from_table('Majority met') + .contains('👍') + .should('be.visible'); + cy.get_proposal_information_from_table('Participation met') + .contains('👍') + .should('be.visible'); + // 1004-VOTE-042 + // 1004-VOTE-057 + // 1004-VOTE-058 + // 1004-VOTE-059 + // 1004-VOTE-060 + cy.contains('Currently set to pass').should('be.visible'); }); }); @@ -852,6 +1042,8 @@ context('Governance flow - with eth and vega wallets connected', function () { parseSpecialCharSequences: false, delay: 2, }); + + cy.wrap(freeformProposal); }); }); diff --git a/apps/token-e2e/src/integration/view/governance.cy.js b/apps/token-e2e/src/integration/view/governance.cy.js index 33f3b94ab..a646d9225 100644 --- a/apps/token-e2e/src/integration/view/governance.cy.js +++ b/apps/token-e2e/src/integration/view/governance.cy.js @@ -1,5 +1,7 @@ const noOpenProposals = '[data-testid="no-open-proposals"]'; const noClosedProposals = '[data-testid="no-closed-proposals"]'; +const proposalDocumentationLink = '[data-testid="external-link"]'; +const newProposalLink = '[data-testid="new-proposal-link"]'; context('Governance Page - verify elements on page', function () { before('navigate to governance page', function () { @@ -15,7 +17,26 @@ context('Governance Page - verify elements on page', function () { cy.verify_page_header('Governance'); }); - it('should have information visible', function () { + it('should be able to see link for - Find out more about Vega governance', function () { + // 1004-VOTE-001 + cy.get(proposalDocumentationLink) + .should('be.visible') + .and('have.text', 'Find out more about Vega governance') + .and('have.attr', 'href') + .and('equal', 'https://vega.xyz/governance'); + }); + + it('should be able to see button for - new proposal', function () { + // 1004-VOTE-002 + cy.get(newProposalLink) + .should('be.visible') + .and('have.text', 'New proposal') + .and('have.attr', 'href') + .and('equal', '/governance/propose'); + }); + + it('should be able to see that no proposals exist', function () { + // 1004-VOTE-003 cy.get(noOpenProposals) .should('be.visible') .and('have.text', 'There are no open or yet to enact proposals'); diff --git a/apps/token-e2e/src/integration/view/home.cy.js b/apps/token-e2e/src/integration/view/home.cy.js index 4654d8b5f..5aa137bb8 100644 --- a/apps/token-e2e/src/integration/view/home.cy.js +++ b/apps/token-e2e/src/integration/view/home.cy.js @@ -3,7 +3,7 @@ const navHome = '[href="/"]'; const navVesting = '[href="/vesting"]'; const navStaking = '[href="/staking"]'; const navRewards = '[href="/rewards"]'; -const navWithdraw = '[href="/withdraw"]'; +const navWithdraw = '[href="/withdrawals"]'; const navGovernance = '[href="/governance"]'; const tokenDetailsTable = '.token-details'; diff --git a/apps/token-e2e/src/integration/view/wallet-vega.cy.js b/apps/token-e2e/src/integration/view/wallet-vega.cy.js index 871bef646..bc6394fee 100644 --- a/apps/token-e2e/src/integration/view/wallet-vega.cy.js +++ b/apps/token-e2e/src/integration/view/wallet-vega.cy.js @@ -170,7 +170,7 @@ context('Vega Wallet - verify elements on widget', function () { }); }); - it('should have wallet name visible', function () { + it.skip('should have wallet name visible', function () { cy.get(walletContainer).within(() => { cy.get(walletName) .should('be.visible') @@ -238,7 +238,7 @@ context('Vega Wallet - verify elements on widget', function () { }); }); - it('should have vega wallet public key and name visible', function () { + it.skip('should have vega wallet public key and name visible', function () { cy.get(dialog).within(() => { cy.get(dialogVegaKey) .should('be.visible') diff --git a/apps/token-e2e/src/integration/view/withdraw.cy.js b/apps/token-e2e/src/integration/view/withdraw.cy.js index 9036b375a..da417d05b 100644 --- a/apps/token-e2e/src/integration/view/withdraw.cy.js +++ b/apps/token-e2e/src/integration/view/withdraw.cy.js @@ -1,18 +1,17 @@ const connectToVegaBtn = '[data-testid="connect-to-vega-wallet-btn"]'; -const warning = '[data-testid="callout"]'; context('Withdraw Page - verify elements on page', function () { - before('navigate to withdraw page', function () { - cy.visit('/').navigate_to('withdraw'); + before('navigate to withdrawals page', function () { + cy.visit('/').navigate_to('withdrawals'); }); describe('with wallets disconnected', function () { it('should have withdraw tab highlighted', function () { - cy.verify_tab_highlighted('withdraw'); + cy.verify_tab_highlighted('withdrawals'); }); it('should have WITHDRAW header visible', function () { - cy.verify_page_header('Withdraw'); + cy.verify_page_header('Withdrawals'); }); it('should have connect Vega wallet button', function () { @@ -20,9 +19,5 @@ context('Withdraw Page - verify elements on page', function () { .should('be.visible') .and('have.text', 'Connect Vega wallet'); }); - - it('should have withdraw information box', function () { - cy.get(warning).should('be.visible'); - }); }); }); diff --git a/apps/token-e2e/src/support/common.functions.js b/apps/token-e2e/src/support/common.functions.js index 434e17657..4266ef186 100644 --- a/apps/token-e2e/src/support/common.functions.js +++ b/apps/token-e2e/src/support/common.functions.js @@ -12,7 +12,7 @@ const navigation = { vesting: '[href="/vesting"]', staking: '[href="/staking"]', rewards: '[href="/rewards"]', - withdraw: '[href="/withdraw"]', + withdrawals: '[href="/withdrawals"]', governance: '[href="/governance"]', pageSpinner: '[data-testid="splash-loader"]', }; diff --git a/apps/token-e2e/src/support/wallet-vega.functions.js b/apps/token-e2e/src/support/wallet-vega.functions.js index f77a2759d..c25826df1 100644 --- a/apps/token-e2e/src/support/wallet-vega.functions.js +++ b/apps/token-e2e/src/support/wallet-vega.functions.js @@ -1,19 +1,26 @@ const vegaWalletContainer = '[data-testid="vega-wallet"]'; const restConnectorForm = '[data-testid="rest-connector-form"]'; +const vegaWalletNameElement = '[data-testid="wallet-name"]'; const vegaWalletName = Cypress.env('vegaWalletName'); const vegaWalletLocation = Cypress.env('vegaWalletLocation'); const vegaWalletPassphrase = Cypress.env('vegaWalletPassphrase'); Cypress.Commands.add('vega_wallet_import', () => { cy.highlight(`Importing Vega Wallet ${vegaWalletName}`); - cy.exec(`vegawallet init -f --home ${vegaWalletLocation}`); + cy.exec(`vega wallet init -f --home ${vegaWalletLocation}`); cy.exec( - `vegawallet import -w ${vegaWalletName} --recovery-phrase-file ./src/fixtures/wallet/recovery -p ./src/fixtures/wallet/passphrase --home ~/.vegacapsule/testnet/wallet`, + `vega wallet import -w ${vegaWalletName} --recovery-phrase-file ./src/fixtures/wallet/recovery -p ./src/fixtures/wallet/passphrase --home ~/.vegacapsule/testnet/wallet`, { failOnNonZeroExit: false } ); cy.exec( - `vegawallet service run --network DV --automatic-consent --home ${vegaWalletLocation}` + `vega wallet service run --network DV --automatic-consent --home ${vegaWalletLocation}` ); + + cy.exec(`vega wallet version`) + .its('stdout') + .then((output) => { + cy.log(output); + }); }); Cypress.Commands.add('vega_wallet_connect', () => { @@ -31,5 +38,5 @@ Cypress.Commands.add('vega_wallet_connect', () => { cy.get('#passphrase').click().type(vegaWalletPassphrase); cy.get('button').contains('Connect').click(); }); - cy.contains(`${vegaWalletName} key`, { timeout: 20000 }).should('be.visible'); + cy.get(vegaWalletNameElement).should('be.visible'); }); diff --git a/apps/token/.env b/apps/token/.env index e4bc187e4..2c47f7911 100644 --- a/apps/token/.env +++ b/apps/token/.env @@ -1,10 +1,10 @@ # App configuration variables NX_VEGA_ENV=TESTNET NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json -NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql +NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHERSCAN_URL=https://ropsten.etherscan.io -NX_VEGA_REST=https://api.n11.testnet.vega.xyz +NX_VEGA_REST=https://api.n07.testnet.vega.xyz NX_FAIRGROUND=false NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}' NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions diff --git a/apps/token/.env.capsule b/apps/token/.env.capsule index 3a96cbc27..170d608e7 100644 --- a/apps/token/.env.capsule +++ b/apps/token/.env.capsule @@ -1,5 +1,5 @@ # App configuration variables -NX_VEGA_ENV=TESTNET +NX_VEGA_ENV=CUSTOM NX_ETHEREUM_PROVIDER_URL=http://localhost:8545 NX_ETHERSCAN_URL=https://ropsten.etherscan.io NX_FAIRGROUND=false diff --git a/apps/token/.eslintrc.json b/apps/token/.eslintrc.json index db820c5d0..de2a9b877 100644 --- a/apps/token/.eslintrc.json +++ b/apps/token/.eslintrc.json @@ -1,6 +1,6 @@ { "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*", "__generated__"], + "ignorePatterns": ["!**/*", "__generated__", "__generated___"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], diff --git a/apps/token/client.graphql b/apps/token/client.graphql new file mode 100644 index 000000000..137c4d621 --- /dev/null +++ b/apps/token/client.graphql @@ -0,0 +1,43 @@ +extend type Delegation { + "The amount field formatted by the client" + amountFormatted: String! +} + +extend type PartyStake { + "The currently available stake formatted by the client" + currentStakeAvailableFormatted: String! +} + +extend type NodeData { + "The total staked field formatted by the client" + stakedTotalFormatted: String! +} + +extend type Node { + "The total staked field formatted by the client" + stakedTotalFormatted: String! + + "The pending staked field formatted by the client" + pendingStakeFormatted: String! + + "The stakes by operator field formatted by the client" + stakedByOperatorFormatted: String! + + "The stakes by delegates field formatted by the client" + stakedByDelegatesFormatted: String! +} + +extend type Reward { + "The amount field formatted by the client" + amountFormatted: String! +} + +extend type RewardPerAssetDetail { + "The total amount field formatted by the client" + totalAmountFormatted: String! +} + +extend type Account { + "The balance field formatted by the client" + balanceFormatted: String! +} diff --git a/apps/token/src/components/nav/nav.tsx b/apps/token/src/components/nav/nav.tsx index 64ef6a1e7..af047ea3f 100644 --- a/apps/token/src/components/nav/nav.tsx +++ b/apps/token/src/components/nav/nav.tsx @@ -224,7 +224,7 @@ const NavLinks = ({ { route: Routes.VESTING, text: t('Vesting') }, { route: Routes.STAKING, text: t('Staking') }, { route: Routes.REWARDS, text: t('Rewards') }, - { route: Routes.WITHDRAW, text: t('Withdraw') }, + { route: Routes.WITHDRAWALS, text: t('Withdraw') }, { route: Routes.GOVERNANCE, text: t('Governance') }, ]; const navClasses = classNames('flex', { diff --git a/apps/token/src/components/token-input/token-input.tsx b/apps/token/src/components/token-input/token-input.tsx index 0a22d703a..d8c8c9f31 100644 --- a/apps/token/src/components/token-input/token-input.tsx +++ b/apps/token/src/components/token-input/token-input.tsx @@ -37,7 +37,7 @@ export const AmountInput = ({ }) => { const { t } = useTranslation(); return ( -
    +
    {maximum && ( -
    - setAmount(maximum.toString())} - data-testid="token-amount-use-maximum" - > - {t('Use maximum')} - -
    + setAmount(maximum.toString())} + data-testid="token-amount-use-maximum" + > + {t('Use maximum')} + )}
    ); @@ -169,7 +167,7 @@ export const TokenInput = ({ } else if (requireApproval) { approveContent = ( -

    {`${currency} are approved for staking`}

    +

    {`${currency} are approved for staking`}

    ); } @@ -188,7 +186,7 @@ export const TokenInput = ({ currency={currency} /> - {approveContent ?
    {approveContent}
    : null} + {approveContent ?
    {approveContent}
    : null} +

    {t('withdrawalsText')}

    {t('withdrawalsPreparedWarningText')}

    -
      - {withdrawals.map((w) => ( -
    • - -
    • - ))} -
    - +
    + +
    + ); }; -interface WithdrawalProps { - withdrawal: Withdrawals_party_withdrawals; - complete: (withdrawalId: string) => void; -} - -export const Withdrawal = ({ withdrawal, complete }: WithdrawalProps) => { - const { ETHERSCAN_URL } = useEnvironment(); - const { t } = useTranslation(); - let status; - let footer = null; - - if (withdrawal.pendingOnForeignChain) { - status = t('Pending'); - footer = ( - - ); - } else if (withdrawal.status === WithdrawalStatus.STATUS_FINALIZED) { - if (withdrawal.txHash) { - status = t('Complete'); - } else { - status = t('Incomplete'); - footer = ( - - ); - } - } else { - status = withdrawal.status; - } - - return ( -
    - - - {t('Withdraw')} - - {addDecimal( - new BigNumber(withdrawal.amount), - withdrawal.asset.decimals - )}{' '} - {withdrawal.asset.symbol} - - - - {t('toEthereum')} - - - {truncateMiddle(withdrawal.details?.receiverAddress ?? '')} - - - - - {t('created')} - - {format( - new Date(withdrawal.createdTimestamp), - DATE_FORMAT_DETAILED - )} - - - - {t('withdrawalTransaction', { foreignChain: 'Ethereum' })} - - {withdrawal.txHash ? ( - - {truncateMiddle(withdrawal.txHash)} - - ) : ( - '-' - )} - - - - {t('status')} - {status} - - - {footer} -
    - ); -}; - export default Withdrawals; diff --git a/apps/trading-e2e/src/integration/deposit.cy.ts b/apps/trading-e2e/src/integration/deposit.cy.ts index ccf606e54..11295146c 100644 --- a/apps/trading-e2e/src/integration/deposit.cy.ts +++ b/apps/trading-e2e/src/integration/deposit.cy.ts @@ -3,28 +3,28 @@ import { generateDepositPage } from '../support/mocks/generate-deposit-page'; import { generateNetworkParameters } from '../support/mocks/generate-network-parameters'; const connectEthWalletBtn = 'connect-eth-wallet-btn'; +const assetSelectField = 'select[name="asset"]'; +const toAddressField = 'input[name="to"]'; +const amountField = 'input[name="amount"]'; +const formFieldError = 'input-error-text'; describe('deposit form validation', () => { beforeEach(() => { cy.mockWeb3Provider(); cy.mockGQL((req) => { aliasQuery(req, 'NetworkParamsQuery', generateNetworkParameters()); - aliasQuery(req, 'AssetsConnection', generateDepositPage()); + aliasQuery(req, 'DepositPage', generateDepositPage()); }); cy.visit('/portfolio/deposit'); - cy.wait('@AssetsConnection'); // Deposit page requires connection Ethereum wallet first cy.getByTestId(connectEthWalletBtn).click(); cy.getByTestId('web3-connector-MetaMask').click(); + + cy.wait('@DepositPage'); }); it('handles empty fields', () => { - const assetSelectField = 'select[name="asset"]'; - const toAddressField = 'input[name="to"]'; - const amountField = 'input[name="amount"]'; - const formFieldError = 'input-error-text'; - // Submit form to trigger any empty validaion messages cy.getByTestId('deposit-submit').click(); @@ -56,6 +56,14 @@ describe('deposit form validation', () => { .should('have.text', 'Insufficient amount in Ethereum wallet'); }); + it('unable to select assets not enabled', () => { + cy.getByTestId('deposit-submit').click(); + // Assets not enabled in mocks + cy.get(assetSelectField + ' option:contains(Asset 2)').should('not.exist'); + cy.get(assetSelectField + ' option:contains(Asset 3)').should('not.exist'); + cy.get(assetSelectField + ' option:contains(Asset 4)').should('not.exist'); + }); + it('able to disconnect eth wallet', () => { const ethWalletAddress = Cypress.env('ETHEREUM_WALLET_ADDRESS'); diff --git a/apps/trading-e2e/src/integration/home.cy.ts b/apps/trading-e2e/src/integration/home.cy.ts index 84fbe79b9..509b020bf 100644 --- a/apps/trading-e2e/src/integration/home.cy.ts +++ b/apps/trading-e2e/src/integration/home.cy.ts @@ -4,14 +4,18 @@ import { mockTradingPage } from '../support/trading'; describe('home', () => { const selectMarketOverlay = 'select-market-list'; + beforeEach(() => { + cy.mockGQL((req) => { + mockTradingPage(req, MarketState.STATE_ACTIVE); + }); + cy.visit('/'); + }); describe('default market found', () => { it('redirects to a default market with the landing dialog open', () => { - cy.mockGQL((req) => { - // Mock all market page queries - mockTradingPage(req, MarketState.STATE_ACTIVE); - }); cy.visit('/'); + cy.wait('@Market'); + cy.get('main[data-testid="market"]', { timeout: 20000 }).should('exist'); // Wait for page to be rendered to before checking url // Overlay should be shown @@ -51,10 +55,16 @@ describe('home', () => { it('redirects to a the market list page if no sensible default is found', () => { // Mock markets query that is triggered by home page to find default market cy.mockGQL((req) => { - aliasQuery(req, 'MarketList', { markets: [] }); + const data = { + marketsConnection: { + __typename: 'MarketConnection', + edges: [], + }, + }; + aliasQuery(req, 'Markets', data); }); - cy.visit('/'); + cy.wait('@Markets'); cy.url().should('eq', Cypress.config().baseUrl + '/markets'); }); }); diff --git a/apps/trading-e2e/src/integration/market-info.cy.ts b/apps/trading-e2e/src/integration/market-info.cy.ts index fafa62721..86deed88c 100644 --- a/apps/trading-e2e/src/integration/market-info.cy.ts +++ b/apps/trading-e2e/src/integration/market-info.cy.ts @@ -1,9 +1,11 @@ -import { MarketState } from '@vegaprotocol/types'; +import { MarketState, MarketTradingModeMapping } from '@vegaprotocol/types'; import { mockTradingPage } from '../support/trading'; const marketInfoBtn = 'Info'; const row = 'key-value-table-row'; const marketTitle = 'accordion-title'; +const link = 'link'; +const externalLink = 'external-link'; describe('market info is displayed', () => { before(() => { @@ -25,9 +27,9 @@ describe('market info is displayed', () => { it('market price', () => { cy.getByTestId(marketTitle).contains('Market price').click(); - validateMarketDataRow(0, 'Mark Price', '57.49'); - validateMarketDataRow(1, 'Best Bid Price', '6,817.65'); - validateMarketDataRow(2, 'Best Offer Price', '6,817.69'); + validateMarketDataRow(0, 'Mark Price', '0.05749'); + validateMarketDataRow(1, 'Best Bid Price', '6.81765 '); + validateMarketDataRow(2, 'Best Offer Price', '6.81769 '); }); it('market volume displayed', () => { @@ -48,12 +50,13 @@ describe('market info is displayed', () => { it('key details displayed', () => { cy.getByTestId(marketTitle).contains('Key details').click(); - validateMarketDataRow(0, 'Name', 'ETHBTC Quarterly (30 Jun 2022)'); - validateMarketDataRow(1, 'Decimal Places', '2'); - validateMarketDataRow(2, 'Position Decimal Places', '0'); - validateMarketDataRow(3, 'Trading Mode', 'Trading mode continuous'); - validateMarketDataRow(4, 'State', 'STATE_ACTIVE'); - validateMarketDataRow(5, 'Market ID', 'market-0'); + validateMarketDataRow(0, 'Name', 'BTCUSD Monthly (30 Jun 2022)'); + validateMarketDataRow(1, 'Market ID', 'market-0'); + validateMarketDataRow( + 2, + 'Trading Mode', + MarketTradingModeMapping.TRADING_MODE_CONTINUOUS + ); }); it('instrument displayed', () => { @@ -70,11 +73,7 @@ describe('market info is displayed', () => { validateMarketDataRow(0, 'Name', 'tBTC TEST'); validateMarketDataRow(1, 'Symbol', 'tBTC'); - validateMarketDataRow( - 2, - 'Asset ID', - '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c' - ); + validateMarketDataRow(2, 'Asset ID', 'market-0'); }); it('metadata displayed', () => { @@ -87,13 +86,6 @@ describe('market info is displayed', () => { validateMarketDataRow(4, 'Sector', 'crypto'); }); - it('risk factors displayed', () => { - cy.getByTestId(marketTitle).contains('Risk factors').click(); - - validateMarketDataRow(0, 'Short', '0.008571790367285281'); - validateMarketDataRow(1, 'Long', '0.008508132993273576'); - }); - it('risk model displayed', () => { cy.getByTestId(marketTitle).contains('Risk model').click(); @@ -113,9 +105,9 @@ describe('market info is displayed', () => { it('price monitoring bound displayed', () => { cy.getByTestId(marketTitle).contains('Price monitoring bound 1').click(); - validateMarketDataRow(0, 'Min Valid Price', '6,547.01'); - validateMarketDataRow(1, 'Max Valid Price', '7,973.23'); - validateMarketDataRow(2, 'Reference Price', '7,226.25'); + validateMarketDataRow(0, 'Min Valid Price', '6.54701 '); + validateMarketDataRow(1, 'Max Valid Price', '7.97323 '); + validateMarketDataRow(2, 'Reference Price', '7.22625 '); }); it('liquidity monitoring parameters displayed', () => { @@ -128,6 +120,16 @@ describe('market info is displayed', () => { validateMarketDataRow(2, 'Scaling Factor', '10'); }); + it('liquidity displayed', () => { + cy.getByTestId('accordion-toggle').eq(13).click(); + + validateMarketDataRow(0, 'Target Stake', '0.56789 tBTC'); + validateMarketDataRow(1, 'Supplied Stake', '0.56767 tBTC'); + validateMarketDataRow(2, 'Market Value Proxy', '6.77678 tBTC'); + + cy.getByTestId(link).should('have.text', 'View liquidity provision table'); + }); + it('oracle displayed', () => { cy.getByTestId(marketTitle).contains('Oracle').click(); @@ -137,16 +139,19 @@ describe('market info is displayed', () => { 'Trading Termination Property', 'termination.BTC.value' ); - validateMarketDataRow( - 2, - 'Price Oracle', - 'f028fe5ea7de3890962a05a7163fdde562629af649ed81b8c8902fafb6eef04f' - ); - validateMarketDataRow( - 3, - 'Termination Oracle', - 'f028fe5ea7de3890962a05a7163fdde562629af649ed81b8c8902fafb6eef04f' - ); + + cy.getByTestId(externalLink) + .should('have.attr', 'href') + .and('contain', '/oracles'); + }); + + it('proposal displayed', () => { + cy.getByTestId(marketTitle).contains('Proposal').click(); + + cy.getByTestId(externalLink) + .should('have.text', 'View governance proposal') + .and('have.attr', 'href') + .and('contain', '/governance/market-0'); }); afterEach('close toggle', () => { diff --git a/apps/trading-e2e/src/integration/markets.cy.ts b/apps/trading-e2e/src/integration/markets.cy.ts index a8c811745..fada777dc 100644 --- a/apps/trading-e2e/src/integration/markets.cy.ts +++ b/apps/trading-e2e/src/integration/markets.cy.ts @@ -10,7 +10,10 @@ describe('markets table', () => { it('renders markets correctly', () => { cy.visit('/'); - cy.wait('@MarketList'); + cy.wait('@Market'); + cy.wait('@Markets'); + cy.wait('@MarketsDataQuery'); + cy.wait('@MarketsCandlesQuery'); cy.get('[data-testid^="market-link-"]') .should('not.be.empty') .and('have.attr', 'href'); @@ -23,7 +26,9 @@ describe('markets table', () => { it('renders market list drop down', () => { cy.visit('/'); - cy.wait('@MarketList'); + cy.wait('@Markets'); + cy.wait('@MarketsDataQuery'); + cy.wait('@MarketsCandlesQuery'); openMarketDropDown(); cy.getByTestId('price').invoke('text').should('not.be.empty'); cy.getByTestId('trading-mode').should('not.be.empty'); @@ -34,7 +39,9 @@ describe('markets table', () => { it('Able to select market from dropdown', () => { cy.visit('/'); - cy.wait('@MarketList'); + cy.wait('@Markets'); + cy.wait('@MarketsDataQuery'); + cy.wait('@MarketsCandlesQuery'); openMarketDropDown(); cy.getByTestId('market-link-market-0').should('be.visible').click(); @@ -52,7 +59,9 @@ describe('markets table', () => { 'SOLUSD', ]; cy.visit('/'); - cy.wait('@MarketList'); + cy.wait('@Markets'); + cy.wait('@MarketsDataQuery'); + cy.wait('@MarketsCandlesQuery'); cy.getByTestId('link').should('have.attr', 'href', '/markets').click(); cy.url().should('eq', Cypress.config('baseUrl') + '/markets'); cy.contains('AAPL.MF21').should('be.visible'); @@ -126,7 +135,7 @@ describe('markets table', () => { } function verifyMarketSummaryDisplayed() { - const marketSummaryBlock = 'market-summary'; + const marketSummaryBlock = 'header-summary'; const percentageValue = 'price-change-percentage'; const priceChangeValue = 'price-change'; const tradingVolume = 'trading-volume'; diff --git a/apps/trading-e2e/src/integration/trading-accounts.cy.ts b/apps/trading-e2e/src/integration/trading-accounts.cy.ts index 13a525745..727410080 100644 --- a/apps/trading-e2e/src/integration/trading-accounts.cy.ts +++ b/apps/trading-e2e/src/integration/trading-accounts.cy.ts @@ -33,7 +33,7 @@ describe('accounts', () => { cy.getByTestId('tab-accounts') .should('be.visible') .get(tradingAccountRowId) - .find('[col-id="market.name"]') + .find('[col-id="market.tradableInstrument.instrument.name"]') .should('have.text', '—'); cy.getByTestId('tab-accounts') diff --git a/apps/trading-e2e/src/integration/trading-collateral.cy.ts b/apps/trading-e2e/src/integration/trading-collateral.cy.ts index 229046660..292b3db8f 100644 --- a/apps/trading-e2e/src/integration/trading-collateral.cy.ts +++ b/apps/trading-e2e/src/integration/trading-collateral.cy.ts @@ -13,7 +13,8 @@ describe('collateral', () => { const collateralTab = 'Collateral'; const assetSymbolColumn = "[col-id='asset.symbol']"; const assetTypeColumn = "[col-id='type']"; - const assetMarketName = "[col-id='market.name']"; + const assetMarketName = + "[col-id='market.tradableInstrument.instrument.name']"; it('renders collateral', () => { connectVegaWallet(); cy.getByTestId(collateralTab).click(); diff --git a/apps/trading-e2e/src/integration/trading-fills.cy.ts b/apps/trading-e2e/src/integration/trading-fills.cy.ts index 9c78895e6..4467621c3 100644 --- a/apps/trading-e2e/src/integration/trading-fills.cy.ts +++ b/apps/trading-e2e/src/integration/trading-fills.cy.ts @@ -22,7 +22,11 @@ const fills = [ infrastructureFee: '5000', }, market: { - name: 'Apples Daily v3', + tradableInstrument: { + instrument: { + name: 'Apples Daily v3', + }, + }, positionDecimalPlaces: 2, }, }), @@ -37,7 +41,11 @@ const fills = [ id: '3', aggressor: Side.SIDE_SELL, market: { - name: 'ETHBTC Quarterly (30 Jun 2022)', + tradableInstrument: { + instrument: { + name: 'ETHBTC Quarterly (30 Jun 2022)', + }, + }, }, buyer: { id: Cypress.env('VEGA_PUBLIC_KEY'), @@ -90,7 +98,9 @@ describe('fills', () => { cy.getByTestId('tab-fills').should('be.visible'); cy.getByTestId('tab-fills') - .get('[role="gridcell"][col-id="market.name"]') + .get( + '[role="gridcell"][col-id="market.tradableInstrument.instrument.name"]' + ) .each(($marketSymbol) => { cy.wrap($marketSymbol).invoke('text').should('not.be.empty'); }); diff --git a/apps/trading-e2e/src/integration/trading-positions.cy.ts b/apps/trading-e2e/src/integration/trading-positions.cy.ts index 16fcf521e..ba79be7de 100644 --- a/apps/trading-e2e/src/integration/trading-positions.cy.ts +++ b/apps/trading-e2e/src/integration/trading-positions.cy.ts @@ -6,41 +6,63 @@ beforeEach(() => { cy.mockGQL((req) => { mockTradingPage(req, MarketState.STATE_ACTIVE); }); - cy.visit('/markets/market-0'); }); describe('positions', () => { - it('renders positions', () => { + it('renders positions on trading page', () => { + cy.visit('/markets/market-0'); cy.getByTestId('Positions').click(); cy.getByTestId('tab-positions').contains('Please connect Vega wallet'); connectVegaWallet(); + validatePositionsDisplayed(); + }); + it('renders positions on portfolio page', () => { + cy.visit('/portfolio'); + connectVegaWallet(); + validatePositionsDisplayed(); + }); + + function validatePositionsDisplayed() { cy.getByTestId('tab-positions').should('be.visible'); - cy.getByTestId('tab-positions') - .get('[col-id="marketName"]') - .should('be.visible') - .each(($marketSymbol) => { - cy.wrap($marketSymbol).invoke('text').should('not.be.empty'); - }); - cy.getByTestId('tab-positions') - .get('[col-id="openVolume"]') - .each(($openVolume) => { + cy.getByTestId('tab-positions').within(() => { + cy.get('[col-id="marketName"]') + .should('be.visible') + .each(($marketSymbol) => { + cy.wrap($marketSymbol).invoke('text').should('not.be.empty'); + }); + + cy.get('[col-id="openVolume"]').each(($openVolume) => { cy.wrap($openVolume).invoke('text').should('not.be.empty'); }); - // includes average entry price, mark price, realised PNL & leverage - cy.getByTestId('tab-positions') - .getByTestId('flash-cell') - .each(($prices) => { + + // includes average entry price, mark price, realised PNL & leverage + cy.getByTestId('flash-cell').each(($prices) => { cy.wrap($prices).invoke('text').should('not.be.empty'); }); - cy.get('[col-id="averageEntryPrice"]') - .should('contain.text', '11.29935') // entry price - .should('contain.text', '9.21954'); // liquidation price + cy.get('[col-id="averageEntryPrice"]') + .should('contain.text', '11.29935') // entry price + .should('contain.text', '9.21954'); // liquidation price - cy.get('[col-id="capitalUtilisation"]') // margin allocated - .should('contain.text', '0.00%') - .should('contain.text', '1,000.01000'); - }); + cy.get('[col-id="currentLeverage"]').should('contain.text', '1.1'); + + cy.get('[col-id="capitalUtilisation"]') // margin allocated + .should('contain.text', '0.00%') + .should('contain.text', '1,000.01000'); + + cy.get('[col-id="unrealisedPNL"]').each(($unrealisedPnl) => { + cy.wrap($unrealisedPnl).invoke('text').should('not.be.empty'); + }); + + cy.getByTestId('flash-cell').should('contain.text', '2,785.19482'); // Total tDAI position + cy.getByTestId('flash-cell').should('contain.text', '0.00100'); // Total Realised PNL + cy.get('[col-id="unrealisedPNL"]').should('contain.text', '17.90000'); // Total Unrealised PNL + }); + + cy.getByTestId('balance').eq(0).should('have.text', '1,000.01000'); // Asset balance + + cy.getByTestId('close-position').should('be.visible').and('have.length', 3); + } }); diff --git a/apps/trading-e2e/src/integration/withdraw.cy.ts b/apps/trading-e2e/src/integration/withdraw.cy.ts index 580b35060..d78adade8 100644 --- a/apps/trading-e2e/src/integration/withdraw.cy.ts +++ b/apps/trading-e2e/src/integration/withdraw.cy.ts @@ -1,7 +1,9 @@ import { aliasQuery } from '@vegaprotocol/cypress'; import { connectEthereumWallet } from '../support/ethereum-wallet'; +import { generateAccounts } from '../support/mocks/generate-accounts'; import { generateNetworkParameters } from '../support/mocks/generate-network-parameters'; -import { generateWithdrawPageQuery } from '../support/mocks/generate-withdraw-page-query'; +import { generateWithdrawFormQuery } from '../support/mocks/generate-withdraw-page-query'; +import { generateWithdrawals } from '../support/mocks/generate-withdrawals'; import { connectVegaWallet } from '../support/vega-wallet'; describe('withdraw', () => { @@ -16,10 +18,14 @@ describe('withdraw', () => { beforeEach(() => { cy.mockWeb3Provider(); cy.mockGQL((req) => { - aliasQuery(req, 'WithdrawPageQuery', generateWithdrawPageQuery()); + aliasQuery(req, 'Withdrawals', generateWithdrawals()); aliasQuery(req, 'NetworkParamsQuery', generateNetworkParameters()); + aliasQuery(req, 'WithdrawFormQuery', generateWithdrawFormQuery()); + aliasQuery(req, 'Accounts', generateAccounts()); }); - cy.visit('/portfolio/withdraw'); + + cy.visit('/portfolio'); + cy.getByTestId('Withdrawals').click(); // Withdraw page requires vega wallet connection connectVegaWallet(); @@ -27,15 +33,14 @@ describe('withdraw', () => { // It also requires connection Ethereum wallet connectEthereumWallet(); - cy.wait('@WithdrawPageQuery'); - cy.contains('Withdraw'); + cy.mockGQL((req) => { + aliasQuery(req, 'WithdrawFormQuery', generateWithdrawFormQuery()); + }); + cy.getByTestId('withdraw-dialog-button').click(); + cy.wait('@WithdrawFormQuery'); }); it('form validation', () => { - // Prompts that there are incomplete withdrawals - cy.contains('You have incomplete withdrawals'); - cy.getByTestId('complete-withdrawals-prompt').should('exist'); - cy.getByTestId(submitWithdrawBtn).click(); cy.getByTestId(formFieldError).should('contain.text', 'Required'); @@ -78,13 +83,24 @@ describe('withdraw', () => { }, }); cy.get(assetSelectField).select('Asset 0'); + cy.getByTestId('balance-available') + .should('contain.text', 'Balance available') + .find('td') + .should('have.text', '1000'); + cy.getByTestId('withdrawal-threshold') + .should('contain.text', 'Delayed withdrawal threshold') + .find('td') + .should('contain.text', '1m+'); + cy.getByTestId('delay-time') + .should('contain.text', 'Delay time') + .find('td') + .should('have.text', 'None'); cy.get(amountField).clear().type('10'); cy.getByTestId(submitWithdrawBtn).click(); cy.getByTestId('dialog-title').should( 'have.text', - 'Withdrawal transaction pending' + 'Awaiting network confirmation' ); - cy.getByTestId('dialog-text').should('have.text', 'Awaiting transaction'); }); it.skip('creates a withdrawal on submit'); // Needs capsule diff --git a/apps/trading-e2e/src/integration/withdrawals.cy.ts b/apps/trading-e2e/src/integration/withdrawals.cy.ts deleted file mode 100644 index 084fcabbb..000000000 --- a/apps/trading-e2e/src/integration/withdrawals.cy.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { aliasQuery } from '@vegaprotocol/cypress'; -import { connectEthereumWallet } from '../support/ethereum-wallet'; -import { generateNetworkParameters } from '../support/mocks/generate-network-parameters'; -import { generateWithdrawals } from '../support/mocks/generate-withdrawals'; -import { connectVegaWallet } from '../support/vega-wallet'; - -describe('withdrawals', () => { - beforeEach(() => { - cy.mockWeb3Provider(); - cy.mockGQL((req) => { - aliasQuery(req, 'Withdrawals', generateWithdrawals()); - aliasQuery(req, 'NetworkParamsQuery', generateNetworkParameters()); - }); - cy.visit('/portfolio/withdrawals'); - - // Withdraw page requires vega wallet connection - connectVegaWallet(); - - // It also requires connection Ethereum wallet - connectEthereumWallet(); - }); - - it('renders history of withdrawals', () => { - const ethAddressLink = `${Cypress.env( - 'ETHERSCAN_URL' - )}/address/0x72c22822A19D20DE7e426fB84aa047399Ddd8853`; - const etherScanLink = `${Cypress.env( - 'ETHERSCAN_URL' - )}/tx/0x5d7b1a35ba6bd23be17bb7a159c13cdbb3121fceb94e9c6c510f5503dce48d03`; - - const row = '.ag-center-cols-container[role="rowgroup"] > [role="row"]'; - - // First row is incomplete - cy.get(row) - .eq(0) - .find('[col-id="asset.symbol"]') - .should('contain.text', 'AST0'); - cy.get(row) - .eq(0) - .find('[col-id="amount"]') - .should('contain.text', '0.00100'); - cy.get(row) - .eq(0) - .find('[col-id="details.receiverAddress"]') - .should('contain.text', '0x72c2…dd8853') - .find('a') - .should('have.attr', 'href', ethAddressLink); - cy.get(row) - .eq(0) - .find('[col-id="createdTimestamp"]') - .invoke('text') - .should('not.be.empty'); - cy.get(row) - .eq(0) - .find('[col-id="status"]') - .should('contain.text', 'Open') - .find('button') - .contains('Click to complete'); - - // Second row is complete so last cell should have a link to the tx - cy.get(row) - .eq(1) - .find('[col-id="status"]') - .should('contain.text', 'Finalized') - .find('a') - .contains('View on Etherscan') - .should('have.attr', 'href', etherScanLink); - }); - - it('renders a link to start a new withdrawal', () => { - cy.getByTestId('start-withdrawal').click(); - cy.url().should('include', '/portfolio/withdraw'); - }); - - it.skip('renders pending and unfinished withdrawals'); - it.skip('can complete unfinished withdrawals'); // Needs capsule -}); diff --git a/apps/trading-e2e/src/support/mocks/generate-accounts.ts b/apps/trading-e2e/src/support/mocks/generate-accounts.ts index 3c6d4e36e..f0e322bb5 100644 --- a/apps/trading-e2e/src/support/mocks/generate-accounts.ts +++ b/apps/trading-e2e/src/support/mocks/generate-accounts.ts @@ -1,12 +1,12 @@ import merge from 'lodash/merge'; -import type { Accounts } from '@vegaprotocol/accounts'; +import type { AccountsQuery } from '@vegaprotocol/accounts'; import { AccountType } from '@vegaprotocol/types'; import type { PartialDeep } from 'type-fest'; export const generateAccounts = ( - override?: PartialDeep -): Accounts => { - const defaultAccounts: Accounts = { + override?: PartialDeep +): AccountsQuery => { + const defaultAccounts: AccountsQuery = { party: { __typename: 'Party', id: Cypress.env('VEGA_PUBLIC_KEY'), @@ -29,7 +29,13 @@ export const generateAccounts = ( balance: '100000000', market: { id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13', - name: 'AAVEDAI Monthly (30 Jun 2022)', + tradableInstrument: { + __typename: 'TradableInstrument', + instrument: { + __typename: 'Instrument', + name: 'AAVEDAI Monthly (30 Jun 2022)', + }, + }, __typename: 'Market', }, asset: { @@ -45,7 +51,13 @@ export const generateAccounts = ( balance: '1000', market: { __typename: 'Market', - name: '', + tradableInstrument: { + __typename: 'TradableInstrument', + instrument: { + __typename: 'Instrument', + name: '', + }, + }, id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376', }, asset: { @@ -61,7 +73,13 @@ export const generateAccounts = ( balance: '1000', market: { __typename: 'Market', - name: '', + tradableInstrument: { + __typename: 'TradableInstrument', + instrument: { + __typename: 'Instrument', + name: '', + }, + }, id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d', }, asset: { @@ -71,6 +89,18 @@ export const generateAccounts = ( decimals: 5, }, }, + { + __typename: 'Account', + type: AccountType.ACCOUNT_TYPE_GENERAL, + balance: '100000000', + market: null, + asset: { + __typename: 'Asset', + id: 'asset-0', + symbol: 'AST0', + decimals: 5, + }, + }, ], }, }; diff --git a/apps/trading-e2e/src/support/mocks/generate-candles.ts b/apps/trading-e2e/src/support/mocks/generate-candles.ts index 2ce58d860..3ac1912f3 100644 --- a/apps/trading-e2e/src/support/mocks/generate-candles.ts +++ b/apps/trading-e2e/src/support/mocks/generate-candles.ts @@ -1,12 +1,14 @@ import merge from 'lodash/merge'; import type { PartialDeep } from 'type-fest'; import type { - Candles, - Candles_market_candles, + CandlesQuery, + CandleFieldsFragment, } from '@vegaprotocol/candles-chart'; -export const generateCandles = (override?: PartialDeep): Candles => { - const candles: Candles_market_candles[] = [ +export const generateCandles = ( + override?: PartialDeep +): CandlesQuery => { + const candles: CandleFieldsFragment[] = [ { datetime: '2022-04-06T09:15:00Z', high: '17481092', diff --git a/apps/trading-e2e/src/support/mocks/generate-chart.ts b/apps/trading-e2e/src/support/mocks/generate-chart.ts index f80db6353..91819aedd 100644 --- a/apps/trading-e2e/src/support/mocks/generate-chart.ts +++ b/apps/trading-e2e/src/support/mocks/generate-chart.ts @@ -1,15 +1,21 @@ import merge from 'lodash/merge'; import type { PartialDeep } from 'type-fest'; -import type { - Chart, - Chart_market_data_priceMonitoringBounds, -} from '@vegaprotocol/candles-chart'; +import type { ChartQuery } from '@vegaprotocol/candles-chart'; +import type { Schema } from '@vegaprotocol/types'; -export const generateChart = (override?: PartialDeep): Chart => { - const priceMonitoringBound: Chart_market_data_priceMonitoringBounds = { +export const generateChart = ( + override?: PartialDeep +): ChartQuery => { + const priceMonitoringBound: Schema.PriceMonitoringBounds = { minValidPrice: '16256291', maxValidPrice: '18296869', referencePrice: '17247489', + trigger: { + __typename: 'PriceMonitoringTrigger', + auctionExtensionSecs: 1, + horizonSecs: 0, + probability: 0, + }, __typename: 'PriceMonitoringBounds', }; const defaultResult = { diff --git a/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts b/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts index 55c162232..faa6ff55e 100644 --- a/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts +++ b/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts @@ -10,7 +10,6 @@ export const generateDealTicketQuery = ( market: { __typename: 'Market', id: 'market-0', - name: 'ETHBTC Quarterly (30 Jun 2022)', decimalPlaces: 5, positionDecimalPlaces: 0, state: MarketState.STATE_ACTIVE, @@ -18,8 +17,9 @@ export const generateDealTicketQuery = ( tradableInstrument: { __typename: 'TradableInstrument', instrument: { - id: 'tBTC TEST', __typename: 'Instrument', + id: 'tBTC TEST', + name: 'ETHBTC Quarterly (30 Jun 2022)', product: { __typename: 'Future', quoteName: 'BTC', diff --git a/apps/trading-e2e/src/support/mocks/generate-deposit-page.ts b/apps/trading-e2e/src/support/mocks/generate-deposit-page.ts index 6ca1997c5..105e41d07 100644 --- a/apps/trading-e2e/src/support/mocks/generate-deposit-page.ts +++ b/apps/trading-e2e/src/support/mocks/generate-deposit-page.ts @@ -1,3 +1,4 @@ +import { AssetStatus } from '@vegaprotocol/types'; import merge from 'lodash/merge'; import type { PartialDeep } from 'type-fest'; @@ -14,6 +15,7 @@ export const generateDepositPage = ( symbol: 'AST0', name: 'Asset 0', decimals: 5, + status: AssetStatus.STATUS_ENABLED, source: { __typename: 'ERC20', contractAddress: '0x5E4b9aDA947130Fc320a144cd22bC1641e5c9d81', @@ -28,6 +30,7 @@ export const generateDepositPage = ( symbol: 'AST1', name: 'Asset 1', decimals: 5, + status: AssetStatus.STATUS_ENABLED, source: { __typename: 'ERC20', contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d81', @@ -36,6 +39,51 @@ export const generateDepositPage = ( }, __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', }, diff --git a/apps/trading-e2e/src/support/mocks/generate-fills.ts b/apps/trading-e2e/src/support/mocks/generate-fills.ts index 987e50653..192982fbc 100644 --- a/apps/trading-e2e/src/support/mocks/generate-fills.ts +++ b/apps/trading-e2e/src/support/mocks/generate-fills.ts @@ -23,7 +23,11 @@ export const generateFills = (override?: PartialDeep): Fills => { infrastructureFee: '5000', }, market: { - name: 'Apples Daily v3', + tradableInstrument: { + instrument: { + name: 'Apples Daily v3', + }, + }, positionDecimalPlaces: 2, }, }), @@ -38,7 +42,11 @@ export const generateFills = (override?: PartialDeep): Fills => { id: '3', aggressor: Side.SIDE_SELL, market: { - name: 'ETHBTC Quarterly (30 Jun 2022)', + tradableInstrument: { + instrument: { + name: 'ETHBTC Quarterly (30 Jun 2022)', + }, + }, }, buyer: { id: Cypress.env('VEGA_PUBLIC_KEY'), @@ -108,7 +116,6 @@ export const generateFill = ( market: { __typename: 'Market', id: 'market-id', - name: 'UNIDAI Monthly (30 Jun 2022)', positionDecimalPlaces: 0, decimalPlaces: 5, tradableInstrument: { @@ -117,6 +124,7 @@ export const generateFill = ( __typename: 'Instrument', id: 'instrument-id', code: 'instrument-code', + name: 'UNIDAI Monthly (30 Jun 2022)', product: { __typename: 'Future', settlementAsset: { diff --git a/apps/trading-e2e/src/support/mocks/generate-market-depth.ts b/apps/trading-e2e/src/support/mocks/generate-market-depth.ts index d7016fc1c..74012beb1 100644 --- a/apps/trading-e2e/src/support/mocks/generate-market-depth.ts +++ b/apps/trading-e2e/src/support/mocks/generate-market-depth.ts @@ -1,5 +1,4 @@ import merge from 'lodash/merge'; -import { MarketTradingMode } from '@vegaprotocol/types'; import type { PartialDeep } from 'type-fest'; // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries import type { MarketDepth } from '../../../../../libs/market-depth/src/lib/__generated__/MarketDepth'; @@ -10,26 +9,10 @@ export const generateMarketDepth = ( const defaultResult: MarketDepth = { market: { id: 'market-0', - decimalPlaces: 5, - positionDecimalPlaces: 0, - data: { - marketTradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, - staticMidPrice: '0', - indicativePrice: '0', - bestStaticBidPrice: '0', - bestStaticOfferPrice: '0', - indicativeVolume: '0', - market: { - id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35', - __typename: 'Market', - }, - __typename: 'MarketData', - }, depth: { __typename: 'MarketDepth', buy: [], sell: [], - lastTrade: null, sequenceNumber: '', }, __typename: 'Market', diff --git a/apps/trading-e2e/src/support/mocks/generate-market-info-query.ts b/apps/trading-e2e/src/support/mocks/generate-market-info-query.ts index 39238e0b0..9bd9a56c6 100644 --- a/apps/trading-e2e/src/support/mocks/generate-market-info-query.ts +++ b/apps/trading-e2e/src/support/mocks/generate-market-info-query.ts @@ -1,4 +1,4 @@ -import type { MarketInfoQuery } from '@vegaprotocol/deal-ticket'; +import type { MarketInfoQuery } from '@vegaprotocol/market-info'; import { AccountType, AuctionTrigger, @@ -15,8 +15,7 @@ export const generateMarketInfoQuery = ( market: { __typename: 'Market', id: 'market-0', - name: 'ETHBTC Quarterly (30 Jun 2022)', - decimalPlaces: 2, + decimalPlaces: 5, positionDecimalPlaces: 0, state: MarketState.STATE_ACTIVE, tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, @@ -86,7 +85,9 @@ export const generateMarketInfoQuery = ( id: '54b78c1b877e106842ae156332ccec740ad98d6bad43143ac6a029501dd7c6e0', }, markPrice: '5749', - indicativeVolume: '0', + suppliedStake: '56767', + marketValueProxy: '677678', + targetStake: '56789', bestBidVolume: '5', bestOfferVolume: '1', bestStaticBidVolume: '5', @@ -143,9 +144,10 @@ export const generateMarketInfoQuery = ( quoteName: 'BTC', settlementAsset: { __typename: 'Asset', - id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c', + id: 'market-0', symbol: 'tBTC', name: 'tBTC TEST', + decimals: 5, }, oracleSpecForSettlementPrice: { __typename: 'OracleSpec', diff --git a/apps/trading-e2e/src/support/mocks/generate-market.ts b/apps/trading-e2e/src/support/mocks/generate-market.ts index 322bd3be4..7ac21d0ce 100644 --- a/apps/trading-e2e/src/support/mocks/generate-market.ts +++ b/apps/trading-e2e/src/support/mocks/generate-market.ts @@ -12,7 +12,6 @@ export const generateMarket = (override?: PartialDeep): Market => { const defaultResult: Market = { market: { id: 'market-0', - name: 'ACTIVE MARKET', tradingMode: MarketTradingMode.TRADING_MODE_MONITORING_AUCTION, state: MarketState.STATE_ACTIVE, decimalPlaces: 5, @@ -39,7 +38,7 @@ export const generateMarket = (override?: PartialDeep): Market => { tradableInstrument: { instrument: { id: 'BTCUSD.MF21', - name: 'BTCUSD Monthly', + name: 'ACTIVE MARKET', code: 'BTCUSD.MF21', metadata: { tags: [ @@ -59,6 +58,7 @@ export const generateMarket = (override?: PartialDeep): Market => { }, quoteName: 'BTCUSD Monthly', settlementAsset: { + decimals: 0, id: '000', symbol: 'USD', name: 'United States Dollar', diff --git a/apps/trading-e2e/src/support/mocks/generate-markets.ts b/apps/trading-e2e/src/support/mocks/generate-markets.ts index 4aa54b5fe..f40925d47 100644 --- a/apps/trading-e2e/src/support/mocks/generate-markets.ts +++ b/apps/trading-e2e/src/support/mocks/generate-markets.ts @@ -5,15 +5,19 @@ import { MarketTradingMode, } from '@vegaprotocol/types'; import type { PartialDeep } from 'type-fest'; -import type { MarketList, MarketList_markets } from '@vegaprotocol/market-list'; +import type { + Markets, + Markets_marketsConnection_edges_node, + MarketsCandlesQuery, + MarketsCandlesQuery_marketsConnection_edges_node, + MarketsDataQuery, + MarketsDataQuery_marketsConnection_edges_node, +} from '@vegaprotocol/market-list'; -export const generateMarkets = ( - override?: PartialDeep -): MarketList => { - const markets: MarketList_markets[] = [ +export const generateMarkets = (override?: PartialDeep): Markets => { + const markets: Markets_marketsConnection_edges_node[] = [ { id: 'market-0', - name: 'ACTIVE MARKET', decimalPlaces: 5, positionDecimalPlaces: 0, tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, @@ -23,15 +27,6 @@ export const generateMarkets = ( close: '', open: '', }, - candles: [ - { - __typename: 'Candle', - open: '100', - close: '100', - high: '110', - low: '90', - }, - ], fees: { __typename: 'Fees', factors: { @@ -41,25 +36,11 @@ export const generateMarkets = ( liquidityFee: '', }, }, - data: { - market: { - id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35', - state: MarketState.STATE_ACTIVE, - tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, - __typename: 'Market', - }, - indicativeVolume: '0', - bestBidPrice: '0', - bestOfferPrice: '0', - markPrice: '4612690058', - trigger: AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { id: '', code: 'BTCUSD.MF21', - name: '', + name: 'ACTIVE MARKET', metadata: { __typename: 'InstrumentMetadata', tags: [], @@ -79,7 +60,6 @@ export const generateMarkets = ( }, { id: 'market-1', - name: 'SUSPENDED MARKET', decimalPlaces: 2, positionDecimalPlaces: 0, tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, @@ -89,15 +69,6 @@ export const generateMarkets = ( close: '', open: '', }, - candles: [ - { - __typename: 'Candle', - open: '100', - close: '100', - high: '110', - low: '90', - }, - ], fees: { __typename: 'Fees', factors: { @@ -107,24 +78,10 @@ export const generateMarkets = ( liquidityFee: '', }, }, - data: { - market: { - id: '34d95e10faa00c21d19d382d6d7e6fc9722a96985369f0caec041b0f44b775ed', - state: MarketState.STATE_SUSPENDED, - tradingMode: MarketTradingMode.TRADING_MODE_NO_TRADING, - __typename: 'Market', - }, - bestBidPrice: '0', - bestOfferPrice: '0', - indicativeVolume: '0', - markPrice: '8441', - trigger: AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { id: 'SOLUSD', - name: 'SOL/USD', + name: 'SUSPENDED MARKET', code: 'SOLUSD', metadata: { __typename: 'InstrumentMetadata', @@ -145,7 +102,6 @@ export const generateMarkets = ( }, { id: 'market-2', - name: 'Apple Monthly (30 Jun 2022)', decimalPlaces: 5, positionDecimalPlaces: 0, tradingMode: MarketTradingMode.TRADING_MODE_MONITORING_AUCTION, @@ -155,15 +111,6 @@ export const generateMarkets = ( close: '2022-08-26T11:36:32.252490405Z', open: null, }, - candles: [ - { - __typename: 'Candle', - open: '100', - close: '100', - high: '110', - low: '90', - }, - ], fees: { __typename: 'Fees', factors: { @@ -173,20 +120,6 @@ export const generateMarkets = ( liquidityFee: '0.001', }, }, - data: { - market: { - id: 'a1c731af07570ca49b22a3cd253cc143dc14068edbec918e1087e69db934af5f', - state: MarketState.STATE_SUSPENDED, - tradingMode: MarketTradingMode.TRADING_MODE_MONITORING_AUCTION, - __typename: 'Market', - }, - indicativeVolume: '0', - bestBidPrice: '0', - bestOfferPrice: '0', - markPrice: '4612690058', - trigger: AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { id: '', @@ -211,7 +144,6 @@ export const generateMarkets = ( }, { id: 'market-3', - name: 'ETHBTC Quarterly (30 Jun 2022)', decimalPlaces: 5, positionDecimalPlaces: 0, tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, @@ -221,15 +153,6 @@ export const generateMarkets = ( close: '2022-08-26T11:36:32.252490405Z', open: null, }, - candles: [ - { - __typename: 'Candle', - open: '100', - close: '100', - high: '110', - low: '90', - }, - ], fees: { __typename: 'Fees', factors: { @@ -239,20 +162,6 @@ export const generateMarkets = ( liquidityFee: '0.001', }, }, - data: { - market: { - id: 'bebea8ec669b913a7d6a704a6d8cede164bc1376229e0d472bc6fdaa976629b2', - state: MarketState.STATE_ACTIVE, - tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, - __typename: 'Market', - }, - indicativeVolume: '0', - bestBidPrice: '0', - bestOfferPrice: '0', - markPrice: '4612690058', - trigger: AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY, - __typename: 'MarketData', - }, tradableInstrument: { instrument: { id: '', @@ -276,8 +185,212 @@ export const generateMarkets = ( __typename: 'Market', }, ]; - const defaultResult = { - markets, + + const defaultResult: Markets = { + marketsConnection: { + __typename: 'MarketConnection', + edges: markets.map((node) => ({ + __typename: 'MarketEdge', + node, + })), + }, + }; + + return merge(defaultResult, override); +}; + +export const generateMarketsData = ( + override?: PartialDeep +): MarketsDataQuery => { + const markets: MarketsDataQuery_marketsConnection_edges_node[] = [ + { + data: { + market: { + id: 'market-0', + __typename: 'Market', + }, + marketTradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, + staticMidPrice: '0', + indicativePrice: '0', + bestStaticBidPrice: '0', + bestStaticOfferPrice: '0', + indicativeVolume: '0', + bestBidPrice: '0', + bestOfferPrice: '0', + markPrice: '4612690058', + trigger: AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED, + __typename: 'MarketData', + }, + __typename: 'Market', + }, + { + data: { + market: { + id: 'market-1', + __typename: 'Market', + }, + marketTradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, + staticMidPrice: '0', + indicativePrice: '0', + bestStaticBidPrice: '0', + bestStaticOfferPrice: '0', + indicativeVolume: '0', + bestBidPrice: '0', + bestOfferPrice: '0', + markPrice: '8441', + trigger: AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED, + __typename: 'MarketData', + }, + __typename: 'Market', + }, + { + data: { + market: { + id: 'market-2', + __typename: 'Market', + }, + marketTradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, + staticMidPrice: '0', + indicativePrice: '0', + bestStaticBidPrice: '0', + bestStaticOfferPrice: '0', + indicativeVolume: '0', + bestBidPrice: '0', + bestOfferPrice: '0', + markPrice: '4612690058', + trigger: AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY, + __typename: 'MarketData', + }, + __typename: 'Market', + }, + { + data: { + market: { + id: 'market-3', + __typename: 'Market', + }, + marketTradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, + staticMidPrice: '0', + indicativePrice: '0', + bestStaticBidPrice: '0', + bestStaticOfferPrice: '0', + indicativeVolume: '0', + bestBidPrice: '0', + bestOfferPrice: '0', + markPrice: '4612690058', + trigger: AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY, + __typename: 'MarketData', + }, + __typename: 'Market', + }, + ]; + + const defaultResult: MarketsDataQuery = { + marketsConnection: { + __typename: 'MarketConnection', + edges: markets.map((node) => ({ + __typename: 'MarketEdge', + node, + })), + }, + }; + + return merge(defaultResult, override); +}; + +export const generateMarketsCandles = ( + override?: PartialDeep +): MarketsCandlesQuery => { + const markets: MarketsCandlesQuery_marketsConnection_edges_node[] = [ + { + __typename: 'Market', + id: 'market-0', + candlesConnection: { + __typename: 'CandleDataConnection', + edges: [ + { + __typename: 'CandleEdge', + node: { + __typename: 'CandleNode', + open: '100', + close: '100', + high: '110', + low: '90', + volume: '1', + }, + }, + ], + }, + }, + { + __typename: 'Market', + id: 'market-1', + candlesConnection: { + __typename: 'CandleDataConnection', + edges: [ + { + __typename: 'CandleEdge', + node: { + __typename: 'CandleNode', + open: '100', + close: '100', + high: '110', + low: '90', + volume: '1', + }, + }, + ], + }, + }, + { + __typename: 'Market', + id: 'market-2', + candlesConnection: { + __typename: 'CandleDataConnection', + edges: [ + { + __typename: 'CandleEdge', + node: { + __typename: 'CandleNode', + open: '100', + close: '100', + high: '110', + low: '90', + volume: '1', + }, + }, + ], + }, + }, + { + __typename: 'Market', + id: 'market-3', + candlesConnection: { + __typename: 'CandleDataConnection', + edges: [ + { + __typename: 'CandleEdge', + node: { + __typename: 'CandleNode', + open: '100', + close: '100', + high: '110', + low: '90', + volume: '1', + }, + }, + ], + }, + }, + ]; + const defaultResult: MarketsCandlesQuery = { + marketsConnection: { + __typename: 'MarketConnection', + edges: markets.map((node) => ({ + __typename: 'MarketEdge', + node, + })), + }, }; return merge(defaultResult, override); diff --git a/apps/trading-e2e/src/support/mocks/generate-order-book.ts b/apps/trading-e2e/src/support/mocks/generate-order-book.ts index 763072179..1529083e2 100644 --- a/apps/trading-e2e/src/support/mocks/generate-order-book.ts +++ b/apps/trading-e2e/src/support/mocks/generate-order-book.ts @@ -4,33 +4,13 @@ import type { MarketDepth, MarketDepth_market, } from '@vegaprotocol/market-depth'; -import { MarketTradingMode } from '@vegaprotocol/types'; export const generateOrderBook = ( override?: PartialDeep ): MarketDepth => { const marketDepth: MarketDepth_market = { id: 'b2426f67b085ba8fb429f1b529d49372b2d096c6fb6f509f76c5863abb6d969e', - decimalPlaces: 5, - positionDecimalPlaces: 0, - data: { - staticMidPrice: '826337', - marketTradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, - indicativeVolume: '0', - indicativePrice: '0', - bestStaticBidPrice: '826336', - bestStaticOfferPrice: '826338', - market: { - id: 'b2426f67b085ba8fb429f1b529d49372b2d096c6fb6f509f76c5863abb6d969e', - __typename: 'Market', - }, - __typename: 'MarketData', - }, depth: { - lastTrade: { - price: '826338', - __typename: 'Trade', - }, sell: [ { price: '826338', diff --git a/apps/trading-e2e/src/support/mocks/generate-orders.ts b/apps/trading-e2e/src/support/mocks/generate-orders.ts index b466ffb3e..ca65d3061 100644 --- a/apps/trading-e2e/src/support/mocks/generate-orders.ts +++ b/apps/trading-e2e/src/support/mocks/generate-orders.ts @@ -19,7 +19,6 @@ export const generateOrders = (override?: PartialDeep): Orders => { market: { __typename: 'Market', id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d', - name: 'AAVEDAI Monthly (30 Jun 2022)', decimalPlaces: 5, positionDecimalPlaces: 0, tradableInstrument: { @@ -28,6 +27,7 @@ export const generateOrders = (override?: PartialDeep): Orders => { id: '', __typename: 'Instrument', code: 'AAVEDAI.MF21', + name: 'AAVEDAI Monthly (30 Jun 2022)', }, }, }, @@ -49,7 +49,6 @@ export const generateOrders = (override?: PartialDeep): Orders => { market: { __typename: 'Market', id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376', - name: 'Tesla Quarterly (30 Jun 2022)', decimalPlaces: 5, positionDecimalPlaces: 0, tradableInstrument: { @@ -58,6 +57,7 @@ export const generateOrders = (override?: PartialDeep): Orders => { id: '', __typename: 'Instrument', code: 'TSLA.QM21', + name: 'Tesla Quarterly (30 Jun 2022)', }, }, }, @@ -79,7 +79,7 @@ export const generateOrders = (override?: PartialDeep): Orders => { market: { __typename: 'Market', id: 'c6f4337b31ed57a961969c3ba10297b369d01b9e75a4cbb96db4fc62886444e6', - name: 'BTCUSD Monthly (30 Jun 2022)', + decimalPlaces: 5, positionDecimalPlaces: 0, tradableInstrument: { @@ -88,6 +88,7 @@ export const generateOrders = (override?: PartialDeep): Orders => { id: '', __typename: 'Instrument', code: 'BTCUSD.MF21', + name: 'BTCUSD Monthly (30 Jun 2022)', }, }, }, @@ -109,7 +110,6 @@ export const generateOrders = (override?: PartialDeep): Orders => { market: { __typename: 'Market', id: 'a316fa51dab97d76a1472c2f22906f4e461728e04355096788165d5b13999ed5', - name: 'UNIDAI Monthly (30 Jun 2022)', decimalPlaces: 5, positionDecimalPlaces: 0, tradableInstrument: { @@ -118,6 +118,7 @@ export const generateOrders = (override?: PartialDeep): Orders => { id: '', __typename: 'Instrument', code: 'UNIDAI.MF21', + name: 'UNIDAI Monthly (30 Jun 2022)', }, }, }, @@ -139,7 +140,6 @@ export const generateOrders = (override?: PartialDeep): Orders => { market: { __typename: 'Market', id: 'a316fa51dab97d76a1472c2f22906f4e461728e04355096788165d5b13999ed5', - name: 'UNIDAI Monthly (30 Jun 2022)', decimalPlaces: 5, positionDecimalPlaces: 0, tradableInstrument: { @@ -148,6 +148,7 @@ export const generateOrders = (override?: PartialDeep): Orders => { id: '', __typename: 'Instrument', code: 'UNIDAI.MF21', + name: 'UNIDAI Monthly (30 Jun 2022)', }, }, }, diff --git a/apps/trading-e2e/src/support/mocks/generate-positions.ts b/apps/trading-e2e/src/support/mocks/generate-positions.ts index 00ec06fba..cbe5665a0 100644 --- a/apps/trading-e2e/src/support/mocks/generate-positions.ts +++ b/apps/trading-e2e/src/support/mocks/generate-positions.ts @@ -42,7 +42,6 @@ export const generatePositions = ( }, market: { id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d', - name: 'UNIDAI Monthly (30 Jun 2022)', tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, data: { markPrice: '17588787', @@ -64,6 +63,59 @@ export const generatePositions = ( __typename: 'Market', }, }, + { + __typename: 'Position', + realisedPNL: '100', + openVolume: '20', + unrealisedPNL: '895000', + averageEntryPrice: '8509338', + updatedAt: '2022-07-28T15:09:34.441143Z', + marginsConnection: { + __typename: 'MarginConnection', + edges: [ + { + __typename: 'MarginEdge', + node: { + __typename: 'MarginLevels', + maintenanceLevel: '0', + searchLevel: '0', + initialLevel: '0', + collateralReleaseLevel: '0', + market: { + __typename: 'Market', + id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13', + }, + asset: { + __typename: 'Asset', + symbol: 'tDAI', + }, + }, + }, + ], + }, + market: { + id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13', + tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, + data: { + markPrice: '8649338', + __typename: 'MarketData', + market: { + __typename: 'Market', + id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13', + }, + }, + decimalPlaces: 5, + positionDecimalPlaces: 0, + tradableInstrument: { + instrument: { + name: 'AAVEDAI Monthly (30 Jun 2022)', + __typename: 'Instrument', + }, + __typename: 'TradableInstrument', + }, + __typename: 'Market', + }, + }, { realisedPNL: '0', openVolume: '1', @@ -95,7 +147,6 @@ export const generatePositions = ( }, market: { id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376', - name: 'Tesla Quarterly (30 Jun 2022)', tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS, data: { markPrice: '84377569', 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 index fb26f30d6..01c57a4cf 100644 --- a/apps/trading-e2e/src/support/mocks/generate-withdraw-page-query.ts +++ b/apps/trading-e2e/src/support/mocks/generate-withdraw-page-query.ts @@ -1,66 +1,71 @@ -import { AccountType } from '@vegaprotocol/types'; +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 generateWithdrawPageQuery = ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - override?: PartialDeep -) => { +export const generateWithdrawFormQuery = ( + override?: PartialDeep +): WithdrawFormQuery => { + const withdrawal: WithdrawFormQuery_party_withdrawals = { + id: 'withdrawal-0', + txHash: null, + __typename: 'Withdrawal', + }; + const account: WithdrawFormQuery_party_accounts = { + type: AccountType.ACCOUNT_TYPE_GENERAL, + balance: '100000000', + asset: { + __typename: 'Asset', + id: 'asset-0', + symbol: 'AST0', + }, + __typename: 'Account', + }; + const assetEdge1: WithdrawFormQuery_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', + }; + const assetEdge2: WithdrawFormQuery_assetsConnection_edges = { + node: { + id: 'asset-1', + symbol: 'AST1', + name: 'Asset 1', + decimals: 5, + status: AssetStatus.STATUS_ENABLED, + source: { + __typename: 'ERC20', + contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d81', + }, + __typename: 'Asset', + }, + __typename: 'AssetEdge', + }; const defaultResult = { party: { id: 'party-0', - withdrawals: [ - { - id: 'withdrawal-0', - txHash: null, - __typename: 'Withdrawal', - }, - ], - accounts: [ - { - type: AccountType.ACCOUNT_TYPE_GENERAL, - balance: '100000000', - asset: { - __typename: 'Asset', - id: 'asset-0', - symbol: 'AST0', - }, - __typename: 'Account', - }, - ], + withdrawals: [withdrawal], + accounts: [account], __typename: 'Party', }, assetsConnection: { - edges: [ - { - node: { - id: 'asset-0', - symbol: 'AST0', - name: 'Asset 0', - decimals: 5, - source: { - __typename: 'ERC20', - contractAddress: '0x5E4b9aDA947130Fc320a144cd22bC1641e5c9d81', - }, - __typename: 'Asset', - }, - __typename: 'AssetEdge', - }, - { - node: { - id: 'asset-1', - symbol: 'AST1', - name: 'Asset 1', - decimals: 5, - source: { - __typename: 'ERC20', - contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d81', - }, - __typename: 'Asset', - }, - __typename: 'AssetEdge', - }, - ], + __typename: 'AssetsConnection', + edges: [assetEdge1, assetEdge2], }, }; diff --git a/apps/trading-e2e/src/support/mocks/generate-withdrawals.ts b/apps/trading-e2e/src/support/mocks/generate-withdrawals.ts index a134200b4..206e16a97 100644 --- a/apps/trading-e2e/src/support/mocks/generate-withdrawals.ts +++ b/apps/trading-e2e/src/support/mocks/generate-withdrawals.ts @@ -1,55 +1,76 @@ -import { WithdrawalStatus } from '@vegaprotocol/types'; +import { AssetStatus, WithdrawalStatus } from '@vegaprotocol/types'; +import type { Withdrawals } from '@vegaprotocol/withdraws'; import merge from 'lodash/merge'; import type { PartialDeep } from 'type-fest'; -export const generateWithdrawals = ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - override?: PartialDeep -) => { - const defaultResult = { +export const generateWithdrawals = (override?: PartialDeep) => { + const defaultResult: Withdrawals = { party: { id: 'party-0', - withdrawals: [ - { - id: 'withdrawal-0', - status: WithdrawalStatus.STATUS_FINALIZED, - amount: '100', - txHash: null, - createdTimestamp: new Date('2022-02-02').toISOString(), - withdrawnTimestamp: new Date('2022-02-02').toISOString(), - details: { - __typename: 'Erc20WithdrawalDetails', - receiverAddress: '0x72c22822A19D20DE7e426fB84aa047399Ddd8853', + withdrawalsConnection: { + __typename: 'WithdrawalsConnection', + edges: [ + { + __typename: 'WithdrawalEdge', + node: { + id: 'withdrawal-0', + status: WithdrawalStatus.STATUS_FINALIZED, + amount: '100', + txHash: null, + createdTimestamp: new Date('2022-02-02').toISOString(), + withdrawnTimestamp: new Date('2022-02-02').toISOString(), + pendingOnForeignChain: false, + details: { + __typename: 'Erc20WithdrawalDetails', + receiverAddress: '0x72c22822A19D20DE7e426fB84aa047399Ddd8853', + }, + asset: { + __typename: 'Asset', + id: 'asset-0', + name: 'asset-0 name', + symbol: 'AST0', + decimals: 5, + status: AssetStatus.STATUS_ENABLED, + source: { + __typename: 'ERC20', + contractAddress: '0x123', + }, + }, + __typename: 'Withdrawal', + }, }, - asset: { - __typename: 'Asset', - id: 'asset-0', - symbol: 'AST0', - decimals: 5, + { + __typename: 'WithdrawalEdge', + node: { + id: 'withdrawal-1', + status: WithdrawalStatus.STATUS_FINALIZED, + amount: '100', + txHash: + '0x5d7b1a35ba6bd23be17bb7a159c13cdbb3121fceb94e9c6c510f5503dce48d03', + createdTimestamp: new Date('2022-02-01').toISOString(), + withdrawnTimestamp: new Date('2022-02-01').toISOString(), + pendingOnForeignChain: false, + details: { + __typename: 'Erc20WithdrawalDetails', + receiverAddress: '0x72c22822A19D20DE7e426fB84aa047399Ddd8853', + }, + asset: { + __typename: 'Asset', + id: 'asset-0', + name: 'asset-0 name', + symbol: 'AST0', + decimals: 5, + status: AssetStatus.STATUS_ENABLED, + source: { + __typename: 'ERC20', + contractAddress: '0x123', + }, + }, + __typename: 'Withdrawal', + }, }, - __typename: 'Withdrawal', - }, - { - id: 'withdrawal-1', - status: WithdrawalStatus.STATUS_FINALIZED, - amount: '100', - txHash: - '0x5d7b1a35ba6bd23be17bb7a159c13cdbb3121fceb94e9c6c510f5503dce48d03', - createdTimestamp: new Date('2022-02-01').toISOString(), - withdrawnTimestamp: new Date('2022-02-01').toISOString(), - details: { - __typename: 'Erc20WithdrawalDetails', - receiverAddress: '0x72c22822A19D20DE7e426fB84aa047399Ddd8853', - }, - asset: { - __typename: 'Asset', - id: 'asset-0', - symbol: 'AST0', - decimals: 5, - }, - __typename: 'Withdrawal', - }, - ], + ], + }, __typename: 'Party', }, }; diff --git a/apps/trading-e2e/src/support/trading.ts b/apps/trading-e2e/src/support/trading.ts index 43f90041f..a63074c0f 100644 --- a/apps/trading-e2e/src/support/trading.ts +++ b/apps/trading-e2e/src/support/trading.ts @@ -8,7 +8,11 @@ import { generateDealTicketQuery } from './mocks/generate-deal-ticket-query'; import { generateMarket } from './mocks/generate-market'; import { generateMarketDepth } from './mocks/generate-market-depth'; import { generateMarketInfoQuery } from './mocks/generate-market-info-query'; -import { generateMarkets } from './mocks/generate-markets'; +import { + generateMarkets, + generateMarketsData, + generateMarketsCandles, +} from './mocks/generate-markets'; import { generateOrders } from './mocks/generate-orders'; import { generatePositions } from './mocks/generate-positions'; import { generateTrades } from './mocks/generate-trades'; @@ -22,12 +26,19 @@ export const mockTradingPage = ( 'Market', generateMarket({ market: { - name: `${state.toUpperCase()} MARKET`, + tradableInstrument: { + instrument: { + name: `${state.toUpperCase()} MARKET`, + }, + }, state: state, }, }) ); - aliasQuery(req, 'MarketList', generateMarkets()); + aliasQuery(req, 'Markets', generateMarkets()); + aliasQuery(req, 'MarketsDataQuery', generateMarketsData()); + aliasQuery(req, 'MarketsCandlesQuery', generateMarketsCandles()); + aliasQuery(req, 'MarketDepth', generateMarketDepth()); aliasQuery(req, 'Orders', generateOrders()); aliasQuery(req, 'Accounts', generateAccounts()); diff --git a/apps/trading/.env b/apps/trading/.env index 5e9905ad6..3fc6aca19 100644 --- a/apps/trading/.env +++ b/apps/trading/.env @@ -1,6 +1,6 @@ # App configuration variables NX_VEGA_ENV=TESTNET -NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql +NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHERSCAN_URL=https://ropsten.etherscan.io NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\"} diff --git a/apps/trading/.env.testnet b/apps/trading/.env.testnet index 5bd96ac0e..762151b78 100644 --- a/apps/trading/.env.testnet +++ b/apps/trading/.env.testnet @@ -1,6 +1,6 @@ # App configuration variables NX_VEGA_ENV=TESTNET -NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql +NX_VEGA_URL=https://api.n09.testnet.vega.xyz/graphql NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}' NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHERSCAN_URL=https://ropsten.etherscan.io diff --git a/apps/trading/.eslintrc.json b/apps/trading/.eslintrc.json index bc7243829..4219c80ff 100644 --- a/apps/trading/.eslintrc.json +++ b/apps/trading/.eslintrc.json @@ -5,7 +5,7 @@ "next", "next/core-web-vitals" ], - "ignorePatterns": ["!**/*", "__generated__"], + "ignorePatterns": ["!**/*", "__generated__", "__generated___"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], diff --git a/apps/trading/components/footer/footer.tsx b/apps/trading/components/footer/footer.tsx index 20ee8dbd0..ad35d6906 100644 --- a/apps/trading/components/footer/footer.tsx +++ b/apps/trading/components/footer/footer.tsx @@ -1,11 +1,8 @@ -import { Vega } from '../icons/vega'; - export const Footer = () => { return ( -
    +
    Status
    -
    ); diff --git a/apps/trading/components/header/header.tsx b/apps/trading/components/header/header.tsx new file mode 100644 index 000000000..07442bb5a --- /dev/null +++ b/apps/trading/components/header/header.tsx @@ -0,0 +1,57 @@ +import { Tooltip } from '@vegaprotocol/ui-toolkit'; +import type { ReactElement, ReactNode } from 'react'; +import { Children } from 'react'; +import { cloneElement } from 'react'; + +interface TradeMarketHeaderProps { + title: ReactNode; + children: Array; +} + +export const Header = ({ title, children }: TradeMarketHeaderProps) => { + return ( +
    +
    +
    {title}
    +
    + {Children.map(children, (child, index) => { + if (!child) return null; + return cloneElement(child, { + id: `header-stat-${index}`, + }); + })} +
    +
    +
    + ); +}; + +export const HeaderStat = ({ + children, + heading, + id, + description, +}: { + children: ReactNode; + heading: string; + id?: string; + description?: string | ReactNode; +}) => { + const itemClass = + 'min-w-min w-[120px] whitespace-nowrap pb-3 px-4 border-l border-default'; + const itemHeading = 'text-neutral-500 dark:text-neutral-400'; + + return ( +
    +
    {heading}
    + +
    + {children} +
    +
    +
    + ); +}; diff --git a/apps/trading/components/header/index.ts b/apps/trading/components/header/index.ts new file mode 100644 index 000000000..677ca79d4 --- /dev/null +++ b/apps/trading/components/header/index.ts @@ -0,0 +1 @@ +export * from './header'; diff --git a/apps/trading/components/navbar/navbar.tsx b/apps/trading/components/navbar/navbar.tsx index 57d748361..6bfc5cec8 100644 --- a/apps/trading/components/navbar/navbar.tsx +++ b/apps/trading/components/navbar/navbar.tsx @@ -5,7 +5,8 @@ import { NetworkSwitcher } from '@vegaprotocol/environment'; import { t } from '@vegaprotocol/react-helpers'; import { useGlobalStore } from '../../stores/global'; import { VegaWalletConnectButton } from '../vega-wallet-connect-button'; -import { ThemeSwitcher, VLogo } from '@vegaprotocol/ui-toolkit'; +import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit'; +import { Vega } from '../icons/vega'; interface NavbarProps { theme: 'light' | 'dark'; @@ -19,15 +20,15 @@ export const Navbar = ({ theme, toggleTheme }: NavbarProps) => { })); const tradingPath = marketId ? `/markets/${marketId}` : '/markets'; return ( -
    +
    {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} - + - +
    ); }; diff --git a/libs/deal-ticket/src/components/deal-ticket-market-amount.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-market-amount.tsx similarity index 100% rename from libs/deal-ticket/src/components/deal-ticket-market-amount.tsx rename to libs/deal-ticket/src/components/deal-ticket/deal-ticket-market-amount.tsx diff --git a/libs/deal-ticket/src/components/deal-ticket.spec.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.spec.tsx similarity index 100% rename from libs/deal-ticket/src/components/deal-ticket.spec.tsx rename to libs/deal-ticket/src/components/deal-ticket/deal-ticket.spec.tsx diff --git a/libs/deal-ticket/src/components/deal-ticket.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx similarity index 96% rename from libs/deal-ticket/src/components/deal-ticket.tsx rename to libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx index e0cb6ab4c..c1ed43607 100644 --- a/libs/deal-ticket/src/components/deal-ticket.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx @@ -60,6 +60,10 @@ export const DealTicket = ({ price: order.price && removeDecimal(order.price, market.decimalPlaces), size: removeDecimal(order.size, market.positionDecimalPlaces), + expiresAt: + order.timeInForce === OrderTimeInForce.TIME_IN_FORCE_GTT + ? order.expiresAt + : undefined, }); } }, diff --git a/libs/deal-ticket/src/components/expiry-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/expiry-selector.tsx similarity index 100% rename from libs/deal-ticket/src/components/expiry-selector.tsx rename to libs/deal-ticket/src/components/deal-ticket/expiry-selector.tsx diff --git a/libs/deal-ticket/src/components/deal-ticket/index.ts b/libs/deal-ticket/src/components/deal-ticket/index.ts new file mode 100644 index 000000000..97827ec50 --- /dev/null +++ b/libs/deal-ticket/src/components/deal-ticket/index.ts @@ -0,0 +1,12 @@ +export * from './__generated__'; +export * from './deal-ticket-amount'; +export * from './deal-ticket-container'; +export * from './deal-ticket-limit-amount'; +export * from './deal-ticket-manager'; +export * from './deal-ticket-market-amount'; +export * from './deal-ticket'; +export * from './expiry-selector'; +export * from './market-selector'; +export * from './side-selector'; +export * from './time-in-force-selector'; +export * from './type-selector'; diff --git a/libs/deal-ticket/src/components/market-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/market-selector.tsx similarity index 88% rename from libs/deal-ticket/src/components/market-selector.tsx rename to libs/deal-ticket/src/components/deal-ticket/market-selector.tsx index 898a5ac0f..312f6df9f 100644 --- a/libs/deal-ticket/src/components/market-selector.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/market-selector.tsx @@ -9,7 +9,7 @@ import React, { import * as DialogPrimitives from '@radix-ui/react-dialog'; import { gql, useQuery } from '@apollo/client'; import classNames from 'classnames'; -import type { DealTicketQuery_market } from './__generated__'; +import type { DealTicketQuery_market } from './'; import { ButtonLink, Icon, @@ -33,11 +33,11 @@ export const MARKET_NAMES_QUERY = gql` query MarketNames { markets { id - name state tradableInstrument { instrument { code + name metadata { tags } @@ -70,7 +70,9 @@ export const MarketSelector = ({ market, setMarket, ItemRenderer }: Props) => { const [skip, setSkip] = useState(true); const [results, setResults] = useState([]); const [showPane, setShowPane] = useState(false); - const [lookup, setLookup] = useState(market.name || ''); + const [lookup, setLookup] = useState( + market.tradableInstrument.instrument.name || '' + ); const [dialogContent, setDialogContent] = useState( null ); @@ -102,10 +104,13 @@ export const MarketSelector = ({ market, setMarket, ItemRenderer }: Props) => { ); const handleMarketSelect = useCallback( - ({ id, name }: { id: string; name: string }) => { - setLookup(name); + (market: { + id: string; + tradableInstrument: { instrument: { name: string } }; + }) => { + setLookup(market.tradableInstrument.instrument.name); setShowPane(false); - setMarket(id); + setMarket(market.id); inputRef.current?.focus(); }, [setLookup, setShowPane, setMarket, inputRef] @@ -142,7 +147,7 @@ export const MarketSelector = ({ market, setMarket, ItemRenderer }: Props) => { break; default: setShowPane(false); - setLookup(market.name); + setLookup(market.tradableInstrument.instrument.name); } }, [results, handleMarketSelect] @@ -159,7 +164,7 @@ export const MarketSelector = ({ market, setMarket, ItemRenderer }: Props) => { const handleOnBlur = useCallback(() => { if (!lookup && !showPane) { - setLookup(market.name); + setLookup(market.tradableInstrument.instrument.name); } }, [market, lookup, showPane, setLookup]); @@ -173,11 +178,17 @@ export const MarketSelector = ({ market, setMarket, ItemRenderer }: Props) => { (isOpen: boolean) => { setShowPane(isOpen); if (!isOpen) { - setLookup(lookup || market.name); + setLookup(lookup || market.tradableInstrument.instrument.name); inputRef.current?.focus(); } }, - [setShowPane, lookup, setLookup, market.name, inputRef] + [ + setShowPane, + lookup, + setLookup, + market.tradableInstrument.instrument.name, + inputRef, + ] ); const selectorContent = useMemo(() => { @@ -185,7 +196,7 @@ export const MarketSelector = ({ market, setMarket, ItemRenderer }: Props) => {
    { onKeyDown={handleInputKeyDown} onBlur={handleOnBlur} /> - + {
    -
    +
    { onClick={() => handleMarketSelect(market)} onKeyDown={(e) => handleItemKeyDown(e, market, i)} > - {ItemRenderer ? : market.name} + {ItemRenderer ? ( + + ) : ( + market.tradableInstrument.instrument.name + )}
    ))}
    @@ -262,7 +277,9 @@ export const MarketSelector = ({ market, setMarket, ItemRenderer }: Props) => { data?.markets?.filter( (item: MarketNames_markets) => item.state === MarketState.STATE_ACTIVE && - item.name.match(new RegExp(escapeRegExp(lookup), 'i')) + item.tradableInstrument.instrument.name.match( + new RegExp(escapeRegExp(lookup), 'i') + ) ) || [] ); }, [data, lookup]); diff --git a/libs/deal-ticket/src/components/side-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/side-selector.tsx similarity index 100% rename from libs/deal-ticket/src/components/side-selector.tsx rename to libs/deal-ticket/src/components/deal-ticket/side-selector.tsx diff --git a/libs/deal-ticket/src/components/time-in-force-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/time-in-force-selector.tsx similarity index 100% rename from libs/deal-ticket/src/components/time-in-force-selector.tsx rename to libs/deal-ticket/src/components/deal-ticket/time-in-force-selector.tsx diff --git a/libs/deal-ticket/src/components/type-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx similarity index 100% rename from libs/deal-ticket/src/components/type-selector.tsx rename to libs/deal-ticket/src/components/deal-ticket/type-selector.tsx diff --git a/libs/deal-ticket/src/components/index.ts b/libs/deal-ticket/src/components/index.ts index 384200706..bb141727c 100644 --- a/libs/deal-ticket/src/components/index.ts +++ b/libs/deal-ticket/src/components/index.ts @@ -1,13 +1 @@ -export * from './__generated__'; -export * from './deal-ticket-amount'; -export * from './deal-ticket-container'; -export * from './deal-ticket-limit-amount'; -export * from './deal-ticket-manager'; -export * from './deal-ticket-market-amount'; export * from './deal-ticket'; -export * from './expiry-selector'; -export * from './info-market'; -export * from './side-selector'; -export * from './time-in-force-selector'; -export * from './type-selector'; -export * from './market-selector'; diff --git a/libs/deal-ticket/src/components/info-market.tsx b/libs/deal-ticket/src/components/info-market.tsx deleted file mode 100644 index e7fb234e6..000000000 --- a/libs/deal-ticket/src/components/info-market.tsx +++ /dev/null @@ -1,494 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import type { ReactNode } from 'react'; -import { useMemo } from 'react'; -import { - addDecimalsFormatNumber, - formatLabel, - formatNumber, - formatNumberPercentage, - t, -} from '@vegaprotocol/react-helpers'; -import { - KeyValueTable, - KeyValueTableRow, - AsyncRenderer, - Splash, - Accordion, - Tooltip, - Link, -} from '@vegaprotocol/ui-toolkit'; -import startCase from 'lodash/startCase'; -import pick from 'lodash/pick'; -import omit from 'lodash/omit'; -import type { MarketInfoQuery, MarketInfoQuery_market } from './__generated__'; -import BigNumber from 'bignumber.js'; -import { useQuery } from '@apollo/client'; -import { totalFees } from '@vegaprotocol/market-list'; -import { AccountType, Interval } from '@vegaprotocol/types'; -import { MARKET_INFO_QUERY } from './info-market-query'; -import { ExternalLink } from '@vegaprotocol/ui-toolkit'; - -import { generatePath } from 'react-router-dom'; -import { useEnvironment } from '@vegaprotocol/environment'; - -const Links = { - PROPOSAL_PAGE: ':tokenUrl/governance/:proposalId', -}; - -export interface InfoProps { - market: MarketInfoQuery_market; -} - -export const calcCandleVolume = ( - m: MarketInfoQuery_market -): string | undefined => { - return m?.candles - ?.reduce((acc, c) => { - return acc.plus(new BigNumber(c?.volume ?? 0)); - }, new BigNumber(0)) - .toString(); -}; - -export interface MarketInfoContainerProps { - marketId: string; -} -export const MarketInfoContainer = ({ marketId }: MarketInfoContainerProps) => { - const yTimestamp = useMemo(() => { - const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600; - return new Date(yesterday * 1000).toISOString(); - }, []); - - const { data, loading, error } = useQuery(MARKET_INFO_QUERY, { - variables: { marketId, interval: Interval.INTERVAL_I1H, since: yTimestamp }, - }); - - return ( - data={data} loading={loading} error={error}> - {data && data.market ? ( - - ) : ( - -

    {t('Could not load market')}

    -
    - )} - - ); -}; - -export const Info = ({ market }: InfoProps) => { - const { VEGA_TOKEN_URL } = useEnvironment(); - const headerClassName = 'uppercase text-lg'; - const dayVolume = calcCandleVolume(market); - const marketDataPanels = [ - { - title: t('Current fees'), - content: ( - <> - -

    - {t( - 'All fees are paid by price takers and are a % of the trade notional value. Fees are not paid during auction uncrossing.' - )} -

    - - ), - }, - { - title: t('Market price'), - content: ( - - ), - }, - { - title: t('Market volume'), - content: ( - - ), - }, - ...(market.accounts || []) - .filter((a) => a.type === AccountType.ACCOUNT_TYPE_INSURANCE) - .map((a, i) => ({ - title: t(`Insurance pool`), - content: ( - - ), - })), - ]; - - const keyDetails = pick( - market, - 'name', - 'decimalPlaces', - 'positionDecimalPlaces', - 'tradingMode', - 'state', - 'id' as 'marketId' - ); - const marketSpecPanels = [ - { - title: t('Key details'), - content: ( - - ), - }, - { - title: t('Instrument'), - content: ( - - ), - }, - { - title: t('Settlement asset'), - content: ( - - ), - }, - { - title: t('Metadata'), - content: ( - { - const [key, value] = tag.split(':'); - return { [key]: value }; - }) - .reduce((acc, curr) => ({ ...acc, ...curr }), {}), - }} - /> - ), - }, - { - title: t('Risk factors'), - content: ( - - ), - }, - { - title: t('Risk model'), - content: ( - - ), - }, - ...(market.priceMonitoringSettings?.parameters?.triggers || []).map( - (trigger, i) => ({ - title: t(`Price monitoring trigger ${i + 1}`), - content: , - }) - ), - ...(market.data?.priceMonitoringBounds || []).map((trigger, i) => ({ - title: t(`Price monitoring bound ${i + 1}`), - content: ( - - ), - })), - { - title: t('Liquidity monitoring parameters'), - content: ( - - ), - }, - { - title: t('Oracle'), - content: ( - - ), - }, - ]; - - const marketGovPanels = [ - { - title: t('Proposal'), - content: ( -

    - - {t('View governance proposal')} - -

    - ), - }, - ]; - - return ( -
    -
    -

    {t('Market data')}

    - -
    -
    -

    {t('Market specification')}

    - -
    - {VEGA_TOKEN_URL && market.proposal?.id && ( -
    -

    {t('Market governance')}

    - -
    - )} -
    - ); -}; - -const tooltipMapping: Record = { - makerFee: t( - 'Maker portion of the fee is transferred to the non-aggressive, or passive party in the trade (the maker, as opposed to the taker).' - ), - liquidityFee: t( - 'Liquidity portion of the fee is paid to market makers for providing liquidity, and is transferred to the market-maker fee pool for the market.' - ), - infrastructureFee: t( - 'Fees paid to validators as a reward for running the infrastructure of the network.' - ), - - markPrice: t( - 'A concept derived from traditional markets. It is a calculated value for the ‘current market price’ on a market.' - ), - openInterest: t( - 'The volume of all open positions in a given market (the sum of the size of all positions greater than 0).' - ), - indicativeVolume: t( - 'The volume at which all trades would occur if the auction was uncrossed now (when in auction mode).' - ), - bestBidVolume: t( - 'The aggregated volume being bid at the best bid price on the market.' - ), - bestOfferVolume: t( - 'The aggregated volume being offered at the best offer price on the market.' - ), - bestStaticBidVolume: t( - 'The aggregated volume being bid at the best static bid price on the market.' - ), - bestStaticOfferVolume: t( - 'The aggregated volume being offered at the best static offer price on the market.' - ), - - decimalPlaces: t('The smallest price increment on the book.'), - positionDecimalPlaces: t( - 'How big the smallest order / position on the market can be.' - ), - tradingMode: t('The trading mode the market is currently running.'), - state: t('The current state of the market'), - - base: t( - 'The first currency in a pair for a currency-based derivatives market.' - ), - quote: t( - 'The second currency in a pair for a currency-based derivatives market.' - ), - class: t( - 'The classification of the product. Examples: shares, commodities, crypto, FX.' - ), - sector: t( - 'Data about the sector. Example: "automotive" for a market based on value of Tesla shares.' - ), - - short: t( - 'A number that will be calculated by an appropriate stochastic risk model, dependent on the type of risk model used and its parameters.' - ), - long: t( - 'A number that will be calculated by an appropriate stochastic risk model, dependent on the type of risk model used and its parameters.' - ), - - tau: ( - - {t('Projection horizon measured as a year fraction used in ')} - - {t('Expected Shortfall')} - - {t(' calculation when obtaining Risk Factor Long and Risk Factor Short')} - - ), - riskAversionParameter: ( - - {t('Probability level used in ')} - - {t('Expected Shortfall')} - - {t(' calculation when obtaining Risk Factor Long and Risk Factor Short')} - - ), - - horizonSecs: t('Time horizon of the price projection in seconds.'), - probability: t( - 'Probability level for price projection, e.g. value of 0.95 will result in a price range such that over the specified projection horizon, the prices observed in the market should be in that range 95% of the time.' - ), - auctionExtensionSecs: t( - 'Auction extension duration in seconds, should the price breach its theoretical level over the specified horizon at the specified probability level.' - ), - - triggeringRatio: t('The triggering ratio for entering liquidity auction.'), - timeWindow: t('The length of time over which open interest is measured.'), - scalingFactor: t( - 'The scaling between the liquidity demand estimate, based on open interest and target stake.' - ), -}; - -interface RowProps { - field: string; - value: any; - decimalPlaces?: number; - asPercentage?: boolean; - unformatted?: boolean; -} - -const Row = ({ - field, - value, - decimalPlaces, - asPercentage, - unformatted, -}: RowProps) => { - const isNumber = typeof value === 'number' || !isNaN(Number(value)); - const isPrimitive = typeof value === 'string' || isNumber; - if (isPrimitive) { - return ( - - -
    {startCase(t(field))}
    -
    - - {isNumber && !unformatted - ? decimalPlaces - ? addDecimalsFormatNumber(value, decimalPlaces) - : asPercentage - ? formatNumberPercentage(new BigNumber(value * 100)) - : formatNumber(Number(value)) - : value} - -
    - ); - } - return null; -}; - -export interface MarketInfoTableProps { - data: any; - decimalPlaces?: number; - asPercentage?: boolean; - unformatted?: boolean; - omits?: string[]; -} - -export const MarketInfoTable = ({ - data, - decimalPlaces, - asPercentage, - unformatted, - omits = ['__typename'], -}: MarketInfoTableProps) => { - return ( - - {Object.entries(omit(data, ...omits) || []).map(([key, value]) => ( - - ))} - - ); -}; diff --git a/libs/deposits/.eslintrc.json b/libs/deposits/.eslintrc.json index db820c5d0..de2a9b877 100644 --- a/libs/deposits/.eslintrc.json +++ b/libs/deposits/.eslintrc.json @@ -1,6 +1,6 @@ { "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*", "__generated__"], + "ignorePatterns": ["!**/*", "__generated__", "__generated___"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], diff --git a/libs/deposits/src/index.ts b/libs/deposits/src/index.ts index d267d759e..07125c4da 100644 --- a/libs/deposits/src/index.ts +++ b/libs/deposits/src/index.ts @@ -1 +1,3 @@ export * from './lib/deposit-manager'; +export * from './lib/use-deposits'; +export * from './lib/deposits-table'; diff --git a/libs/deposits/src/lib/Deposit.graphql b/libs/deposits/src/lib/Deposit.graphql new file mode 100644 index 000000000..390455e17 --- /dev/null +++ b/libs/deposits/src/lib/Deposit.graphql @@ -0,0 +1,11 @@ +subscription DepositEvent($partyId: ID!) { + busEvents(partyId: $partyId, batchSize: 0, types: [Deposit]) { + event { + ... on Deposit { + id + txHash + status + } + } + } +} diff --git a/libs/deposits/src/lib/__generated__/DepositEventSub.ts b/libs/deposits/src/lib/__generated__/DepositEventSub.ts new file mode 100644 index 000000000..411994334 --- /dev/null +++ b/libs/deposits/src/lib/__generated__/DepositEventSub.ts @@ -0,0 +1,83 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +import { DepositStatus } from "@vegaprotocol/types"; + +// ==================================================== +// GraphQL subscription operation: DepositEventSub +// ==================================================== + +export interface DepositEventSub_busEvents_event_TimeUpdate { + __typename: "TimeUpdate" | "MarketEvent" | "TransferResponses" | "PositionResolution" | "Order" | "Trade" | "Account" | "Party" | "MarginLevels" | "Proposal" | "Vote" | "MarketData" | "NodeSignature" | "LossSocialization" | "SettlePosition" | "Market" | "Asset" | "MarketTick" | "SettleDistressed" | "AuctionEvent" | "RiskFactor" | "Withdrawal" | "OracleSpec" | "LiquidityProvision"; +} + +export interface DepositEventSub_busEvents_event_Deposit_asset { + __typename: "Asset"; + /** + * The ID of the asset + */ + id: 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; +} + +export interface DepositEventSub_busEvents_event_Deposit { + __typename: "Deposit"; + /** + * The Vega internal ID of the deposit + */ + id: string; + /** + * The current status of the deposit + */ + status: DepositStatus; + /** + * The amount to be withdrawn + */ + amount: string; + /** + * The asset to be withdrawn + */ + asset: DepositEventSub_busEvents_event_Deposit_asset; + /** + * RFC3339Nano time at which the deposit was created + */ + createdTimestamp: string; + /** + * RFC3339Nano time at which the deposit was finalised + */ + creditedTimestamp: string | null; + /** + * Hash of the transaction on the foreign chain + */ + txHash: string | null; +} + +export type DepositEventSub_busEvents_event = DepositEventSub_busEvents_event_TimeUpdate | DepositEventSub_busEvents_event_Deposit; + +export interface DepositEventSub_busEvents { + __typename: "BusEvent"; + /** + * the payload - the wrapped event + */ + event: DepositEventSub_busEvents_event; +} + +export interface DepositEventSub { + /** + * Subscribe to event data from the event bus + */ + busEvents: DepositEventSub_busEvents[] | null; +} + +export interface DepositEventSubVariables { + partyId: string; +} diff --git a/libs/deposits/src/lib/__generated__/DepositFields.ts b/libs/deposits/src/lib/__generated__/DepositFields.ts new file mode 100644 index 000000000..8026e39f3 --- /dev/null +++ b/libs/deposits/src/lib/__generated__/DepositFields.ts @@ -0,0 +1,58 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +import { DepositStatus } from "@vegaprotocol/types"; + +// ==================================================== +// GraphQL fragment: DepositFields +// ==================================================== + +export interface DepositFields_asset { + __typename: "Asset"; + /** + * The ID of the asset + */ + id: 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; +} + +export interface DepositFields { + __typename: "Deposit"; + /** + * The Vega internal ID of the deposit + */ + id: string; + /** + * The current status of the deposit + */ + status: DepositStatus; + /** + * The amount to be withdrawn + */ + amount: string; + /** + * The asset to be withdrawn + */ + asset: DepositFields_asset; + /** + * RFC3339Nano time at which the deposit was created + */ + createdTimestamp: string; + /** + * RFC3339Nano time at which the deposit was finalised + */ + creditedTimestamp: string | null; + /** + * Hash of the transaction on the foreign chain + */ + txHash: string | null; +} diff --git a/libs/deposits/src/lib/__generated__/Deposits.ts b/libs/deposits/src/lib/__generated__/Deposits.ts new file mode 100644 index 000000000..0d203133a --- /dev/null +++ b/libs/deposits/src/lib/__generated__/Deposits.ts @@ -0,0 +1,94 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +import { DepositStatus } from "@vegaprotocol/types"; + +// ==================================================== +// GraphQL query operation: Deposits +// ==================================================== + +export interface Deposits_party_depositsConnection_edges_node_asset { + __typename: "Asset"; + /** + * The ID of the asset + */ + id: 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; +} + +export interface Deposits_party_depositsConnection_edges_node { + __typename: "Deposit"; + /** + * The Vega internal ID of the deposit + */ + id: string; + /** + * The current status of the deposit + */ + status: DepositStatus; + /** + * The amount to be withdrawn + */ + amount: string; + /** + * The asset to be withdrawn + */ + asset: Deposits_party_depositsConnection_edges_node_asset; + /** + * RFC3339Nano time at which the deposit was created + */ + createdTimestamp: string; + /** + * RFC3339Nano time at which the deposit was finalised + */ + creditedTimestamp: string | null; + /** + * Hash of the transaction on the foreign chain + */ + txHash: string | null; +} + +export interface Deposits_party_depositsConnection_edges { + __typename: "DepositEdge"; + node: Deposits_party_depositsConnection_edges_node; +} + +export interface Deposits_party_depositsConnection { + __typename: "DepositsConnection"; + /** + * The deposits + */ + edges: (Deposits_party_depositsConnection_edges | null)[] | null; +} + +export interface Deposits_party { + __typename: "Party"; + /** + * Party identifier + */ + id: string; + /** + * The list of all deposits for a party by the party + */ + depositsConnection: Deposits_party_depositsConnection; +} + +export interface Deposits { + /** + * An entity that is trading on the Vega network + */ + party: Deposits_party | null; +} + +export interface DepositsVariables { + partyId: string; +} diff --git a/libs/deposits/src/lib/__generated__/DepositsQuery.ts b/libs/deposits/src/lib/__generated__/DepositsQuery.ts new file mode 100644 index 000000000..23140dd02 --- /dev/null +++ b/libs/deposits/src/lib/__generated__/DepositsQuery.ts @@ -0,0 +1,94 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +import { DepositStatus } from "@vegaprotocol/types"; + +// ==================================================== +// GraphQL query operation: DepositsQuery +// ==================================================== + +export interface DepositsQuery_party_depositsConnection_edges_node_asset { + __typename: "Asset"; + /** + * The ID of the asset + */ + id: 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; +} + +export interface DepositsQuery_party_depositsConnection_edges_node { + __typename: "Deposit"; + /** + * The Vega internal ID of the deposit + */ + id: string; + /** + * The current status of the deposit + */ + status: DepositStatus; + /** + * The amount to be withdrawn + */ + amount: string; + /** + * The asset to be withdrawn + */ + asset: DepositsQuery_party_depositsConnection_edges_node_asset; + /** + * RFC3339Nano time at which the deposit was created + */ + createdTimestamp: string; + /** + * RFC3339Nano time at which the deposit was finalised + */ + creditedTimestamp: string | null; + /** + * Hash of the transaction on the foreign chain + */ + txHash: string | null; +} + +export interface DepositsQuery_party_depositsConnection_edges { + __typename: "DepositEdge"; + node: DepositsQuery_party_depositsConnection_edges_node; +} + +export interface DepositsQuery_party_depositsConnection { + __typename: "DepositsConnection"; + /** + * The deposits + */ + edges: (DepositsQuery_party_depositsConnection_edges | null)[] | null; +} + +export interface DepositsQuery_party { + __typename: "Party"; + /** + * Party identifier + */ + id: string; + /** + * The list of all deposits for a party by the party + */ + depositsConnection: DepositsQuery_party_depositsConnection; +} + +export interface DepositsQuery { + /** + * An entity that is trading on the Vega network + */ + party: DepositsQuery_party | null; +} + +export interface DepositsQueryVariables { + partyId: string; +} diff --git a/libs/deposits/src/lib/__generated___/Deposit.ts b/libs/deposits/src/lib/__generated___/Deposit.ts new file mode 100644 index 000000000..dce3d6cb8 --- /dev/null +++ b/libs/deposits/src/lib/__generated___/Deposit.ts @@ -0,0 +1,49 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +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, txHash?: string | null, status: Types.DepositStatus } | { __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 DepositEventDocument = gql` + subscription DepositEvent($partyId: ID!) { + busEvents(partyId: $partyId, batchSize: 0, types: [Deposit]) { + event { + ... on Deposit { + id + txHash + status + } + } + } +} + `; + +/** + * __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/deposits-table.tsx b/libs/deposits/src/lib/deposits-table.tsx new file mode 100644 index 000000000..907eccc50 --- /dev/null +++ b/libs/deposits/src/lib/deposits-table.tsx @@ -0,0 +1,81 @@ +import { AgGridColumn } from 'ag-grid-react'; +import { + t, + addDecimalsFormatNumber, + getDateTimeFormat, + truncateByChars, +} from '@vegaprotocol/react-helpers'; +import type { + VegaICellRendererParams, + VegaValueFormatterParams, +} from '@vegaprotocol/ui-toolkit'; +import { AgGridDynamic as AgGrid, Link } from '@vegaprotocol/ui-toolkit'; +import type { DepositFields } from './__generated__/DepositFields'; +import { useEnvironment } from '@vegaprotocol/environment'; +import { DepositStatusMapping } from '@vegaprotocol/types'; + +export interface DepositsTableProps { + deposits: DepositFields[]; +} + +export const DepositsTable = ({ deposits }: DepositsTableProps) => { + const { ETHERSCAN_URL } = useEnvironment(); + return ( + + + ) => { + return addDecimalsFormatNumber(value, data.asset.decimals); + }} + /> + ) => { + return getDateTimeFormat().format(new Date(value)); + }} + /> + ) => { + return DepositStatusMapping[value]; + }} + /> + ) => { + if (!value) return '-'; + return ( + + {truncateByChars(value)} + + ); + }} + /> + + ); +}; diff --git a/libs/deposits/src/lib/use-deposits.ts b/libs/deposits/src/lib/use-deposits.ts new file mode 100644 index 000000000..f53ea2783 --- /dev/null +++ b/libs/deposits/src/lib/use-deposits.ts @@ -0,0 +1,153 @@ +import uniqBy from 'lodash/uniqBy'; +import compact from 'lodash/compact'; +import orderBy from 'lodash/orderBy'; +import { gql, useQuery } from '@apollo/client'; +import type { UpdateQueryFn } from '@apollo/client/core/watchQueryOptions'; +import { useVegaWallet } from '@vegaprotocol/wallet'; +import { useEffect, useMemo } from 'react'; +import type { + DepositEventSub, + DepositEventSubVariables, + DepositEventSub_busEvents_event, + DepositEventSub_busEvents_event_Deposit, +} from './__generated__/DepositEventSub'; +import type { Deposits, DepositsVariables } from './__generated__/Deposits'; + +const DEPOSIT_FRAGMENT = gql` + fragment DepositFields on Deposit { + id + status + amount + asset { + id + symbol + decimals + } + createdTimestamp + creditedTimestamp + txHash + } +`; + +const DEPOSITS_QUERY = gql` + ${DEPOSIT_FRAGMENT} + query DepositsQuery($partyId: ID!) { + party(id: $partyId) { + id + depositsConnection { + edges { + node { + ...DepositFields + } + } + } + } + } +`; + +const DEPOSITS_BUS_EVENT_SUB = gql` + ${DEPOSIT_FRAGMENT} + subscription DepositEventSub($partyId: ID!) { + busEvents(partyId: $partyId, batchSize: 0, types: [Deposit]) { + event { + ... on Deposit { + ...DepositFields + } + } + } + } +`; + +export const useDeposits = () => { + const { keypair } = useVegaWallet(); + const { data, loading, error, subscribeToMore } = useQuery< + Deposits, + DepositsVariables + >(DEPOSITS_QUERY, { + variables: { partyId: keypair?.pub || '' }, + skip: !keypair?.pub, + }); + + const deposits = useMemo(() => { + if (!data?.party?.depositsConnection.edges?.length) { + return []; + } + + return orderBy( + compact(data.party?.depositsConnection.edges?.map((d) => d?.node)), + ['createdTimestamp'], + ['desc'] + ); + }, [data]); + + useEffect(() => { + if (!keypair?.pub) return; + + const unsub = subscribeToMore({ + document: DEPOSITS_BUS_EVENT_SUB, + variables: { partyId: keypair?.pub }, + updateQuery, + }); + + return () => { + unsub(); + }; + }, [keypair?.pub, subscribeToMore]); + + return { data, loading, error, deposits }; +}; + +const updateQuery: UpdateQueryFn< + Deposits, + DepositEventSubVariables, + DepositEventSub +> = (prev, { subscriptionData, variables }) => { + console.log(subscriptionData); + if (!subscriptionData.data.busEvents?.length || !variables?.partyId) { + return prev; + } + + const curr = + compact(prev.party?.depositsConnection.edges?.map((e) => e?.node)) || []; + const incoming = subscriptionData.data.busEvents + .map((e) => e.event) + .filter(isDepositEvent); + + const deposits = uniqBy([...incoming, ...curr], 'id'); + + if (!prev.party) { + return { + ...prev, + party: { + __typename: 'Party', + id: variables?.partyId, + depositsConnection: { + __typename: 'DepositsConnection', + edges: deposits.map((d) => ({ __typename: 'DepositEdge', node: d })), + }, + }, + }; + } + + return { + ...prev, + party: { + ...prev.party, + id: variables?.partyId, + depositsConnection: { + __typename: 'DepositsConnection', + edges: deposits.map((d) => ({ __typename: 'DepositEdge', node: d })), + }, + }, + }; +}; + +const isDepositEvent = ( + event: DepositEventSub_busEvents_event +): event is DepositEventSub_busEvents_event_Deposit => { + if (event.__typename === 'Deposit') { + return true; + } + + return false; +}; diff --git a/libs/environment/.eslintrc.json b/libs/environment/.eslintrc.json index db820c5d0..de2a9b877 100644 --- a/libs/environment/.eslintrc.json +++ b/libs/environment/.eslintrc.json @@ -1,6 +1,6 @@ { "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*", "__generated__"], + "ignorePatterns": ["!**/*", "__generated__", "__generated___"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], diff --git a/libs/environment/src/components/network-switcher/network-switcher.tsx b/libs/environment/src/components/network-switcher/network-switcher.tsx index dab2ca844..f933af496 100644 --- a/libs/environment/src/components/network-switcher/network-switcher.tsx +++ b/libs/environment/src/components/network-switcher/network-switcher.tsx @@ -9,6 +9,7 @@ import { } from '@vegaprotocol/ui-toolkit'; import { useEnvironment } from '../../hooks/use-environment'; import { Networks } from '../../types'; +import classNames from 'classnames'; export const envNameMapping: Record = { [Networks.CUSTOM]: t('Custom'), @@ -68,7 +69,7 @@ const NetworkLabel = ({ ); -export const NetworkSwitcher = () => { +export const NetworkSwitcher = ({ theme }: { theme?: 'dark' | 'light' }) => { const { VEGA_ENV, VEGA_NETWORKS } = useEnvironment(); const [isOpen, setOpen] = useState(false); const [isAdvancedView, setAdvancedView] = useState(false); @@ -83,9 +84,14 @@ export const NetworkSwitcher = () => { [setOpen, setAdvancedView] ); + const dropdownTriggerClasses = classNames({ + 'text-black hover:!bg-neutral-300': theme === 'light', + 'text-white hover:!bg-neutral-700': theme === 'dark', + }); + return ( - + {envTriggerMapping[VEGA_ENV]} diff --git a/libs/fills/.eslintrc.json b/libs/fills/.eslintrc.json index db820c5d0..de2a9b877 100644 --- a/libs/fills/.eslintrc.json +++ b/libs/fills/.eslintrc.json @@ -1,6 +1,6 @@ { "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*", "__generated__"], + "ignorePatterns": ["!**/*", "__generated__", "__generated___"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], diff --git a/libs/fills/src/lib/Fills.graphql b/libs/fills/src/lib/Fills.graphql new file mode 100644 index 000000000..4db669bb3 --- /dev/null +++ b/libs/fills/src/lib/Fills.graphql @@ -0,0 +1,72 @@ +fragment FillFields on Trade { + id + createdAt + price + size + buyOrder + sellOrder + aggressor + buyer { + id + } + seller { + id + } + buyerFee { + makerFee + infrastructureFee + liquidityFee + } + sellerFee { + makerFee + infrastructureFee + liquidityFee + } + market { + id + name + decimalPlaces + positionDecimalPlaces + tradableInstrument { + instrument { + id + code + product { + ... on Future { + settlementAsset { + id + symbol + decimals + } + } + } + } + } + } +} + +query Fills($partyId: ID!, $marketId: ID, $pagination: Pagination) { + party(id: $partyId) { + id + tradesConnection(marketId: $marketId, pagination: $pagination) { + edges { + node { + ...FillFields + } + cursor + } + pageInfo { + startCursor + endCursor + hasNextPage + hasPreviousPage + } + } + } +} + +subscription FillsSub($partyId: ID!) { + trades(partyId: $partyId) { + ...FillFields + } +} diff --git a/libs/fills/src/lib/__generated__/FillFields.ts b/libs/fills/src/lib/__generated__/FillFields.ts index 39ea81610..70c685e65 100644 --- a/libs/fills/src/lib/__generated__/FillFields.ts +++ b/libs/fills/src/lib/__generated__/FillFields.ts @@ -91,6 +91,10 @@ export interface FillFields_market_tradableInstrument_instrument { * A short non necessarily unique code used to easily describe the instrument (e.g: FX:BTCUSD/DEC18) (string) */ code: string; + /** + * Full and fairly descriptive name for the instrument + */ + name: string; /** * A reference to or instance of a fully specified product, including all required product parameters for that product (Product union) */ @@ -111,10 +115,6 @@ export interface FillFields_market { * Market ID */ id: string; - /** - * Market full name - */ - name: string; /** * decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct * number denominated in the currency of the market. (uint64) diff --git a/libs/fills/src/lib/__generated__/Fills.ts b/libs/fills/src/lib/__generated__/Fills.ts index 05cc287ca..669b87d12 100644 --- a/libs/fills/src/lib/__generated__/Fills.ts +++ b/libs/fills/src/lib/__generated__/Fills.ts @@ -91,6 +91,10 @@ export interface Fills_party_tradesConnection_edges_node_market_tradableInstrume * A short non necessarily unique code used to easily describe the instrument (e.g: FX:BTCUSD/DEC18) (string) */ code: string; + /** + * Full and fairly descriptive name for the instrument + */ + name: string; /** * A reference to or instance of a fully specified product, including all required product parameters for that product (Product union) */ @@ -111,10 +115,6 @@ export interface Fills_party_tradesConnection_edges_node_market { * Market ID */ id: string; - /** - * Market full name - */ - name: string; /** * decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct * number denominated in the currency of the market. (uint64) diff --git a/libs/fills/src/lib/__generated__/FillsSub.ts b/libs/fills/src/lib/__generated__/FillsSub.ts index 7765a85ed..69651b833 100644 --- a/libs/fills/src/lib/__generated__/FillsSub.ts +++ b/libs/fills/src/lib/__generated__/FillsSub.ts @@ -91,6 +91,10 @@ export interface FillsSub_trades_market_tradableInstrument_instrument { * A short non necessarily unique code used to easily describe the instrument (e.g: FX:BTCUSD/DEC18) (string) */ code: string; + /** + * Full and fairly descriptive name for the instrument + */ + name: string; /** * A reference to or instance of a fully specified product, including all required product parameters for that product (Product union) */ @@ -111,10 +115,6 @@ export interface FillsSub_trades_market { * Market ID */ id: string; - /** - * Market full name - */ - name: string; /** * decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct * number denominated in the currency of the market. (uint64) diff --git a/libs/fills/src/lib/__generated___/Fills.ts b/libs/fills/src/lib/__generated___/Fills.ts new file mode 100644 index 000000000..b0011f312 --- /dev/null +++ b/libs/fills/src/lib/__generated___/Fills.ts @@ -0,0 +1,152 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type FillFieldsFragment = { __typename?: 'Trade', id: string, createdAt: string, price: string, size: string, buyOrder: string, sellOrder: string, aggressor: Types.Side, buyer: { __typename?: 'Party', id: string }, seller: { __typename?: 'Party', id: string }, buyerFee: { __typename?: 'TradeFee', makerFee: string, infrastructureFee: string, liquidityFee: string }, sellerFee: { __typename?: 'TradeFee', makerFee: string, infrastructureFee: string, liquidityFee: string }, market: { __typename?: 'Market', id: string, name: string, decimalPlaces: number, positionDecimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, code: string, product: { __typename?: 'Future', settlementAsset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } } } } } }; + +export type FillsQueryVariables = Types.Exact<{ + partyId: Types.Scalars['ID']; + marketId?: Types.InputMaybe; + pagination?: Types.InputMaybe; +}>; + + +export type FillsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, tradesConnection: { __typename?: 'TradeConnection', edges: Array<{ __typename?: 'TradeEdge', cursor: string, node: { __typename?: 'Trade', id: string, createdAt: string, price: string, size: string, buyOrder: string, sellOrder: string, aggressor: Types.Side, buyer: { __typename?: 'Party', id: string }, seller: { __typename?: 'Party', id: string }, buyerFee: { __typename?: 'TradeFee', makerFee: string, infrastructureFee: string, liquidityFee: string }, sellerFee: { __typename?: 'TradeFee', makerFee: string, infrastructureFee: string, liquidityFee: string }, market: { __typename?: 'Market', id: string, name: string, decimalPlaces: number, positionDecimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, code: string, product: { __typename?: 'Future', settlementAsset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } } } } } } }>, pageInfo: { __typename?: 'PageInfo', startCursor: string, endCursor: string, hasNextPage: boolean, hasPreviousPage: boolean } } } | null }; + +export type FillsSubSubscriptionVariables = Types.Exact<{ + partyId: Types.Scalars['ID']; +}>; + + +export type FillsSubSubscription = { __typename?: 'Subscription', trades?: Array<{ __typename?: 'Trade', id: string, createdAt: string, price: string, size: string, buyOrder: string, sellOrder: string, aggressor: Types.Side, buyer: { __typename?: 'Party', id: string }, seller: { __typename?: 'Party', id: string }, buyerFee: { __typename?: 'TradeFee', makerFee: string, infrastructureFee: string, liquidityFee: string }, sellerFee: { __typename?: 'TradeFee', makerFee: string, infrastructureFee: string, liquidityFee: string }, market: { __typename?: 'Market', id: string, name: string, decimalPlaces: number, positionDecimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, code: string, product: { __typename?: 'Future', settlementAsset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } } } } } }> | null }; + +export const FillFieldsFragmentDoc = gql` + fragment FillFields on Trade { + id + createdAt + price + size + buyOrder + sellOrder + aggressor + buyer { + id + } + seller { + id + } + buyerFee { + makerFee + infrastructureFee + liquidityFee + } + sellerFee { + makerFee + infrastructureFee + liquidityFee + } + market { + id + name + decimalPlaces + positionDecimalPlaces + tradableInstrument { + instrument { + id + code + product { + ... on Future { + settlementAsset { + id + symbol + decimals + } + } + } + } + } + } +} + `; +export const FillsDocument = gql` + query Fills($partyId: ID!, $marketId: ID, $pagination: Pagination) { + party(id: $partyId) { + id + tradesConnection(marketId: $marketId, pagination: $pagination) { + edges { + node { + ...FillFields + } + cursor + } + pageInfo { + startCursor + endCursor + hasNextPage + hasPreviousPage + } + } + } +} + ${FillFieldsFragmentDoc}`; + +/** + * __useFillsQuery__ + * + * To run a query within a React component, call `useFillsQuery` and pass it any options that fit your needs. + * When your component renders, `useFillsQuery` 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 } = useFillsQuery({ + * variables: { + * partyId: // value for 'partyId' + * marketId: // value for 'marketId' + * pagination: // value for 'pagination' + * }, + * }); + */ +export function useFillsQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(FillsDocument, options); + } +export function useFillsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(FillsDocument, options); + } +export type FillsQueryHookResult = ReturnType; +export type FillsLazyQueryHookResult = ReturnType; +export type FillsQueryResult = Apollo.QueryResult; +export const FillsSubDocument = gql` + subscription FillsSub($partyId: ID!) { + trades(partyId: $partyId) { + ...FillFields + } +} + ${FillFieldsFragmentDoc}`; + +/** + * __useFillsSubSubscription__ + * + * To run a query within a React component, call `useFillsSubSubscription` and pass it any options that fit your needs. + * When your component renders, `useFillsSubSubscription` 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 } = useFillsSubSubscription({ + * variables: { + * partyId: // value for 'partyId' + * }, + * }); + */ +export function useFillsSubSubscription(baseOptions: Apollo.SubscriptionHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useSubscription(FillsSubDocument, options); + } +export type FillsSubSubscriptionHookResult = ReturnType; +export type FillsSubSubscriptionResult = Apollo.SubscriptionResult; \ No newline at end of file diff --git a/libs/fills/src/lib/fills-data-provider.ts b/libs/fills/src/lib/fills-data-provider.ts index fe48713aa..0de17da1c 100644 --- a/libs/fills/src/lib/fills-data-provider.ts +++ b/libs/fills/src/lib/fills-data-provider.ts @@ -41,13 +41,13 @@ const FILL_FRAGMENT = gql` } market { id - name decimalPlaces positionDecimalPlaces tradableInstrument { instrument { id code + name product { ... on Future { settlementAsset { diff --git a/libs/fills/src/lib/fills-table.spec.tsx b/libs/fills/src/lib/fills-table.spec.tsx index 8fe0637cc..827bd1661 100644 --- a/libs/fills/src/lib/fills-table.spec.tsx +++ b/libs/fills/src/lib/fills-table.spec.tsx @@ -28,11 +28,11 @@ describe('FillsTable', () => { price: '100', size: '300000', market: { - name: 'test market', decimalPlaces: 2, positionDecimalPlaces: 5, tradableInstrument: { instrument: { + name: 'test market', product: { settlementAsset: { decimals: 2, @@ -87,7 +87,7 @@ describe('FillsTable', () => { const cells = screen.getAllByRole('gridcell'); const expectedValues = [ - buyerFill.market.name, + buyerFill.market.tradableInstrument.instrument.name, '+3.00000', '1.00 BTC', '3.00 BTC', @@ -124,7 +124,7 @@ describe('FillsTable', () => { const cells = screen.getAllByRole('gridcell'); const expectedValues = [ - buyerFill.market.name, + buyerFill.market.tradableInstrument.instrument.name, '+3.00000', '1.00 BTC', '3.00 BTC', @@ -161,7 +161,7 @@ describe('FillsTable', () => { const cells = screen.getAllByRole('gridcell'); const expectedValues = [ - buyerFill.market.name, + buyerFill.market.tradableInstrument.instrument.name, '-3.00000', '1.00 BTC', '3.00 BTC', diff --git a/libs/fills/src/lib/fills-table.tsx b/libs/fills/src/lib/fills-table.tsx index 966d95c4f..70ada7875 100644 --- a/libs/fills/src/lib/fills-table.tsx +++ b/libs/fills/src/lib/fills-table.tsx @@ -44,7 +44,10 @@ export const FillsTable = forwardRef( getRowId={({ data }) => data?.id} {...props} > - + ): Fills => { infrastructureFee: '5000', }, market: { - name: 'Apples Daily v3', + tradableInstrument: { + instrument: { + name: 'Apples Daily v3', + }, + }, positionDecimalPlaces: 2, }, }), @@ -38,7 +42,11 @@ export const generateFills = (override?: PartialDeep): Fills => { id: '3', aggressor: Side.SIDE_SELL, market: { - name: 'ETHBTC Quarterly (30 Jun 2022)', + tradableInstrument: { + instrument: { + name: 'ETHBTC Quarterly (30 Jun 2022)', + }, + }, }, buyer: { id: 'party-id', @@ -108,7 +116,6 @@ export const generateFill = ( market: { __typename: 'Market', id: 'market-id', - name: 'UNIDAI Monthly (30 Jun 2022)', positionDecimalPlaces: 0, decimalPlaces: 5, tradableInstrument: { @@ -117,6 +124,7 @@ export const generateFill = ( __typename: 'Instrument', id: 'instrument-id', code: 'instrument-code', + name: 'UNIDAI Monthly (30 Jun 2022)', product: { __typename: 'Future', settlementAsset: { diff --git a/libs/governance/.eslintrc.json b/libs/governance/.eslintrc.json index db820c5d0..de2a9b877 100644 --- a/libs/governance/.eslintrc.json +++ b/libs/governance/.eslintrc.json @@ -1,6 +1,6 @@ { "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*", "__generated__"], + "ignorePatterns": ["!**/*", "__generated__", "__generated___"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], diff --git a/libs/governance/src/lib/index.ts b/libs/governance/src/lib/index.ts index 8e913b42f..e84c1929e 100644 --- a/libs/governance/src/lib/index.ts +++ b/libs/governance/src/lib/index.ts @@ -1 +1,2 @@ export * from './proposals-hooks'; +export * from './proposals-queries'; diff --git a/libs/governance/src/lib/proposal-form.tsx b/libs/governance/src/lib/proposal-form.tsx new file mode 100644 index 000000000..c63f7b2b4 --- /dev/null +++ b/libs/governance/src/lib/proposal-form.tsx @@ -0,0 +1,84 @@ +import { + Button, + FormGroup, + InputError, + TextArea, +} from '@vegaprotocol/ui-toolkit'; +import { useForm } from 'react-hook-form'; +import { useProposalSubmit } from './proposals-hooks'; +import { + getProposalDialogIcon, + getProposalDialogIntent, + getProposalDialogTitle, +} from '../utils'; +import { t } from '@vegaprotocol/react-helpers'; + +export interface FormFields { + proposalData: string; +} + +export const ProposalForm = () => { + const { + register, + handleSubmit, + formState: { isSubmitting, errors }, + } = useForm(); + const { finalizedProposal, submit, Dialog } = useProposalSubmit(); + + const hasError = Boolean(errors.proposalData?.message); + + const onSubmit = async (fields: FormFields) => { + await submit(JSON.parse(fields.proposalData)); + }; + + return ( +
    + +