diff --git a/.github/workflows/capsule-cypress-manual-trigger.yml b/.github/workflows/capsule-cypress-manual-trigger.yml index 98339188d..6cb2b810d 100644 --- a/.github/workflows/capsule-cypress-manual-trigger.yml +++ b/.github/workflows/capsule-cypress-manual-trigger.yml @@ -78,7 +78,7 @@ jobs: uses: actions/checkout@v2 with: repository: vegaprotocol/vega - ref: v0.54.0 + ref: v0.55.0 token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} path: './vega' diff --git a/.github/workflows/capsule-cypress-night-run.yml b/.github/workflows/capsule-cypress-night-run.yml index befc1ce14..b0ea14659 100644 --- a/.github/workflows/capsule-cypress-night-run.yml +++ b/.github/workflows/capsule-cypress-night-run.yml @@ -62,7 +62,7 @@ jobs: uses: actions/checkout@v2 with: repository: vegaprotocol/vega - ref: v0.54.0 + ref: v0.55.0 token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} path: './vega' 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 be2502964..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'); 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 6665940bd..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()); 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-markets.ts b/apps/console-lite-e2e/src/support/mocks/generate-markets.ts index 18a3cdc42..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 = () => { @@ -880,3 +882,41 @@ export const generateLongListMarkets = (count: number) => { } 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/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/static/src/assets/mainnet-tranches.json b/apps/static/src/assets/mainnet-tranches.json index 6d9246351..e6d2c4442 100644 --- a/apps/static/src/assets/mainnet-tranches.json +++ b/apps/static/src/assets/mainnet-tranches.json @@ -232,7 +232,7 @@ "tranche_end": "2023-12-05T00:00:00.000Z", "total_added": "129999.45", "total_removed": "0", - "locked_amount": "106213.256196636749978685", + "locked_amount": "106157.42863308813035358", "deposits": [ { "amount": "129999.45", @@ -298,7 +298,7 @@ "tranche_end": "2023-09-03T00:00:00.000Z", "total_added": "52600", "total_removed": "0", - "locked_amount": "51120.22803145611028", + "locked_amount": "51086.3139079147652", "deposits": [ { "amount": "2600", @@ -682,7 +682,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "97499.58", "total_removed": "0", - "locked_amount": "47407.5117394524021021252", + "locked_amount": "47352.750100183962108426", "deposits": [ { "amount": "97499.58", @@ -715,7 +715,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "135173.4239508", "total_removed": "0", - "locked_amount": "64797.883982370617886030171276", + "locked_amount": "64723.03427569330008772598952", "deposits": [ { "amount": "135173.4239508", @@ -748,7 +748,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "32499.86", "total_removed": "0", - "locked_amount": "19943.521504849955184182", + "locked_amount": "19920.484228892651852084", "deposits": [ { "amount": "32499.86", @@ -781,7 +781,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "10833.29", "total_removed": "0", - "locked_amount": "6491.422722476852413578", + "locked_amount": "6483.924312701184824618", "deposits": [ { "amount": "10833.29", @@ -889,7 +889,7 @@ "tranche_end": "2022-11-01T00:00:00.000Z", "total_added": "30000", "total_removed": "0", - "locked_amount": "7945.3728864734298", + "locked_amount": "7907.00294384058", "deposits": [ { "amount": "7500", @@ -1006,7 +1006,7 @@ "tranche_end": "2023-06-02T00:00:00.000Z", "total_added": "1939928.38", "total_removed": "479504.6187210477481", - "locked_amount": "1391070.132328404443679426", + "locked_amount": "1389819.353416984256757146", "deposits": [ { "amount": "1852091.69", @@ -1292,7 +1292,7 @@ "tranche_end": "2023-02-01T00:00:00.000Z", "total_added": "42500", "total_removed": "0", - "locked_amount": "32505.94492250402725", + "locked_amount": "32451.587503774155", "deposits": [ { "amount": "12500", @@ -2159,7 +2159,7 @@ "tranche_end": "2022-09-30T00:00:00.000Z", "total_added": "60916.66666633337", "total_removed": "20696.25757434884556896", - "locked_amount": "2613.42189971663007907723962443745", + "locked_amount": "2576.66327604240614178127968391758", "deposits": [ { "amount": "2833.333333", @@ -5892,7 +5892,7 @@ "tranche_id": 11, "tranche_start": "2021-09-03T00:00:00.000Z", "tranche_end": "2022-09-03T00:00:00.000Z", - "total_added": "35960.000000000000000003", + "total_added": "35972.000000000000000003", "total_removed": "17098.49537348884", "locked_amount": "0", "deposits": [ @@ -5916,6 +5916,11 @@ "user": "0x60901F5a6a66BCaD910A97e85373A00996B361f5", "tx": "0xa87cd2caf4f27d7a60443ec952b831b005a809803fc899c4bcc3ca12016299eb" }, + { + "amount": "12", + "user": "0x60901F5a6a66BCaD910A97e85373A00996B361f5", + "tx": "0x056bbadf095fbbee4dc0ccac4431c998c65ad3e714a76844c71bdb0509b0ced5" + }, { "amount": "15", "user": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f", @@ -12543,12 +12548,18 @@ "user": "0x60901F5a6a66BCaD910A97e85373A00996B361f5", "tranche_id": 11, "tx": "0xa87cd2caf4f27d7a60443ec952b831b005a809803fc899c4bcc3ca12016299eb" + }, + { + "amount": "12", + "user": "0x60901F5a6a66BCaD910A97e85373A00996B361f5", + "tranche_id": 11, + "tx": "0x056bbadf095fbbee4dc0ccac4431c998c65ad3e714a76844c71bdb0509b0ced5" } ], "withdrawals": [], - "total_tokens": "2", + "total_tokens": "14", "withdrawn_tokens": "0", - "remaining_tokens": "2" + "remaining_tokens": "14" }, { "address": "0xb4eE687f019A8e48F7087f4b4f8653208B8cc48f", @@ -22475,7 +22486,7 @@ "tranche_end": "2023-06-05T00:00:00.000Z", "total_added": "3732368.4671", "total_removed": "204390.7646836173642", - "locked_amount": "2162091.79893798351430427894", + "locked_amount": "2160169.78722609591911997613", "deposits": [ { "amount": "1998.95815", @@ -23342,8 +23353,8 @@ "tranche_start": "2022-06-05T00:00:00.000Z", "tranche_end": "2023-12-05T00:00:00.000Z", "total_added": "15870102.715470999700000001", - "total_removed": "203258.7850094080512444", - "locked_amount": "12966326.2851132206444730663636805143254933", + "total_removed": "203595.9963255265343694", + "locked_amount": "12959510.9549878156668938206553737397120844", "deposits": [ { "amount": "16249.93", @@ -23877,6 +23888,11 @@ "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", "tx": "0xa2cf8d5f7caa97b4c6804c0bce8003115d61772edf6ab6f8c9b3de503eafd2f5" }, + { + "amount": "337.211316118483125", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0x1e6bd91941381b74b4bec158b2366838830987396925340281bce36d0a75a514" + }, { "amount": "305.8599694076328", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -24466,6 +24482,12 @@ "tranche_id": 2, "tx": "0xa2cf8d5f7caa97b4c6804c0bce8003115d61772edf6ab6f8c9b3de503eafd2f5" }, + { + "amount": "337.211316118483125", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0x1e6bd91941381b74b4bec158b2366838830987396925340281bce36d0a75a514" + }, { "amount": "305.8599694076328", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -24924,8 +24946,8 @@ } ], "total_tokens": "259998.8875", - "withdrawn_tokens": "47344.039530071746", - "remaining_tokens": "212654.847969928254" + "withdrawn_tokens": "47681.250846190229125", + "remaining_tokens": "212317.636653809770875" }, { "address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c", @@ -26470,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": "2764972.018594596729147647", - "locked_amount": "6248984.409351215960935111906418583", + "total_removed": "2765441.081300436948788147", + "locked_amount": "6242692.54009573292258816652086769", "deposits": [ { "amount": "129284.449", @@ -26710,6 +26732,11 @@ "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", "tx": "0x0fb5472a41850ad312926ca6a39df1901579d075b0b8836459e2cd7f96353a8b" }, + { + "amount": "469.0627058402196405", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x6e6546452d57d7d58c5fd0671b8a43c2c6024bf845d085fc3133c6851ab18620" + }, { "amount": "551.363354573845008", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -28817,6 +28844,12 @@ "tranche_id": 3, "tx": "0x0fb5472a41850ad312926ca6a39df1901579d075b0b8836459e2cd7f96353a8b" }, + { + "amount": "469.0627058402196405", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x6e6546452d57d7d58c5fd0671b8a43c2c6024bf845d085fc3133c6851ab18620" + }, { "amount": "551.363354573845008", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -30553,8 +30586,8 @@ } ], "total_tokens": "359123.469575", - "withdrawn_tokens": "205072.37111770255727725", - "remaining_tokens": "154051.09845729744272275" + "withdrawn_tokens": "205541.43382354277691775", + "remaining_tokens": "153582.03575145722308225" }, { "address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB", @@ -31642,7 +31675,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "5778205.3912159303", "total_removed": "1773434.744647395163801354", - "locked_amount": "2152108.130137534146322763792771381", + "locked_amount": "2149622.17454178526100337726730932", "deposits": [ { "amount": "552496.6455", @@ -33095,7 +33128,7 @@ "tranche_end": "2023-06-05T00:00:00.000Z", "total_added": "472355.6199999996", "total_removed": "3216.01601557326", - "locked_amount": "342595.80458534469382288375849824", + "locked_amount": "342291.23586461032793916252257736", "deposits": [ { "amount": "3000", diff --git a/apps/static/src/assets/testnet-tranches.json b/apps/static/src/assets/testnet-tranches.json index ccce8c31d..cef26ae2d 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": "79.60645389396243020007881827118214102", + "locked_amount": "78.95550735667177060007817376966007106", "deposits": [ { "amount": "1000", 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 644f493d3..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 ); @@ -200,7 +202,7 @@ context('Governance flow - with eth and vega wallets connected', function () { }); }); - 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,7 +232,53 @@ context('Governance flow - with eth and vega wallets connected', function () { }); }); - 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 ); @@ -255,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', 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) @@ -275,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 ); @@ -314,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 ); @@ -348,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'); @@ -356,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 ); @@ -385,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') @@ -408,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'); @@ -419,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 ); @@ -448,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') @@ -482,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 ); @@ -507,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'); @@ -520,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'); @@ -537,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 ); @@ -564,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%') @@ -592,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 ); @@ -616,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') @@ -637,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'); @@ -652,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'); }); }); @@ -844,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/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/support/wallet-vega.functions.js b/apps/token-e2e/src/support/wallet-vega.functions.js index 883358645..c25826df1 100644 --- a/apps/token-e2e/src/support/wallet-vega.functions.js +++ b/apps/token-e2e/src/support/wallet-vega.functions.js @@ -7,15 +7,16 @@ 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(`vegawallet version`) + + cy.exec(`vega wallet version`) .its('stdout') .then((output) => { cy.log(output); diff --git a/apps/token/src/routes/governance/components/proposals-list/proposals-list.tsx b/apps/token/src/routes/governance/components/proposals-list/proposals-list.tsx index 10a264121..7336c3df3 100644 --- a/apps/token/src/routes/governance/components/proposals-list/proposals-list.tsx +++ b/apps/token/src/routes/governance/components/proposals-list/proposals-list.tsx @@ -66,7 +66,11 @@ export const ProposalsList = ({ proposals }: ProposalsListProps) => { {t( `The Vega network is governed by the community. View active proposals, vote on them or propose changes to the network.` )}{' '} - + {t(`Find out more about Vega governance`)}

diff --git a/apps/trading-e2e/src/integration/home.cy.ts b/apps/trading-e2e/src/integration/home.cy.ts index 996050767..509b020bf 100644 --- a/apps/trading-e2e/src/integration/home.cy.ts +++ b/apps/trading-e2e/src/integration/home.cy.ts @@ -55,11 +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('@MarketList'); + cy.wait('@Markets'); cy.url().should('eq', Cypress.config().baseUrl + '/markets'); }); }); diff --git a/apps/trading-e2e/src/integration/markets.cy.ts b/apps/trading-e2e/src/integration/markets.cy.ts index afc4ea06f..fada777dc 100644 --- a/apps/trading-e2e/src/integration/markets.cy.ts +++ b/apps/trading-e2e/src/integration/markets.cy.ts @@ -11,7 +11,9 @@ describe('markets table', () => { it('renders markets correctly', () => { cy.visit('/'); cy.wait('@Market'); - cy.wait('@MarketList'); + cy.wait('@Markets'); + cy.wait('@MarketsDataQuery'); + cy.wait('@MarketsCandlesQuery'); cy.get('[data-testid^="market-link-"]') .should('not.be.empty') .and('have.attr', 'href'); @@ -24,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'); @@ -35,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(); @@ -53,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'); 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-markets.ts b/apps/trading-e2e/src/support/mocks/generate-markets.ts index c4724aa7a..f40925d47 100644 --- a/apps/trading-e2e/src/support/mocks/generate-markets.ts +++ b/apps/trading-e2e/src/support/mocks/generate-markets.ts @@ -5,12 +5,17 @@ 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', decimalPlaces: 5, @@ -22,15 +27,6 @@ export const generateMarkets = ( close: '', open: '', }, - candles: [ - { - __typename: 'Candle', - open: '100', - close: '100', - high: '110', - low: '90', - }, - ], fees: { __typename: 'Fees', factors: { @@ -40,20 +36,6 @@ 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: '', @@ -87,15 +69,6 @@ export const generateMarkets = ( close: '', open: '', }, - candles: [ - { - __typename: 'Candle', - open: '100', - close: '100', - high: '110', - low: '90', - }, - ], fees: { __typename: 'Fees', factors: { @@ -105,20 +78,6 @@ 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', @@ -152,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: { @@ -170,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: '', @@ -217,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: { @@ -235,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: '', @@ -272,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/trading.ts b/apps/trading-e2e/src/support/trading.ts index 0b11bfeb1..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'; @@ -31,7 +35,10 @@ export const mockTradingPage = ( }, }) ); - 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/pages/index.page.tsx b/apps/trading/pages/index.page.tsx index 542344bc8..347e2b8ff 100644 --- a/apps/trading/pages/index.page.tsx +++ b/apps/trading/pages/index.page.tsx @@ -1,4 +1,5 @@ -import { useMarketList } from '@vegaprotocol/market-list'; +import { activeMarketsProvider } from '@vegaprotocol/market-list'; +import { useDataProvider } from '@vegaprotocol/react-helpers'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import { useRouter } from 'next/router'; import { useEffect } from 'react'; @@ -8,7 +9,10 @@ export function Index() { const { replace } = useRouter(); // The default market selected in the platform behind the overlay // should be the oldest market that is currently trading in continuous mode(i.e. not in auction). - const { data, error, loading } = useMarketList(); + const { data, error, loading } = useDataProvider({ + dataProvider: activeMarketsProvider, + noUpdate: true, + }); const { riskNoticeDialog, update } = useGlobalStore((store) => ({ riskNoticeDialog: store.riskNoticeDialog, update: store.update, diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-container.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-container.tsx index 62682822f..3282ac731 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-container.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-container.tsx @@ -64,6 +64,7 @@ export const DealTicketContainer = ({ ) ) : ( + {JSON.stringify(data)}

{t('Could not load market')}

)} diff --git a/libs/market-depth/src/lib/__generated__/MarketDepth.ts b/libs/market-depth/src/lib/__generated__/MarketDepth.ts index 7b043223b..7de7f05b6 100644 --- a/libs/market-depth/src/lib/__generated__/MarketDepth.ts +++ b/libs/market-depth/src/lib/__generated__/MarketDepth.ts @@ -3,60 +3,10 @@ // @generated // This file was automatically generated and should not be edited. -import { MarketTradingMode } from "@vegaprotocol/types"; - // ==================================================== // GraphQL query operation: MarketDepth // ==================================================== -export interface MarketDepth_market_data_market { - __typename: "Market"; - /** - * Market ID - */ - id: string; -} - -export interface MarketDepth_market_data { - __typename: "MarketData"; - /** - * the arithmetic average of the best static bid price and best static offer price - */ - staticMidPrice: string; - /** - * what state the market is in (auction, continuous, etc) - */ - marketTradingMode: MarketTradingMode; - /** - * indicative volume if the auction ended now, 0 if not in auction mode - */ - indicativeVolume: string; - /** - * indicative price if the auction ended now, 0 if not in auction mode - */ - indicativePrice: string; - /** - * the highest price level on an order book for buy orders not including pegged orders. - */ - bestStaticBidPrice: string; - /** - * the lowest price level on an order book for offer orders not including pegged orders. - */ - bestStaticOfferPrice: string; - /** - * market ID of the associated mark price - */ - market: MarketDepth_market_data_market; -} - -export interface MarketDepth_market_depth_lastTrade { - __typename: "Trade"; - /** - * The price of the trade (probably initially the passive order price, other determination algorithms are possible though) (uint64) - */ - price: string; -} - export interface MarketDepth_market_depth_sell { __typename: "PriceLevel"; /** @@ -91,10 +41,6 @@ export interface MarketDepth_market_depth_buy { export interface MarketDepth_market_depth { __typename: "MarketDepth"; - /** - * Last trade for the given market (if available) - */ - lastTrade: MarketDepth_market_depth_lastTrade | null; /** * Sell side price levels (if available) */ @@ -115,34 +61,6 @@ export interface MarketDepth_market { * Market ID */ id: 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) - * - * Examples: - * Currency Balance decimalPlaces Real Balance - * GBP 100 0 GBP 100 - * GBP 100 2 GBP 1.00 - * GBP 100 4 GBP 0.01 - * GBP 1 4 GBP 0.0001 ( 0.01p ) - * - * GBX (pence) 100 0 GBP 1.00 (100p ) - * GBX (pence) 100 2 GBP 0.01 ( 1p ) - * GBX (pence) 100 4 GBP 0.0001 ( 0.01p ) - * GBX (pence) 1 4 GBP 0.000001 ( 0.0001p) - */ - decimalPlaces: number; - /** - * positionDecimalPlaces indicates the number of decimal places that an integer must be shifted in order to get a correct size (uint64). - * i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes. - * 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market. - * This sets how big the smallest order / position on the market can be. - */ - positionDecimalPlaces: number; - /** - * marketData for the given market - */ - data: MarketDepth_market_data | null; /** * Current depth on the order book for this market */ diff --git a/libs/market-depth/src/lib/__generated__/MarketDepthSubscription.ts b/libs/market-depth/src/lib/__generated__/MarketDepthSubscription.ts index 456b6cc8c..03de5c765 100644 --- a/libs/market-depth/src/lib/__generated__/MarketDepthSubscription.ts +++ b/libs/market-depth/src/lib/__generated__/MarketDepthSubscription.ts @@ -3,72 +3,11 @@ // @generated // This file was automatically generated and should not be edited. -import { MarketTradingMode } from "@vegaprotocol/types"; - // ==================================================== // GraphQL subscription operation: MarketDepthSubscription // ==================================================== -export interface MarketDepthSubscription_marketDepthUpdate_market_data_market { - __typename: "Market"; - /** - * Market ID - */ - id: string; -} - -export interface MarketDepthSubscription_marketDepthUpdate_market_data { - __typename: "MarketData"; - /** - * the arithmetic average of the best static bid price and best static offer price - */ - staticMidPrice: string; - /** - * what state the market is in (auction, continuous, etc) - */ - marketTradingMode: MarketTradingMode; - /** - * indicative volume if the auction ended now, 0 if not in auction mode - */ - indicativeVolume: string; - /** - * indicative price if the auction ended now, 0 if not in auction mode - */ - indicativePrice: string; - /** - * the highest price level on an order book for buy orders not including pegged orders. - */ - bestStaticBidPrice: string; - /** - * the lowest price level on an order book for offer orders not including pegged orders. - */ - bestStaticOfferPrice: string; - /** - * market ID of the associated mark price - */ - market: MarketDepthSubscription_marketDepthUpdate_market_data_market; -} - -export interface MarketDepthSubscription_marketDepthUpdate_market { - __typename: "Market"; - /** - * Market ID - */ - id: string; - /** - * positionDecimalPlaces indicates the number of decimal places that an integer must be shifted in order to get a correct size (uint64). - * i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes. - * 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market. - * This sets how big the smallest order / position on the market can be. - */ - positionDecimalPlaces: number; - /** - * marketData for the given market - */ - data: MarketDepthSubscription_marketDepthUpdate_market_data | null; -} - -export interface MarketDepthSubscription_marketDepthUpdate_sell { +export interface MarketDepthSubscription_marketsDepthUpdate_sell { __typename: "PriceLevel"; /** * The price of all the orders at this level (uint64) @@ -84,7 +23,7 @@ export interface MarketDepthSubscription_marketDepthUpdate_sell { numberOfOrders: string; } -export interface MarketDepthSubscription_marketDepthUpdate_buy { +export interface MarketDepthSubscription_marketsDepthUpdate_buy { __typename: "PriceLevel"; /** * The price of all the orders at this level (uint64) @@ -100,33 +39,37 @@ export interface MarketDepthSubscription_marketDepthUpdate_buy { numberOfOrders: string; } -export interface MarketDepthSubscription_marketDepthUpdate { - __typename: "MarketDepthUpdate"; +export interface MarketDepthSubscription_marketsDepthUpdate { + __typename: "ObservableMarketDepthUpdate"; /** - * Market + * Market ID */ - market: MarketDepthSubscription_marketDepthUpdate_market; + marketId: string; /** * Sell side price levels (if available) */ - sell: MarketDepthSubscription_marketDepthUpdate_sell[] | null; + sell: MarketDepthSubscription_marketsDepthUpdate_sell[] | null; /** * Buy side price levels (if available) */ - buy: MarketDepthSubscription_marketDepthUpdate_buy[] | null; + buy: MarketDepthSubscription_marketsDepthUpdate_buy[] | null; /** * Sequence number for the current snapshot of the market depth. It is always increasing but not monotonic. */ sequenceNumber: string; + /** + * Sequence number of the last update sent; useful for checking that no updates were missed. + */ + previousSequenceNumber: string; } export interface MarketDepthSubscription { /** * Subscribe to price level market depth updates */ - marketDepthUpdate: MarketDepthSubscription_marketDepthUpdate; + marketsDepthUpdate: MarketDepthSubscription_marketsDepthUpdate[]; } export interface MarketDepthSubscriptionVariables { - marketId: string; + id: string; } diff --git a/libs/market-depth/src/lib/depth-chart.tsx b/libs/market-depth/src/lib/depth-chart.tsx index 8b830b49b..87cd59550 100644 --- a/libs/market-depth/src/lib/depth-chart.tsx +++ b/libs/market-depth/src/lib/depth-chart.tsx @@ -7,7 +7,7 @@ import { ThemeContext, getNumberFormat, } from '@vegaprotocol/react-helpers'; -import dataProvider from './market-depth-data-provider'; +import dataProvider from './market-depth-provider'; import { useCallback, useEffect, @@ -16,7 +16,13 @@ import { useState, useContext, } from 'react'; -import type { MarketDepthSubscription_marketDepthUpdate } from './__generated__/MarketDepthSubscription'; +import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list'; +import type { MarketData } from '@vegaprotocol/market-list'; +import type { + MarketDepthSubscription_marketsDepthUpdate, + MarketDepthSubscription_marketsDepthUpdate_sell, + MarketDepthSubscription_marketsDepthUpdate_buy, +} from './__generated__/MarketDepthSubscription'; import type { DepthChartProps } from 'pennant'; import { parseLevel, updateLevels } from './depth-chart-utils'; @@ -33,46 +39,80 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => { const theme = useContext(ThemeContext); const variables = useMemo(() => ({ marketId }), [marketId]); const [depthData, setDepthData] = useState(null); - const [decimalPlaces, setDecimalPlaces] = useState(0); - const [positionDecimalPlaces, setPositionDecimalPlaces] = useState(0); const dataRef = useRef(null); - const setDepthDataThrottledRef = useRef(throttle(setDepthData, 1000)); + const marketDataRef = useRef(null); + const deltaRef = useRef<{ + sell: MarketDepthSubscription_marketsDepthUpdate_sell[]; + buy: MarketDepthSubscription_marketsDepthUpdate_buy[]; + }>({ + sell: [], + buy: [], + }); - // Apply updates to the table - const update = useCallback( - ({ delta }: { delta: MarketDepthSubscription_marketDepthUpdate }) => { - if (!dataRef.current) { - return false; + const updateDepthData = useRef( + throttle(() => { + if (!dataRef.current || !marketDataRef.current || !market) { + return; } dataRef.current = { ...dataRef.current, - midPrice: delta.market.data?.staticMidPrice - ? formatMidPrice(delta.market.data?.staticMidPrice, decimalPlaces) + midPrice: marketDataRef.current?.staticMidPrice + ? formatMidPrice( + marketDataRef.current?.staticMidPrice, + market.decimalPlaces + ) : undefined, data: { - buy: delta.buy + buy: deltaRef.current.buy ? updateLevels( dataRef.current.data.buy, - delta.buy, - decimalPlaces, - positionDecimalPlaces, + deltaRef.current.buy, + market.decimalPlaces, + market.positionDecimalPlaces, true ) : dataRef.current.data.buy, - sell: delta.sell + sell: deltaRef.current.sell ? updateLevels( dataRef.current.data.sell, - delta.sell, - decimalPlaces, - positionDecimalPlaces + deltaRef.current.sell, + market.decimalPlaces, + market.positionDecimalPlaces ) : dataRef.current.data.sell, }, }; - setDepthDataThrottledRef.current(dataRef.current); + deltaRef.current.buy = []; + deltaRef.current.sell = []; + setDepthData(dataRef.current); + }, 1000) + ); + + // Apply updates to the table + const update = useCallback( + ({ + delta: deltas, + }: { + delta: MarketDepthSubscription_marketsDepthUpdate[]; + }) => { + if (!dataRef.current) { + return false; + } + for (const delta of deltas) { + if (delta.marketId !== marketId) { + continue; + } + if (delta.sell) { + deltaRef.current.sell.push(...delta.sell); + } + if (delta.buy) { + deltaRef.current.buy.push(...delta.buy); + } + updateDepthData.current(); + } return true; }, - [decimalPlaces, positionDecimalPlaces] + [marketId, updateDepthData] ); const { data, error, loading } = useDataProvider({ @@ -81,53 +121,86 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => { variables, }); + const { + data: market, + error: marketError, + loading: marketLoading, + } = useDataProvider({ + dataProvider: marketProvider, + noUpdate: true, + variables, + }); + + const marketDataUpdate = useCallback(({ data }: { data: MarketData }) => { + marketDataRef.current = data; + return true; + }, []); + + const { + data: marketData, + error: marketDataError, + loading: marketDataLoading, + } = useDataProvider({ + dataProvider: marketDataProvider, + update: marketDataUpdate, + variables, + }); + + marketDataRef.current = marketData; + useEffect(() => { + if (!marketData || !market || !data) { + return; + } if (!data) { dataRef.current = null; setDepthData(dataRef.current); return; } dataRef.current = { - midPrice: data.data?.staticMidPrice - ? formatMidPrice(data.data?.staticMidPrice, data.decimalPlaces) + midPrice: marketData.staticMidPrice + ? formatMidPrice(marketData.staticMidPrice, market.decimalPlaces) : undefined, data: { buy: data.depth.buy?.map((priceLevel) => parseLevel( priceLevel, - data.decimalPlaces, - data.positionDecimalPlaces + market.decimalPlaces, + market.positionDecimalPlaces ) ) ?? [], sell: data.depth.sell?.map((priceLevel) => parseLevel( priceLevel, - data.decimalPlaces, - data.positionDecimalPlaces + market.decimalPlaces, + market.positionDecimalPlaces ) ) ?? [], }, }; setDepthData(dataRef.current); - setDecimalPlaces(data.decimalPlaces); - setPositionDecimalPlaces(data.positionDecimalPlaces); - }, [data]); + }, [data, marketData, market]); const volumeFormat = useCallback( (volume: number) => - getNumberFormat(data?.positionDecimalPlaces || 0).format(volume), - [data?.positionDecimalPlaces] + getNumberFormat(market?.positionDecimalPlaces || 0).format(volume), + [market?.positionDecimalPlaces] ); const priceFormat = useCallback( - (price: number) => getNumberFormat(data?.decimalPlaces || 0).format(price), - [data?.decimalPlaces] + (price: number) => + getNumberFormat(market?.decimalPlaces || 0).format(price), + [market?.decimalPlaces] ); return ( - + {depthData && ( = {}; - -const update: Update< - MarketDepth_market, - MarketDepthSubscription_marketDepthUpdate -> = (data, delta, reload) => { - if (delta.market.id !== data.id) { - return data; - } - const sequenceNumber = Number(delta.sequenceNumber); - if (sequenceNumber <= sequenceNumbers[delta.market.id]) { - return data; - } - /* - if (sequenceNumber - 1 !== sequenceNumbers[delta.market.id]) { - sequenceNumbers[delta.market.id] = 0; - reload(); - return; - } - */ - sequenceNumbers[delta.market.id] = sequenceNumber; - const updatedData = { - ...data, - data: delta.market.data, - depth: { ...data.depth }, - }; - if (delta.buy) { - updatedData.depth.buy = updateLevels(data.depth.buy ?? [], delta.buy); - } - if (delta.sell) { - updatedData.depth.sell = updateLevels(data.depth.sell ?? [], delta.sell); - } - return updatedData; -}; - -const getData = (responseData: MarketDepth) => { - if (responseData.market?.id) { - sequenceNumbers[responseData.market.id] = Number( - responseData.market.depth.sequenceNumber - ); - } - return responseData.market; -}; -const getDelta = (subscriptionData: MarketDepthSubscription) => - subscriptionData.marketDepthUpdate; - -export const marketDepthDataProvider = makeDataProvider({ - query: MARKET_DEPTH_QUERY, - subscriptionQuery: MARKET_DEPTH_SUBSCRIPTION_QUERY, - update, - getData, - getDelta, -}); - -export default marketDepthDataProvider; diff --git a/libs/market-depth/src/lib/market-depth-provider.ts b/libs/market-depth/src/lib/market-depth-provider.ts new file mode 100644 index 000000000..2a5c1dcee --- /dev/null +++ b/libs/market-depth/src/lib/market-depth-provider.ts @@ -0,0 +1,111 @@ +import { gql } from '@apollo/client'; +import { makeDataProvider } from '@vegaprotocol/react-helpers'; +import { updateLevels } from './orderbook-data'; +import type { Update } from '@vegaprotocol/react-helpers'; +import type { + MarketDepth, + MarketDepth_market, +} from './__generated__/MarketDepth'; +import type { + MarketDepthSubscription, + MarketDepthSubscription_marketsDepthUpdate, +} from './__generated__/MarketDepthSubscription'; + +const MARKET_DEPTH_QUERY = gql` + query MarketDepth($marketId: ID!) { + market(id: $marketId) { + id + depth { + sell { + price + volume + numberOfOrders + } + buy { + price + volume + numberOfOrders + } + sequenceNumber + } + } + } +`; + +export const MARKET_DEPTH_SUBSCRIPTION_QUERY = gql` + subscription MarketDepthSubscription($marketId: ID!) { + marketsDepthUpdate(marketIds: [$marketId]) { + marketId + sell { + price + volume + numberOfOrders + } + buy { + price + volume + numberOfOrders + } + sequenceNumber + previousSequenceNumber + } + } +`; + +const sequenceNumbers: Record = {}; + +const update: Update< + MarketDepth_market, + MarketDepthSubscription_marketsDepthUpdate[] +> = (data, deltas, reload) => { + for (const delta of deltas) { + if (delta.marketId !== data.id) { + continue; + } + const sequenceNumber = Number(delta.sequenceNumber); + if (sequenceNumber <= sequenceNumbers[delta.marketId]) { + return data; + } + /* + if (sequenceNumber - 1 !== sequenceNumbers[delta.market.id]) { + sequenceNumbers[delta.market.id] = 0; + reload(); + return; + } + */ + sequenceNumbers[delta.marketId] = sequenceNumber; + const updatedData = { + ...data, + depth: { ...data.depth }, + }; + if (delta.buy) { + updatedData.depth.buy = updateLevels(data.depth.buy ?? [], delta.buy); + } + if (delta.sell) { + updatedData.depth.sell = updateLevels(data.depth.sell ?? [], delta.sell); + } + return updatedData; + } + return data; +}; + +const getData = (responseData: MarketDepth) => { + if (responseData.market?.id) { + sequenceNumbers[responseData.market.id] = Number( + responseData.market.depth.sequenceNumber + ); + } + return responseData.market; +}; +const getDelta = (subscriptionData: MarketDepthSubscription) => + subscriptionData.marketsDepthUpdate; + +export const marketDepthProvider = makeDataProvider({ + query: MARKET_DEPTH_QUERY, + subscriptionQuery: MARKET_DEPTH_SUBSCRIPTION_QUERY, + update, + getData, + getDelta, +}); + +export default marketDepthProvider; diff --git a/libs/market-depth/src/lib/orderbook-data.ts b/libs/market-depth/src/lib/orderbook-data.ts index fa515a464..1bb1341e3 100644 --- a/libs/market-depth/src/lib/orderbook-data.ts +++ b/libs/market-depth/src/lib/orderbook-data.ts @@ -1,15 +1,14 @@ import groupBy from 'lodash/groupBy'; import { VolumeType } from '@vegaprotocol/react-helpers'; import { MarketTradingMode } from '@vegaprotocol/types'; +import type { MarketData } from '@vegaprotocol/market-list'; import type { MarketDepth_market_depth_sell, MarketDepth_market_depth_buy, - MarketDepth_market_data, } from './__generated__/MarketDepth'; import type { - MarketDepthSubscription_marketDepthUpdate_sell, - MarketDepthSubscription_marketDepthUpdate_buy, - MarketDepthSubscription_marketDepthUpdate_market_data, + MarketDepthSubscription_marketsDepthUpdate_sell, + MarketDepthSubscription_marketsDepthUpdate_buy, } from './__generated__/MarketDepthSubscription'; export interface CumulativeVol { @@ -33,7 +32,7 @@ export interface OrderbookRowData { type PartialOrderbookRowData = Pick; export type OrderbookData = Partial< - Omit + Omit > & { rows: OrderbookRowData[] | null }; export const getPriceLevel = (price: string | bigint, resolution: number) => { @@ -105,11 +104,13 @@ export const createRow = ( const mapRawData = (dataType: VolumeType.ask | VolumeType.bid) => ( - data: + data: Omit< | MarketDepth_market_depth_sell - | MarketDepthSubscription_marketDepthUpdate_sell + | MarketDepthSubscription_marketsDepthUpdate_sell | MarketDepth_market_depth_buy - | MarketDepthSubscription_marketDepthUpdate_buy + | MarketDepthSubscription_marketsDepthUpdate_buy, + '__typename' + > ): PartialOrderbookRowData => createPartialRow(data.price, Number(data.volume), dataType); @@ -118,16 +119,18 @@ const mapRawData = */ export const compactRows = ( sell: - | ( + | Omit< | MarketDepth_market_depth_sell - | MarketDepthSubscription_marketDepthUpdate_sell - )[] + | MarketDepthSubscription_marketsDepthUpdate_sell, + '__typename' + >[] | null, buy: - | ( + | Omit< | MarketDepth_market_depth_buy - | MarketDepthSubscription_marketDepthUpdate_buy - )[] + | MarketDepthSubscription_marketsDepthUpdate_buy, + '__typename' + >[] | null, resolution: number ) => { @@ -199,8 +202,8 @@ const partiallyUpdateCompactedRows = ( dataType: VolumeType, data: OrderbookRowData[], delta: - | MarketDepthSubscription_marketDepthUpdate_sell - | MarketDepthSubscription_marketDepthUpdate_buy, + | MarketDepthSubscription_marketsDepthUpdate_sell + | MarketDepthSubscription_marketsDepthUpdate_buy, resolution: number, modifiedIndex: number ): [number, OrderbookRowData[]] => { @@ -255,8 +258,8 @@ const partiallyUpdateCompactedRows = ( */ export const updateCompactedRows = ( rows: OrderbookRowData[], - sell: MarketDepthSubscription_marketDepthUpdate_sell[] | null, - buy: MarketDepthSubscription_marketDepthUpdate_buy[] | null, + sell: MarketDepthSubscription_marketsDepthUpdate_sell[] | null, + buy: MarketDepthSubscription_marketsDepthUpdate_buy[] | null, resolution: number ) => { let sellModifiedIndex = -1; @@ -320,10 +323,13 @@ export const updateCompactedRows = ( }; export const mapMarketData = ( - data: - | MarketDepth_market_data - | MarketDepthSubscription_marketDepthUpdate_market_data - | null, + data: Pick< + MarketData, + | 'staticMidPrice' + | 'bestStaticBidPrice' + | 'bestStaticOfferPrice' + | 'indicativePrice' + > | null, resolution: number ) => ({ staticMidPrice: @@ -347,8 +353,8 @@ export const mapMarketData = ( export const updateLevels = ( draft: (MarketDepth_market_depth_buy | MarketDepth_market_depth_sell)[], updates: ( - | MarketDepthSubscription_marketDepthUpdate_buy - | MarketDepthSubscription_marketDepthUpdate_sell + | MarketDepthSubscription_marketsDepthUpdate_buy + | MarketDepthSubscription_marketsDepthUpdate_sell )[] ) => { const levels = [...draft]; @@ -399,41 +405,37 @@ export const generateMockData = ({ }: MockDataGeneratorParams) => { let matrix = new Array(numberOfSellRows).fill(undefined); let price = midPrice + (numberOfSellRows - Math.ceil(overlap / 2) + 1); - const sell: MarketDepth_market_depth_sell[] = matrix.map((row, i) => ({ - __typename: 'PriceLevel', - price: (price -= 1).toString(), - volume: (numberOfSellRows - i + 1).toString(), - numberOfOrders: '', - })); + const sell: Omit[] = matrix.map( + (row, i) => ({ + price: (price -= 1).toString(), + volume: (numberOfSellRows - i + 1).toString(), + numberOfOrders: '', + }) + ); price += overlap; matrix = new Array(numberOfBuyRows).fill(undefined); - const buy: MarketDepth_market_depth_buy[] = matrix.map((row, i) => ({ - __typename: 'PriceLevel', - price: (price -= 1).toString(), - volume: (i + 2).toString(), - numberOfOrders: '', - })); + const buy: Omit[] = matrix.map( + (row, i) => ({ + price: (price -= 1).toString(), + volume: (i + 2).toString(), + numberOfOrders: '', + }) + ); const rows = compactRows(sell, buy, resolution); return { rows, resolution, indicativeVolume: indicativeVolume?.toString(), + marketTradingMode: + overlap > 0 + ? MarketTradingMode.TRADING_MODE_BATCH_AUCTION + : MarketTradingMode.TRADING_MODE_CONTINUOUS, ...mapMarketData( { - __typename: 'MarketData', staticMidPrice: '', - marketTradingMode: - overlap > 0 - ? MarketTradingMode.TRADING_MODE_BATCH_AUCTION - : MarketTradingMode.TRADING_MODE_CONTINUOUS, bestStaticBidPrice: bestStaticBidPrice.toString(), bestStaticOfferPrice: bestStaticOfferPrice.toString(), indicativePrice: indicativePrice?.toString() ?? '', - indicativeVolume: indicativeVolume?.toString() ?? '', - market: { - __typename: 'Market', - id: '', - }, }, resolution ), diff --git a/libs/market-depth/src/lib/orderbook-manager.tsx b/libs/market-depth/src/lib/orderbook-manager.tsx index 0772401cd..e43bd559c 100644 --- a/libs/market-depth/src/lib/orderbook-manager.tsx +++ b/libs/market-depth/src/lib/orderbook-manager.tsx @@ -2,9 +2,15 @@ import throttle from 'lodash/throttle'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import { Orderbook } from './orderbook'; import { useDataProvider } from '@vegaprotocol/react-helpers'; -import dataProvider from './market-depth-data-provider'; +import marketDepthProvider from './market-depth-provider'; +import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list'; +import type { MarketData } from '@vegaprotocol/market-list'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import type { MarketDepthSubscription_marketDepthUpdate } from './__generated__/MarketDepthSubscription'; +import type { + MarketDepthSubscription_marketsDepthUpdate, + MarketDepthSubscription_marketsDepthUpdate_sell, + MarketDepthSubscription_marketsDepthUpdate_buy, +} from './__generated__/MarketDepthSubscription'; import { compactRows, updateCompactedRows, @@ -24,82 +30,116 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => { rows: null, }); const dataRef = useRef({ rows: null }); - const deltaRef = useRef(); + const marketDataRef = useRef(null); + const deltaRef = useRef<{ + sell: MarketDepthSubscription_marketsDepthUpdate_sell[]; + buy: MarketDepthSubscription_marketsDepthUpdate_buy[]; + }>({ + sell: [], + buy: [], + }); const updateOrderbookData = useRef( throttle(() => { - if (!deltaRef.current) { - return; - } dataRef.current = { - ...deltaRef.current.market.data, - ...mapMarketData(deltaRef.current.market.data, resolutionRef.current), - rows: updateCompactedRows( - dataRef.current.rows ?? [], - deltaRef.current.sell, - deltaRef.current.buy, - resolutionRef.current - ), + ...marketDataRef.current, + ...mapMarketData(marketDataRef.current, resolutionRef.current), + rows: + deltaRef.current.buy.length || deltaRef.current.sell.length + ? updateCompactedRows( + dataRef.current.rows ?? [], + deltaRef.current.sell, + deltaRef.current.buy, + resolutionRef.current + ) + : dataRef.current.rows, }; - deltaRef.current = undefined; + deltaRef.current.buy = []; + deltaRef.current.sell = []; setOrderbookData(dataRef.current); }, 1000) ); const update = useCallback( - ({ delta }: { delta: MarketDepthSubscription_marketDepthUpdate }) => { + ({ + delta: deltas, + }: { + delta: MarketDepthSubscription_marketsDepthUpdate[]; + }) => { if (!dataRef.current.rows) { return false; } - if (deltaRef.current) { - deltaRef.current.market = delta.market; + for (const delta of deltas) { + if (delta.marketId !== marketId) { + continue; + } if (delta.sell) { - if (deltaRef.current.sell) { - deltaRef.current.sell.push(...delta.sell); - } else { - deltaRef.current.sell = delta.sell; - } + deltaRef.current.sell.push(...delta.sell); } if (delta.buy) { - if (deltaRef.current.buy) { - deltaRef.current.buy.push(...delta.buy); - } else { - deltaRef.current.buy = delta.buy; - } + deltaRef.current.buy.push(...delta.buy); } - } else { - deltaRef.current = delta; + updateOrderbookData.current(); } - updateOrderbookData.current(); return true; }, - // using resolutionRef.current to avoid using resolution as a dependency - it will cause data provider restart on resolution change - [] + [marketId, updateOrderbookData] ); const { data, error, loading, flush } = useDataProvider({ - dataProvider, + dataProvider: marketDepthProvider, update, variables, }); + const { + data: market, + error: marketError, + loading: marketLoading, + } = useDataProvider({ + dataProvider: marketProvider, + noUpdate: true, + variables, + }); + + const marketDataUpdate = useCallback(({ data }: { data: MarketData }) => { + marketDataRef.current = data; + updateOrderbookData.current(); + return true; + }, []); + + const { + data: marketData, + error: marketDataError, + loading: marketDataLoading, + } = useDataProvider({ + dataProvider: marketDataProvider, + update: marketDataUpdate, + variables, + }); + + marketDataRef.current = marketData; + useEffect(() => { const throttleRunnner = updateOrderbookData.current; + if (!marketDataRef.current) { + return; + } if (!data) { dataRef.current = { rows: null }; setOrderbookData(dataRef.current); return; } dataRef.current = { - ...data.data, + ...marketDataRef.current, + ...mapMarketData(marketDataRef.current, resolution), rows: compactRows(data.depth.sell, data.depth.buy, resolution), - ...mapMarketData(data.data, resolution), }; setOrderbookData(dataRef.current); return () => { throttleRunnner.cancel(); }; - }, [data, resolution]); + }, [data, marketData, resolution]); useEffect(() => { resolutionRef.current = resolution; @@ -107,11 +147,15 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => { }, [resolution, flush]); return ( - + setResolution(resolution)} /> diff --git a/libs/market-depth/src/lib/use-orderbook-data.ts b/libs/market-depth/src/lib/use-orderbook-data.ts index ace259830..c4a007f59 100644 --- a/libs/market-depth/src/lib/use-orderbook-data.ts +++ b/libs/market-depth/src/lib/use-orderbook-data.ts @@ -1,8 +1,8 @@ import { useCallback, useEffect, useRef, useState } from 'react'; import throttle from 'lodash/throttle'; import { useDataProvider } from '@vegaprotocol/react-helpers'; -import dataProvider from './market-depth-data-provider'; -import type { MarketDepth_market } from './'; +import dataProvider from './market-depth-provider'; +import type { MarketDepth_market } from './__generated__/MarketDepth'; interface Props { variables: { marketId: string }; diff --git a/libs/market-list/src/lib/MarketData.graphql b/libs/market-list/src/lib/MarketData.graphql deleted file mode 100644 index 5bc5f9906..000000000 --- a/libs/market-list/src/lib/MarketData.graphql +++ /dev/null @@ -1,75 +0,0 @@ -fragment MarketDataFields on MarketData { - market { - id - state - tradingMode - } - bestBidPrice - bestOfferPrice - markPrice - trigger - indicativeVolume -} - -query MarketList($interval: Interval!, $since: String!) { - markets { - id - name - decimalPlaces - positionDecimalPlaces - state - tradingMode - fees { - factors { - makerFee - infrastructureFee - liquidityFee - } - } - data { - market { - id - state - tradingMode - } - bestBidPrice - bestOfferPrice - markPrice - trigger - indicativeVolume - } - tradableInstrument { - instrument { - id - name - code - metadata { - tags - } - product { - ... on Future { - settlementAsset { - symbol - } - } - } - } - } - marketTimestamps { - open - close - } - candles(interval: $interval, since: $since) { - open - close - high - low - } - } -} - -subscription MarketDataSub { - marketData { - ...MarketDataFields - } -} diff --git a/libs/market-list/src/lib/__generated__/MarketCandlesQuery.ts b/libs/market-list/src/lib/__generated__/MarketCandlesQuery.ts new file mode 100644 index 000000000..070d3e591 --- /dev/null +++ b/libs/market-list/src/lib/__generated__/MarketCandlesQuery.ts @@ -0,0 +1,78 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +import { Interval } from "@vegaprotocol/types"; + +// ==================================================== +// GraphQL query operation: MarketCandlesQuery +// ==================================================== + +export interface MarketCandlesQuery_marketsConnection_edges_node_candlesConnection_edges_node { + __typename: "CandleNode"; + /** + * High price (uint64) + */ + high: string; + /** + * Low price (uint64) + */ + low: string; + /** + * Open price (uint64) + */ + open: string; + /** + * Close price (uint64) + */ + close: string; + /** + * Volume price (uint64) + */ + volume: string; +} + +export interface MarketCandlesQuery_marketsConnection_edges_node_candlesConnection_edges { + __typename: "CandleEdge"; + node: MarketCandlesQuery_marketsConnection_edges_node_candlesConnection_edges_node; +} + +export interface MarketCandlesQuery_marketsConnection_edges_node_candlesConnection { + __typename: "CandleDataConnection"; + /** + * The candles + */ + edges: (MarketCandlesQuery_marketsConnection_edges_node_candlesConnection_edges | null)[] | null; +} + +export interface MarketCandlesQuery_marketsConnection_edges_node { + __typename: "Market"; + /** + * Candles on a market, for the 'last' n candles, at 'interval' seconds as specified by parameters using cursor based pagination + */ + candlesConnection: MarketCandlesQuery_marketsConnection_edges_node_candlesConnection; +} + +export interface MarketCandlesQuery_marketsConnection_edges { + __typename: "MarketEdge"; + node: MarketCandlesQuery_marketsConnection_edges_node; +} + +export interface MarketCandlesQuery_marketsConnection { + __typename: "MarketConnection"; + /** + * The markets in this connection + */ + edges: MarketCandlesQuery_marketsConnection_edges[]; +} + +export interface MarketCandlesQuery { + marketsConnection: MarketCandlesQuery_marketsConnection; +} + +export interface MarketCandlesQueryVariables { + interval: Interval; + since: string; + marketId: string; +} diff --git a/libs/market-list/src/lib/__generated__/MarketCandlesSub.ts b/libs/market-list/src/lib/__generated__/MarketCandlesSub.ts new file mode 100644 index 000000000..c5a5a4738 --- /dev/null +++ b/libs/market-list/src/lib/__generated__/MarketCandlesSub.ts @@ -0,0 +1,46 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +import { Interval } from "@vegaprotocol/types"; + +// ==================================================== +// GraphQL subscription operation: MarketCandlesSub +// ==================================================== + +export interface MarketCandlesSub_candles { + __typename: "Candle"; + /** + * High price (uint64) + */ + high: string; + /** + * Low price (uint64) + */ + low: string; + /** + * Open price (uint64) + */ + open: string; + /** + * Close price (uint64) + */ + close: string; + /** + * Volume price (uint64) + */ + volume: string; +} + +export interface MarketCandlesSub { + /** + * Subscribe to the candles updates + */ + candles: MarketCandlesSub_candles; +} + +export interface MarketCandlesSubVariables { + marketId: string; + interval: Interval; +} diff --git a/libs/market-list/src/lib/__generated__/MarketDataFields.ts b/libs/market-list/src/lib/__generated__/MarketDataFields.ts index 44cdd10ac..d31d4b3c2 100644 --- a/libs/market-list/src/lib/__generated__/MarketDataFields.ts +++ b/libs/market-list/src/lib/__generated__/MarketDataFields.ts @@ -3,7 +3,7 @@ // @generated // This file was automatically generated and should not be edited. -import { MarketState, MarketTradingMode, AuctionTrigger } from "@vegaprotocol/types"; +import { AuctionTrigger, MarketTradingMode } from "@vegaprotocol/types"; // ==================================================== // GraphQL fragment: MarketDataFields @@ -15,20 +15,12 @@ export interface MarketDataFields_market { * Market ID */ id: string; - /** - * Current state of the market - */ - state: MarketState; - /** - * Current mode of execution of the market - */ - tradingMode: MarketTradingMode; } export interface MarketDataFields { __typename: "MarketData"; /** - * market ID of the associated mark price + * market of the associated mark price */ market: MarketDataFields_market; /** @@ -47,8 +39,28 @@ export interface MarketDataFields { * what triggered an auction (if an auction was started) */ trigger: AuctionTrigger; + /** + * the arithmetic average of the best static bid price and best static offer price + */ + staticMidPrice: string; + /** + * what state the market is in (auction, continuous, etc) + */ + marketTradingMode: MarketTradingMode; /** * indicative volume if the auction ended now, 0 if not in auction mode */ indicativeVolume: string; + /** + * indicative price if the auction ended now, 0 if not in auction mode + */ + indicativePrice: string; + /** + * the highest price level on an order book for buy orders not including pegged orders. + */ + bestStaticBidPrice: string; + /** + * the lowest price level on an order book for offer orders not including pegged orders. + */ + bestStaticOfferPrice: string; } diff --git a/libs/market-list/src/lib/__generated__/MarketDataQuery.ts b/libs/market-list/src/lib/__generated__/MarketDataQuery.ts new file mode 100644 index 000000000..67b13d022 --- /dev/null +++ b/libs/market-list/src/lib/__generated__/MarketDataQuery.ts @@ -0,0 +1,95 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +import { AuctionTrigger, MarketTradingMode } from "@vegaprotocol/types"; + +// ==================================================== +// GraphQL query operation: MarketDataQuery +// ==================================================== + +export interface MarketDataQuery_marketsConnection_edges_node_data_market { + __typename: "Market"; + /** + * Market ID + */ + id: string; +} + +export interface MarketDataQuery_marketsConnection_edges_node_data { + __typename: "MarketData"; + /** + * market of the associated mark price + */ + market: MarketDataQuery_marketsConnection_edges_node_data_market; + /** + * the highest price level on an order book for buy orders. + */ + bestBidPrice: string; + /** + * the lowest price level on an order book for offer orders. + */ + bestOfferPrice: string; + /** + * the mark price (an unsigned integer) + */ + markPrice: string; + /** + * what triggered an auction (if an auction was started) + */ + trigger: AuctionTrigger; + /** + * the arithmetic average of the best static bid price and best static offer price + */ + staticMidPrice: string; + /** + * what state the market is in (auction, continuous, etc) + */ + marketTradingMode: MarketTradingMode; + /** + * indicative volume if the auction ended now, 0 if not in auction mode + */ + indicativeVolume: string; + /** + * indicative price if the auction ended now, 0 if not in auction mode + */ + indicativePrice: string; + /** + * the highest price level on an order book for buy orders not including pegged orders. + */ + bestStaticBidPrice: string; + /** + * the lowest price level on an order book for offer orders not including pegged orders. + */ + bestStaticOfferPrice: string; +} + +export interface MarketDataQuery_marketsConnection_edges_node { + __typename: "Market"; + /** + * marketData for the given market + */ + data: MarketDataQuery_marketsConnection_edges_node_data | null; +} + +export interface MarketDataQuery_marketsConnection_edges { + __typename: "MarketEdge"; + node: MarketDataQuery_marketsConnection_edges_node; +} + +export interface MarketDataQuery_marketsConnection { + __typename: "MarketConnection"; + /** + * The markets in this connection + */ + edges: MarketDataQuery_marketsConnection_edges[]; +} + +export interface MarketDataQuery { + marketsConnection: MarketDataQuery_marketsConnection; +} + +export interface MarketDataQueryVariables { + id: string; +} diff --git a/libs/market-list/src/lib/__generated__/MarketDataSub.ts b/libs/market-list/src/lib/__generated__/MarketDataSub.ts index c77181ea3..bb78f4ae2 100644 --- a/libs/market-list/src/lib/__generated__/MarketDataSub.ts +++ b/libs/market-list/src/lib/__generated__/MarketDataSub.ts @@ -3,34 +3,18 @@ // @generated // This file was automatically generated and should not be edited. -import { MarketState, MarketTradingMode, AuctionTrigger } from "@vegaprotocol/types"; +import { AuctionTrigger, MarketTradingMode } from "@vegaprotocol/types"; // ==================================================== // GraphQL subscription operation: MarketDataSub // ==================================================== -export interface MarketDataSub_marketData_market { - __typename: "Market"; - /** - * Market ID - */ - id: string; - /** - * Current state of the market - */ - state: MarketState; - /** - * Current mode of execution of the market - */ - tradingMode: MarketTradingMode; -} - -export interface MarketDataSub_marketData { - __typename: "MarketData"; +export interface MarketDataSub_marketsData { + __typename: "ObservableMarketData"; /** * market ID of the associated mark price */ - market: MarketDataSub_marketData_market; + marketId: string; /** * the highest price level on an order book for buy orders. */ @@ -47,15 +31,39 @@ export interface MarketDataSub_marketData { * what triggered an auction (if an auction was started) */ trigger: AuctionTrigger; + /** + * the arithmetic average of the best static bid price and best static offer price + */ + staticMidPrice: string; + /** + * what state the market is in (auction, continuous etc) + */ + marketTradingMode: MarketTradingMode; /** * indicative volume if the auction ended now, 0 if not in auction mode */ indicativeVolume: string; + /** + * indicative price if the auction ended now, 0 if not in auction mode + */ + indicativePrice: string; + /** + * the highest price level on an order book for buy orders not including pegged orders. + */ + bestStaticBidPrice: string; + /** + * the lowest price level on an order book for offer orders not including pegged orders + */ + bestStaticOfferPrice: string; } export interface MarketDataSub { /** * Subscribe to the mark price changes */ - marketData: MarketDataSub_marketData; + marketsData: MarketDataSub_marketsData[]; +} + +export interface MarketDataSubVariables { + id: string; } diff --git a/libs/market-list/src/lib/__generated__/MarketFields.ts b/libs/market-list/src/lib/__generated__/MarketFields.ts new file mode 100644 index 000000000..29c9cca7e --- /dev/null +++ b/libs/market-list/src/lib/__generated__/MarketFields.ts @@ -0,0 +1,154 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +import { MarketState, MarketTradingMode } from "@vegaprotocol/types"; + +// ==================================================== +// GraphQL fragment: MarketFields +// ==================================================== + +export interface MarketFields_fees_factors { + __typename: "FeeFactors"; + /** + * The factor applied to calculate MakerFees, a non-negative float + */ + makerFee: string; + /** + * The factor applied to calculate InfrastructureFees, a non-negative float + */ + infrastructureFee: string; + /** + * The factor applied to calculate LiquidityFees, a non-negative float + */ + liquidityFee: string; +} + +export interface MarketFields_fees { + __typename: "Fees"; + /** + * The factors used to calculate the different fees + */ + factors: MarketFields_fees_factors; +} + +export interface MarketFields_tradableInstrument_instrument_metadata { + __typename: "InstrumentMetadata"; + /** + * An arbitrary list of tags to associated to associate to the Instrument (string list) + */ + tags: string[] | null; +} + +export interface MarketFields_tradableInstrument_instrument_product_settlementAsset { + __typename: "Asset"; + /** + * The symbol of the asset (e.g: GBP) + */ + symbol: string; +} + +export interface MarketFields_tradableInstrument_instrument_product { + __typename: "Future"; + /** + * The name of the asset (string) + */ + settlementAsset: MarketFields_tradableInstrument_instrument_product_settlementAsset; +} + +export interface MarketFields_tradableInstrument_instrument { + __typename: "Instrument"; + /** + * Uniquely identify an instrument across all instruments available on Vega (string) + */ + id: string; + /** + * Full and fairly descriptive name for the instrument + */ + name: string; + /** + * A short non necessarily unique code used to easily describe the instrument (e.g: FX:BTCUSD/DEC18) (string) + */ + code: string; + /** + * Metadata for this instrument + */ + metadata: MarketFields_tradableInstrument_instrument_metadata; + /** + * A reference to or instance of a fully specified product, including all required product parameters for that product (Product union) + */ + product: MarketFields_tradableInstrument_instrument_product; +} + +export interface MarketFields_tradableInstrument { + __typename: "TradableInstrument"; + /** + * An instance of, or reference to, a fully specified instrument. + */ + instrument: MarketFields_tradableInstrument_instrument; +} + +export interface MarketFields_marketTimestamps { + __typename: "MarketTimestamps"; + /** + * Time when the market is open and ready to accept trades + */ + open: string | null; + /** + * Time when the market is closed + */ + close: string | null; +} + +export interface MarketFields { + __typename: "Market"; + /** + * Market ID + */ + id: 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) + * + * Examples: + * Currency Balance decimalPlaces Real Balance + * GBP 100 0 GBP 100 + * GBP 100 2 GBP 1.00 + * GBP 100 4 GBP 0.01 + * GBP 1 4 GBP 0.0001 ( 0.01p ) + * + * GBX (pence) 100 0 GBP 1.00 (100p ) + * GBX (pence) 100 2 GBP 0.01 ( 1p ) + * GBX (pence) 100 4 GBP 0.0001 ( 0.01p ) + * GBX (pence) 1 4 GBP 0.000001 ( 0.0001p) + */ + decimalPlaces: number; + /** + * positionDecimalPlaces indicates the number of decimal places that an integer must be shifted in order to get a correct size (uint64). + * i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes. + * 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market. + * This sets how big the smallest order / position on the market can be. + */ + positionDecimalPlaces: number; + /** + * Current state of the market + */ + state: MarketState; + /** + * Current mode of execution of the market + */ + tradingMode: MarketTradingMode; + /** + * Fees related data + */ + fees: MarketFields_fees; + /** + * An instance of, or reference to, a tradable instrument. + */ + tradableInstrument: MarketFields_tradableInstrument; + /** + * timestamps for state changes in the market + */ + marketTimestamps: MarketFields_marketTimestamps; +} diff --git a/libs/market-list/src/lib/__generated__/MarketList.ts b/libs/market-list/src/lib/__generated__/Markets.ts similarity index 55% rename from libs/market-list/src/lib/__generated__/MarketList.ts rename to libs/market-list/src/lib/__generated__/Markets.ts index f147b3498..c155703fa 100644 --- a/libs/market-list/src/lib/__generated__/MarketList.ts +++ b/libs/market-list/src/lib/__generated__/Markets.ts @@ -3,13 +3,13 @@ // @generated // This file was automatically generated and should not be edited. -import { Interval, MarketState, MarketTradingMode, AuctionTrigger } from "@vegaprotocol/types"; +import { MarketState, MarketTradingMode } from "@vegaprotocol/types"; // ==================================================== -// GraphQL query operation: MarketList +// GraphQL query operation: Markets // ==================================================== -export interface MarketList_markets_fees_factors { +export interface Markets_marketsConnection_edges_node_fees_factors { __typename: "FeeFactors"; /** * The factor applied to calculate MakerFees, a non-negative float @@ -25,59 +25,15 @@ export interface MarketList_markets_fees_factors { liquidityFee: string; } -export interface MarketList_markets_fees { +export interface Markets_marketsConnection_edges_node_fees { __typename: "Fees"; /** * The factors used to calculate the different fees */ - factors: MarketList_markets_fees_factors; + factors: Markets_marketsConnection_edges_node_fees_factors; } -export interface MarketList_markets_data_market { - __typename: "Market"; - /** - * Market ID - */ - id: string; - /** - * Current state of the market - */ - state: MarketState; - /** - * Current mode of execution of the market - */ - tradingMode: MarketTradingMode; -} - -export interface MarketList_markets_data { - __typename: "MarketData"; - /** - * market ID of the associated mark price - */ - market: MarketList_markets_data_market; - /** - * the highest price level on an order book for buy orders. - */ - bestBidPrice: string; - /** - * the lowest price level on an order book for offer orders. - */ - bestOfferPrice: string; - /** - * the mark price (an unsigned integer) - */ - markPrice: string; - /** - * what triggered an auction (if an auction was started) - */ - trigger: AuctionTrigger; - /** - * indicative volume if the auction ended now, 0 if not in auction mode - */ - indicativeVolume: string; -} - -export interface MarketList_markets_tradableInstrument_instrument_metadata { +export interface Markets_marketsConnection_edges_node_tradableInstrument_instrument_metadata { __typename: "InstrumentMetadata"; /** * An arbitrary list of tags to associated to associate to the Instrument (string list) @@ -85,7 +41,7 @@ export interface MarketList_markets_tradableInstrument_instrument_metadata { tags: string[] | null; } -export interface MarketList_markets_tradableInstrument_instrument_product_settlementAsset { +export interface Markets_marketsConnection_edges_node_tradableInstrument_instrument_product_settlementAsset { __typename: "Asset"; /** * The symbol of the asset (e.g: GBP) @@ -93,15 +49,15 @@ export interface MarketList_markets_tradableInstrument_instrument_product_settle symbol: string; } -export interface MarketList_markets_tradableInstrument_instrument_product { +export interface Markets_marketsConnection_edges_node_tradableInstrument_instrument_product { __typename: "Future"; /** * The name of the asset (string) */ - settlementAsset: MarketList_markets_tradableInstrument_instrument_product_settlementAsset; + settlementAsset: Markets_marketsConnection_edges_node_tradableInstrument_instrument_product_settlementAsset; } -export interface MarketList_markets_tradableInstrument_instrument { +export interface Markets_marketsConnection_edges_node_tradableInstrument_instrument { __typename: "Instrument"; /** * Uniquely identify an instrument across all instruments available on Vega (string) @@ -118,22 +74,22 @@ export interface MarketList_markets_tradableInstrument_instrument { /** * Metadata for this instrument */ - metadata: MarketList_markets_tradableInstrument_instrument_metadata; + metadata: Markets_marketsConnection_edges_node_tradableInstrument_instrument_metadata; /** * A reference to or instance of a fully specified product, including all required product parameters for that product (Product union) */ - product: MarketList_markets_tradableInstrument_instrument_product; + product: Markets_marketsConnection_edges_node_tradableInstrument_instrument_product; } -export interface MarketList_markets_tradableInstrument { +export interface Markets_marketsConnection_edges_node_tradableInstrument { __typename: "TradableInstrument"; /** * An instance of, or reference to, a fully specified instrument. */ - instrument: MarketList_markets_tradableInstrument_instrument; + instrument: Markets_marketsConnection_edges_node_tradableInstrument_instrument; } -export interface MarketList_markets_marketTimestamps { +export interface Markets_marketsConnection_edges_node_marketTimestamps { __typename: "MarketTimestamps"; /** * Time when the market is open and ready to accept trades @@ -145,27 +101,7 @@ export interface MarketList_markets_marketTimestamps { close: string | null; } -export interface MarketList_markets_candles { - __typename: "Candle"; - /** - * Open price (uint64) - */ - open: string; - /** - * Close price (uint64) - */ - close: string; - /** - * High price (uint64) - */ - high: string; - /** - * Low price (uint64) - */ - low: string; -} - -export interface MarketList_markets { +export interface Markets_marketsConnection_edges_node { __typename: "Market"; /** * Market ID @@ -206,33 +142,30 @@ export interface MarketList_markets { /** * Fees related data */ - fees: MarketList_markets_fees; - /** - * marketData for the given market - */ - data: MarketList_markets_data | null; + fees: Markets_marketsConnection_edges_node_fees; /** * An instance of, or reference to, a tradable instrument. */ - tradableInstrument: MarketList_markets_tradableInstrument; + tradableInstrument: Markets_marketsConnection_edges_node_tradableInstrument; /** * timestamps for state changes in the market */ - marketTimestamps: MarketList_markets_marketTimestamps; - /** - * Candles on a market, for the 'last' n candles, at 'interval' seconds as specified by parameters - */ - candles: (MarketList_markets_candles | null)[] | null; + marketTimestamps: Markets_marketsConnection_edges_node_marketTimestamps; } -export interface MarketList { - /** - * One or more instruments that are trading on the VEGA network - */ - markets: MarketList_markets[] | null; +export interface Markets_marketsConnection_edges { + __typename: "MarketEdge"; + node: Markets_marketsConnection_edges_node; } -export interface MarketListVariables { - interval: Interval; - since: string; +export interface Markets_marketsConnection { + __typename: "MarketConnection"; + /** + * The markets in this connection + */ + edges: Markets_marketsConnection_edges[]; +} + +export interface Markets { + marketsConnection: Markets_marketsConnection; } diff --git a/libs/market-list/src/lib/__generated__/MarketsCandlesQuery.ts b/libs/market-list/src/lib/__generated__/MarketsCandlesQuery.ts new file mode 100644 index 000000000..03eb6cc86 --- /dev/null +++ b/libs/market-list/src/lib/__generated__/MarketsCandlesQuery.ts @@ -0,0 +1,81 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +import { Interval } from "@vegaprotocol/types"; + +// ==================================================== +// GraphQL query operation: MarketsCandlesQuery +// ==================================================== + +export interface MarketsCandlesQuery_marketsConnection_edges_node_candlesConnection_edges_node { + __typename: "CandleNode"; + /** + * High price (uint64) + */ + high: string; + /** + * Low price (uint64) + */ + low: string; + /** + * Open price (uint64) + */ + open: string; + /** + * Close price (uint64) + */ + close: string; + /** + * Volume price (uint64) + */ + volume: string; +} + +export interface MarketsCandlesQuery_marketsConnection_edges_node_candlesConnection_edges { + __typename: "CandleEdge"; + node: MarketsCandlesQuery_marketsConnection_edges_node_candlesConnection_edges_node; +} + +export interface MarketsCandlesQuery_marketsConnection_edges_node_candlesConnection { + __typename: "CandleDataConnection"; + /** + * The candles + */ + edges: (MarketsCandlesQuery_marketsConnection_edges_node_candlesConnection_edges | null)[] | null; +} + +export interface MarketsCandlesQuery_marketsConnection_edges_node { + __typename: "Market"; + /** + * Market ID + */ + id: string; + /** + * Candles on a market, for the 'last' n candles, at 'interval' seconds as specified by parameters using cursor based pagination + */ + candlesConnection: MarketsCandlesQuery_marketsConnection_edges_node_candlesConnection; +} + +export interface MarketsCandlesQuery_marketsConnection_edges { + __typename: "MarketEdge"; + node: MarketsCandlesQuery_marketsConnection_edges_node; +} + +export interface MarketsCandlesQuery_marketsConnection { + __typename: "MarketConnection"; + /** + * The markets in this connection + */ + edges: MarketsCandlesQuery_marketsConnection_edges[]; +} + +export interface MarketsCandlesQuery { + marketsConnection: MarketsCandlesQuery_marketsConnection; +} + +export interface MarketsCandlesQueryVariables { + interval: Interval; + since: string; +} diff --git a/libs/market-list/src/lib/__generated__/MarketsDataQuery.ts b/libs/market-list/src/lib/__generated__/MarketsDataQuery.ts new file mode 100644 index 000000000..8a69a3b44 --- /dev/null +++ b/libs/market-list/src/lib/__generated__/MarketsDataQuery.ts @@ -0,0 +1,91 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +import { AuctionTrigger, MarketTradingMode } from "@vegaprotocol/types"; + +// ==================================================== +// GraphQL query operation: MarketsDataQuery +// ==================================================== + +export interface MarketsDataQuery_marketsConnection_edges_node_data_market { + __typename: "Market"; + /** + * Market ID + */ + id: string; +} + +export interface MarketsDataQuery_marketsConnection_edges_node_data { + __typename: "MarketData"; + /** + * market of the associated mark price + */ + market: MarketsDataQuery_marketsConnection_edges_node_data_market; + /** + * the highest price level on an order book for buy orders. + */ + bestBidPrice: string; + /** + * the lowest price level on an order book for offer orders. + */ + bestOfferPrice: string; + /** + * the mark price (an unsigned integer) + */ + markPrice: string; + /** + * what triggered an auction (if an auction was started) + */ + trigger: AuctionTrigger; + /** + * the arithmetic average of the best static bid price and best static offer price + */ + staticMidPrice: string; + /** + * what state the market is in (auction, continuous, etc) + */ + marketTradingMode: MarketTradingMode; + /** + * indicative volume if the auction ended now, 0 if not in auction mode + */ + indicativeVolume: string; + /** + * indicative price if the auction ended now, 0 if not in auction mode + */ + indicativePrice: string; + /** + * the highest price level on an order book for buy orders not including pegged orders. + */ + bestStaticBidPrice: string; + /** + * the lowest price level on an order book for offer orders not including pegged orders. + */ + bestStaticOfferPrice: string; +} + +export interface MarketsDataQuery_marketsConnection_edges_node { + __typename: "Market"; + /** + * marketData for the given market + */ + data: MarketsDataQuery_marketsConnection_edges_node_data | null; +} + +export interface MarketsDataQuery_marketsConnection_edges { + __typename: "MarketEdge"; + node: MarketsDataQuery_marketsConnection_edges_node; +} + +export interface MarketsDataQuery_marketsConnection { + __typename: "MarketConnection"; + /** + * The markets in this connection + */ + edges: MarketsDataQuery_marketsConnection_edges[]; +} + +export interface MarketsDataQuery { + marketsConnection: MarketsDataQuery_marketsConnection; +} diff --git a/libs/market-list/src/lib/__generated__/index.ts b/libs/market-list/src/lib/__generated__/index.ts new file mode 100644 index 000000000..c60e2b138 --- /dev/null +++ b/libs/market-list/src/lib/__generated__/index.ts @@ -0,0 +1,9 @@ +export * from './MarketCandlesQuery'; +export * from './MarketCandlesSub'; +export * from './MarketDataFields'; +export * from './MarketDataQuery'; +export * from './MarketDataSub'; +export * from './MarketFields'; +export * from './Markets'; +export * from './MarketsCandlesQuery'; +export * from './MarketsDataQuery'; diff --git a/libs/market-list/src/lib/components/markets-container/market-list-table.tsx b/libs/market-list/src/lib/components/markets-container/market-list-table.tsx index e19f2dfdd..9c44b0c92 100644 --- a/libs/market-list/src/lib/components/markets-container/market-list-table.tsx +++ b/libs/market-list/src/lib/components/markets-container/market-list-table.tsx @@ -22,7 +22,7 @@ import { MarketTradingModeMapping, AuctionTriggerMapping, } from '@vegaprotocol/types'; -import type { MarketList_markets } from '../../'; +import type { MarketWithData } from '../../'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; type Props = AgGridReactProps | AgReactUiProps; @@ -31,7 +31,7 @@ type MarketListTableValueFormatterParams = Omit< ValueFormatterParams, 'data' | 'value' > & { - data: MarketList_markets; + data: MarketWithData; }; export const getRowId = ({ data }: { data: { id: string } }) => data.id; @@ -83,17 +83,17 @@ export const MarketListTable = forwardRef((props, ref) => { headerName={t('Trading mode')} field="data" minWidth={170} - valueGetter={({ data }: { data?: MarketList_markets }) => { + valueGetter={({ data }: { data?: MarketWithData }) => { if (!data?.data) return undefined; - const { market, trigger } = data.data; - return market && - market.tradingMode === - MarketTradingMode.TRADING_MODE_MONITORING_AUCTION && + const { trigger } = data.data; + const { tradingMode } = data; + return tradingMode === + MarketTradingMode.TRADING_MODE_MONITORING_AUCTION && trigger && trigger !== AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED - ? `${MarketTradingModeMapping[market.tradingMode]} + ? `${MarketTradingModeMapping[tradingMode]} - ${AuctionTriggerMapping[trigger]}` - : MarketTradingModeMapping[market.tradingMode]; + : MarketTradingModeMapping[tradingMode]; }} /> ((props, ref) => { type="rightAligned" cellRenderer="PriceFlashCell" filter="agNumberColumnFilter" - valueGetter={({ data }: { data?: MarketList_markets }) => { + valueGetter={({ data }: { data?: MarketWithData }) => { return data?.data?.bestBidPrice === undefined ? undefined : toBigNum(data?.data?.bestBidPrice, data.decimalPlaces).toNumber(); @@ -122,7 +122,7 @@ export const MarketListTable = forwardRef((props, ref) => { type="rightAligned" cellRenderer="PriceFlashCell" filter="agNumberColumnFilter" - valueGetter={({ data }: { data?: MarketList_markets }) => { + valueGetter={({ data }: { data?: MarketWithData }) => { return data?.data?.bestOfferPrice === undefined ? undefined : toBigNum( @@ -145,7 +145,7 @@ export const MarketListTable = forwardRef((props, ref) => { type="rightAligned" cellRenderer="PriceFlashCell" filter="agNumberColumnFilter" - valueGetter={({ data }: { data?: MarketList_markets }) => { + valueGetter={({ data }: { data?: MarketWithData }) => { return data?.data?.markPrice === undefined ? undefined : toBigNum(data?.data?.markPrice, data.decimalPlaces).toNumber(); diff --git a/libs/market-list/src/lib/components/markets-container/markets-container.tsx b/libs/market-list/src/lib/components/markets-container/markets-container.tsx index 98c8e3508..bcbbdc9ab 100644 --- a/libs/market-list/src/lib/components/markets-container/markets-container.tsx +++ b/libs/market-list/src/lib/components/markets-container/markets-container.tsx @@ -1,89 +1,29 @@ -import { useRef, useCallback, useMemo } from 'react'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; -import { MarketListTable, getRowId } from './market-list-table'; +import { MarketListTable } from './market-list-table'; import { useDataProvider } from '@vegaprotocol/react-helpers'; -import type { AgGridReact } from 'ag-grid-react'; import type { RowClickedEvent } from 'ag-grid-community'; -import { produce } from 'immer'; -import merge from 'lodash/merge'; -import type { - MarketList_markets, - MarketList_markets_data, - MarketDataSub_marketData, -} from '../../'; -import { marketsDataProvider as dataProvider } from '../../markets-data-provider'; -import { Interval, MarketState } from '@vegaprotocol/types'; - +import { marketsWithDataProvider as dataProvider } from '../../markets-provider'; +import type { MarketWithData } from '../../markets-provider'; interface MarketsContainerProps { onSelect: (marketId: string) => void; } export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => { - const gridRef = useRef(null); - - const yTimestamp = useMemo(() => { - const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600; - return new Date(yesterday * 1000).toISOString(); - }, []); - const variables = useMemo( - () => ({ interval: Interval.INTERVAL_I1H, since: yTimestamp }), - [yTimestamp] - ); - - const update = useCallback( - ({ delta }: { delta: MarketDataSub_marketData }) => { - const update: MarketList_markets[] = []; - const add: MarketList_markets[] = []; - const remove: MarketList_markets[] = []; - if (!gridRef.current?.api) { - return false; - } - const rowNode = gridRef.current.api.getRowNode( - getRowId({ data: delta.market }) - ); - if (rowNode) { - const updatedData = produce( - rowNode.data.data, - (draft: MarketList_markets) => merge(draft, delta) - ); - if (updatedData !== rowNode.data.data) { - update.push({ ...rowNode.data, data: updatedData }); - } - } - // @TODO - else add new market - if (update.length || add.length || remove.length) { - gridRef.current.api.applyTransactionAsync({ - update, - add, - addIndex: 0, - }); - } - return true; - }, - [gridRef] - ); - - const { data, error, loading } = useDataProvider< - MarketList_markets[], - MarketList_markets_data - >({ dataProvider, update, variables }); + const { data, error, loading } = useDataProvider({ + dataProvider, + noUpdate: true, + }); return ( m.data?.market.state !== MarketState.STATE_REJECTED - ) - } - ref={gridRef} + rowData={data} onRowClicked={(rowEvent: RowClickedEvent) => { const { data, event } = rowEvent; // filters out clicks on the symbol column because it should display asset details if ((event?.target as HTMLElement).tagName.toUpperCase() === 'BUTTON') return; - onSelect((data as MarketList_markets).id); + onSelect((data as MarketWithData).id); }} /> diff --git a/libs/market-list/src/lib/components/select-market-columns.tsx b/libs/market-list/src/lib/components/select-market-columns.tsx index 1db863775..130c0f2bb 100644 --- a/libs/market-list/src/lib/components/select-market-columns.tsx +++ b/libs/market-list/src/lib/components/select-market-columns.tsx @@ -3,6 +3,7 @@ import { addDecimalsFormatNumber, formatNumberPercentage, PriceCell, + signedNumberCssClass, t, } from '@vegaprotocol/react-helpers'; import { @@ -18,10 +19,7 @@ import Link from 'next/link'; import { calcCandleHigh, calcCandleLow, totalFees } from '../utils'; import type { CandleClose } from '@vegaprotocol/types'; -import type { - MarketList_markets, - MarketList_markets_fees_factors, -} from '../__generated__/MarketList'; +import type { Market, MarketData, Candle } from '../'; import isNil from 'lodash/isNil'; export const cellClassNames = 'py-1 first:text-left text-right'; @@ -171,10 +169,12 @@ export const columnHeaders: Column[] = [ ]; export const columns = ( - market: MarketList_markets, + market: Market, + marketData: MarketData | undefined, + candles: Candle[] | undefined, onSelect: (id: string) => void ) => { - const candlesClose = market.candles + const candlesClose = candles ?.map((candle) => candle?.close) .filter((c: string | undefined): c is CandleClose => !isNil(c)); const handleKeyPress = ( @@ -185,8 +185,8 @@ export const columns = ( return onSelect(id); } }; - const candleLow = calcCandleLow(market); - const candleHigh = calcCandleHigh(market); + const candleLow = candles && calcCandleLow(candles); + const candleHigh = candles && calcCandleHigh(candles); const selectMarketColumns: Column[] = [ { value: ( @@ -207,11 +207,11 @@ export const columns = ( onlyOnDetailed: false, }, { - value: market.data?.markPrice ? ( + value: marketData?.markPrice ? (