diff --git a/apps/governance/.env b/apps/governance/.env index a6062b69a..b29f0272c 100644 --- a/apps/governance/.env +++ b/apps/governance/.env @@ -23,7 +23,7 @@ NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground #Test configuration variables CYPRESS_FAIRGROUND=false @@ -31,4 +31,4 @@ LC_ALL="en_US.UTF-8" # Cosmic elevator flags NX_SUCCESSOR_MARKETS=true -NX_METAMASK_SNAPS=true \ No newline at end of file +NX_METAMASK_SNAPS=true diff --git a/apps/governance/.env.capsule b/apps/governance/.env.capsule index 780e7394f..9e818f3ac 100644 --- a/apps/governance/.env.capsule +++ b/apps/governance/.env.capsule @@ -20,7 +20,7 @@ NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz NX_VEGA_REST_URL=http://localhost:3008/api/v2/ NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground NX_TENDERMINT_URL=http://localhost:26617 NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket @@ -30,4 +30,4 @@ CYPRESS_FAIRGROUND=false # Cosmic elevator flags NX_SUCCESSOR_MARKETS=false -NX_METAMASK_SNAPS=false \ No newline at end of file +NX_METAMASK_SNAPS=false diff --git a/apps/governance/.env.devnet b/apps/governance/.env.devnet index 7f9908cc0..e1a177258 100644 --- a/apps/governance/.env.devnet +++ b/apps/governance/.env.devnet @@ -15,11 +15,11 @@ NX_VEGA_REST_URL=https://api.n00.devnet1.vega.xyz/api/v2/ NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996 NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/ NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket # Cosmic elevator flags NX_SUCCESSOR_MARKETS=true -NX_METAMASK_SNAPS=true \ No newline at end of file +NX_METAMASK_SNAPS=true diff --git a/apps/governance/.env.mainnet b/apps/governance/.env.mainnet index 982a605bf..cf9e143f5 100644 --- a/apps/governance/.env.mainnet +++ b/apps/governance/.env.mainnet @@ -15,7 +15,7 @@ NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-k8s.ops.vega.xyz NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json NX_VEGA_REST_URL=https://api.vega.community/api/v2/ NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet NX_TENDERMINT_URL=https://be.vega.community NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket diff --git a/apps/governance/.env.mainnet-mirror b/apps/governance/.env.mainnet-mirror index 0ef3d4076..466f87123 100644 --- a/apps/governance/.env.mainnet-mirror +++ b/apps/governance/.env.mainnet-mirror @@ -14,7 +14,7 @@ NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-mirror-k8s.ops.vega.xyz NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json NX_VEGA_REST_URL=https://api.mainnet-mirror.vega.rocks/api/v2/ NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket diff --git a/apps/governance/.env.stagnet1 b/apps/governance/.env.stagnet1 index 70cb17afe..64171ba1f 100644 --- a/apps/governance/.env.stagnet1 +++ b/apps/governance/.env.stagnet1 @@ -11,7 +11,7 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/ NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket diff --git a/apps/governance/.env.testnet b/apps/governance/.env.testnet index 2135c6f19..408804c11 100644 --- a/apps/governance/.env.testnet +++ b/apps/governance/.env.testnet @@ -16,7 +16,7 @@ NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/ NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996 NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket diff --git a/apps/governance/.env.validators-testnet b/apps/governance/.env.validators-testnet index 5ca68a594..d4489c8bc 100644 --- a/apps/governance/.env.validators-testnet +++ b/apps/governance/.env.validators-testnet @@ -13,7 +13,7 @@ NX_VEGA_REST_URL=https://api-validators-testnet.vega.rocks/api/v2/ NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996 NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega. diff --git a/apps/trading-e2e/src/integration/closed-markets.cy.ts b/apps/trading-e2e/src/integration/closed-markets.cy.ts deleted file mode 100644 index f0861de49..000000000 --- a/apps/trading-e2e/src/integration/closed-markets.cy.ts +++ /dev/null @@ -1,475 +0,0 @@ -import { aliasGQLQuery } from '@vegaprotocol/cypress'; -import type { DataSourceDefinition } from '@vegaprotocol/types'; -import { - MarketState, - MarketStateMapping, - PropertyKeyType, -} from '@vegaprotocol/types'; -import { addDays, subDays } from 'date-fns'; -import { - chainIdQuery, - statisticsQuery, - createDataConnection, - oracleSpecDataConnectionQuery, - createMarketFragment, - marketsQuery, - marketsDataQuery, - createMarketsDataFragment, - assetQuery, - networkParamsQuery, - nodeGuardQuery, -} from '@vegaprotocol/mock'; -import { - addDecimalsFormatNumber, - getDateTimeFormat, -} from '@vegaprotocol/utils'; - -describe('Closed markets', { tags: '@smoke' }, () => { - const settlementDataProperty = 'settlement-data-property'; - const settlementDataPropertyKey = { - __typename: 'PropertyKey' as const, - name: settlementDataProperty, - type: PropertyKeyType.TYPE_INTEGER, - numberDecimalPlaces: 2, - }; - const settlementDataSourceData: DataSourceDefinition = { - sourceType: { - sourceType: { - filters: [ - { - __typename: 'Filter', - key: settlementDataPropertyKey, - }, - ], - }, - }, - }; - const rowSelector = - '[data-testid="tab-closed-markets"] .ag-center-cols-container .ag-row'; - - const assetsResult = assetQuery(); - // @ts-ignore asset definitely exists - const settlementAsset = assetsResult.assetsConnection.edges[0].node; - - const settledMarket = createMarketFragment({ - id: '0', - state: MarketState.STATE_SETTLED, - marketTimestamps: { - open: subDays(new Date(), 10).toISOString(), - close: subDays(new Date(), 4).toISOString(), - }, - tradableInstrument: { - instrument: { - product: { - dataSourceSpecBinding: { - settlementDataProperty, - }, - dataSourceSpecForTradingTermination: { - id: 'market-1-trading-termination-oracle-id', - }, - dataSourceSpecForSettlementData: { - id: 'market-1-settlement-data-oracle-id', - data: settlementDataSourceData, - }, - settlementAsset, - }, - }, - }, - }); - - const terminatedMarket = createMarketFragment({ - id: '1', - state: MarketState.STATE_TRADING_TERMINATED, - marketTimestamps: { - open: subDays(new Date(), 10).toISOString(), - close: null, // market - }, - tradableInstrument: { - instrument: { - metadata: { - tags: [ - `settlement-expiry-date:${addDays(new Date(), 4).toISOString()}`, - ], - }, - product: { - dataSourceSpecBinding: { - settlementDataProperty, - }, - dataSourceSpecForSettlementData: { - id: 'market-1-settlement-data-oracle-id', - data: settlementDataSourceData, - }, - }, - }, - }, - }); - - const delayedSettledMarket = createMarketFragment({ - id: '2', - state: MarketState.STATE_TRADING_TERMINATED, - marketTimestamps: { - open: subDays(new Date(), 10).toISOString(), - close: null, // market - }, - tradableInstrument: { - instrument: { - metadata: { - tags: [ - `settlement-expiry-date:${subDays(new Date(), 2).toISOString()}`, - ], - }, - product: { - dataSourceSpecBinding: { - settlementDataProperty, - }, - dataSourceSpecForSettlementData: { - id: 'market-1-settlement-data-oracle-id', - data: settlementDataSourceData, - }, - }, - }, - }, - }); - - const unknownMarket = createMarketFragment({ - id: '3', - state: MarketState.STATE_SETTLED, - }); - - const closedMarketsResult = [ - { - node: settledMarket, - }, - { - node: terminatedMarket, - }, - { - node: delayedSettledMarket, - }, - { node: unknownMarket }, - { - node: createMarketFragment({ id: '4', state: MarketState.STATE_PENDING }), - }, - { - node: createMarketFragment({ id: '5', state: MarketState.STATE_ACTIVE }), - }, - ]; - - const settledMarketData = createMarketsDataFragment({ - market: { - id: settledMarket.id, - }, - bestBidPrice: '1000', - bestOfferPrice: '2000', - markPrice: '1500', - }); - - const closedMarketsDataResult = [ - { - node: { - data: settledMarketData, - }, - }, - { - node: { - data: createMarketsDataFragment({ - market: { - id: terminatedMarket.id, - }, - }), - }, - }, - { - node: { - data: createMarketsDataFragment({ - market: { - id: delayedSettledMarket.id, - }, - }), - }, - }, - { - node: { - data: createMarketsDataFragment({ - market: { - id: unknownMarket.id, - }, - }), - }, - }, - ]; - - const specDataConnection = createDataConnection(); - - before(() => { - cy.setOnBoardingViewed(); - cy.mockGQL((req) => { - aliasGQLQuery(req, 'ChainId', chainIdQuery()); - aliasGQLQuery(req, 'Statistics', statisticsQuery()); - aliasGQLQuery(req, 'NodeGuard', nodeGuardQuery()); - aliasGQLQuery(req, 'NetworkParams', networkParamsQuery()); - aliasGQLQuery( - req, - 'Markets', - marketsQuery({ - marketsConnection: { - edges: closedMarketsResult, - }, - }) - ); - aliasGQLQuery( - req, - 'MarketsData', - marketsDataQuery({ - marketsConnection: { - edges: closedMarketsDataResult, - }, - }) - ); - aliasGQLQuery( - req, - 'OracleSpecDataConnection', - oracleSpecDataConnectionQuery() - ); - }); - - cy.mockSubscription(); - - cy.visit('/#/markets/all'); - cy.get('[data-testid="Closed markets"]').click(); - }); - - it('renders a settled market', () => { - const expectedMarkets = closedMarketsResult.filter((edge) => { - return [ - MarketState.STATE_SETTLED, - MarketState.STATE_TRADING_TERMINATED, - ].includes(edge.node.state); - }); - const product = settledMarket.tradableInstrument.instrument.product; - - // rows should be filtered to only include settled/terminated markets - cy.get(rowSelector).should('have.length', expectedMarkets.length); - - // check each column in the first row renders correctly - // 6001-MARK-001 - cy.get(rowSelector) - .first() - .find('[col-id="code"]') - .find('[data-testid="market-code"]') - .should('have.text', settledMarket.tradableInstrument.instrument.code); - - // 6001-MARK-071 - cy.get(rowSelector) - .first() - .find('[title="Future"]') - .should('have.text', 'Futr'); - - // 6001-MARK-002 - cy.get(rowSelector) - .first() - .find('[col-id="name"]') - .should('have.text', settledMarket.tradableInstrument.instrument.name); - - // 6001-MARK-003 - cy.get(rowSelector) - .first() - .find('[col-id="state"]') - .should('have.text', MarketStateMapping[settledMarket.state]); - - // 6001-MARK-004 - // 6001-MARK-005 - // 6001-MARK-009 - // 6001-MARK-008 - // 6001-MARK-010 - cy.get(rowSelector) - .first() - .find('[col-id="settlementDate"]') - .find('[data-testid="link"]') - .should(($el) => { - const href = $el.attr('href'); - expect(href).to.match( - new RegExp( - `/oracles/${product.dataSourceSpecForTradingTermination.id}` - ) - ); - }) - .should('have.text', '4 days ago') - .should( - 'have.attr', - 'title', - getDateTimeFormat().format( - new Date(settledMarket.marketTimestamps.close) - ) - ); - - // 6001-MARK-011 - cy.get(rowSelector) - .first() - .find('[col-id="bestBidPrice"]') - .should( - 'have.text', - addDecimalsFormatNumber( - settledMarketData.bestBidPrice, - settledMarket.decimalPlaces - ) - ); - - // 6001-MARK-012 - cy.get(rowSelector) - .first() - .find('[col-id="bestOfferPrice"]') - .should( - 'have.text', - addDecimalsFormatNumber( - settledMarketData.bestOfferPrice, - settledMarket.decimalPlaces - ) - ); - - // 6001-MARK-013 - cy.get(rowSelector).first().find('[col-id="markPrice"]').should( - 'have.text', - - addDecimalsFormatNumber( - settledMarketData.markPrice, - settledMarket.decimalPlaces - ) - ); - - // 6001-MARK-014 - // 6001-MARK-015 - // 6001-MARK-016 - cy.get(rowSelector) - .first() - .find('[col-id="settlementDataOracleId"]') - .find('[data-testid="link"]') - .should(($el) => { - const href = $el.attr('href'); - expect(href).to.match( - new RegExp(`/oracles/${product.dataSourceSpecForSettlementData.id}`) - ); - }) - .should( - 'have.text', - addDecimalsFormatNumber( - // @ts-ignore cannot deep un-partial - specDataConnection.externalData.data.data[0].value, - settlementDataPropertyKey.numberDecimalPlaces - ) - ); - - // 6001-MARK-018 - cy.get(rowSelector) - .first() - .find('[col-id="settlementAsset"]') - .should('have.text', product.settlementAsset.symbol); - - // 6001-MARK-020 - cy.get('.ag-pinned-right-cols-container') - .find('[col-id="market-actions"]') - .first() - .find('button svg') - .should('exist'); - if (Cypress.env('NX_SUCCESSOR_MARKETS')) { - cy.get(rowSelector) - .find('[col-id="successorMarket"]') - .first() - .should('have.text', '-'); - } - }); - - // test market list for market in terminated state - it('renders a terminated market', () => { - cy.get(rowSelector) - .eq(1) - .find('[col-id="state"]') - .should('have.text', MarketStateMapping[terminatedMarket.state]); - - // 6001-MARK-006 - // 6001-MARK-007 - cy.get(rowSelector) - .eq(1) - .find('[col-id="settlementDate"]') - .find('[data-testid="link"]') - .should('have.text', 'Expected in 4 days'); - }); - - it('renders a terminated market which was expected to have settled', () => { - cy.get(rowSelector) - .eq(2) - .find('[col-id="settlementDate"]') - .should('have.class', 'text-danger') - .find('[data-testid="link"]') - .should('have.text', 'Expected 2 days ago'); - }); - - it('renders terminated market which doesnt have settlement date metadata', () => { - cy.get(rowSelector) - .eq(3) - .find('[col-id="settlementDate"]') - .find('[data-testid="link"]') - .should('have.text', 'Unknown'); - }); - - it('can open asset detail dialog', () => { - cy.mockGQL((req) => { - aliasGQLQuery(req, 'Asset', assetsResult); - }); - - cy.get(rowSelector) - .first() - .find('[col-id="settlementAsset"]') - .find('button') - .click(); - - // 6001-MARK-019 - cy.get('[data-testid="dialog-title"]').should( - 'have.text', - `Asset details - ${settlementAsset.symbol}` - ); - - cy.get('[data-testid="dialog-close"]').click(); - }); - - it('can open row actions', () => { - cy.get('.ag-pinned-right-cols-container') - .find('[col-id="market-actions"]') - .first() - .find('button') - .click(); - - const dropdownContent = '[data-testid="market-actions-content"]'; - const dropdownContentItem = '[role="menuitem"]'; - cy.get(dropdownContent) - .find(dropdownContentItem) - .eq(0) - // Cannot click the copy button as it falls back to window.prompt, blocking the test. - .should('have.text', 'Copy Market ID'); - - cy.get(dropdownContent) - .find(dropdownContentItem) - .eq(1) - .find('a') - .then(($el) => { - const href = $el.attr('href'); - expect(/\/markets\/0/.test(href || '')).to.equal(true); - }) - .should('have.text', 'View on Explorer'); - }); -}); - -describe('no closed markets', { tags: '@smoke', testIsolation: true }, () => { - before(() => { - cy.mockTradingPage(); - cy.mockSubscription(); - cy.setOnBoardingViewed(); - cy.visit('/#/markets/all'); - cy.get('[data-testid="Closed markets"]').click(); - }); - - it('can see no markets message', () => { - // 6001-MARK-034 - cy.getByTestId('tab-closed-markets').should('contain.text', 'No markets'); - }); -}); diff --git a/apps/trading-e2e/src/integration/market-info.cy.ts b/apps/trading-e2e/src/integration/market-info.cy.ts index 9e6fd8c08..35720c4a6 100644 --- a/apps/trading-e2e/src/integration/market-info.cy.ts +++ b/apps/trading-e2e/src/integration/market-info.cy.ts @@ -133,11 +133,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => { validateMarketDataRow(4, 'Decimals', '5'); validateMarketDataRow(5, 'Quantum', '1'); validateMarketDataRow(6, 'Status', 'Enabled'); - validateMarketDataRow( - 7, - 'Contract address', - '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4' - ); + validateMarketDataRow(7, 'Contract address', '0x0158…78a4'); validateMarketDataRow(8, 'Withdrawal threshold', '0.0005'); validateMarketDataRow(9, 'Lifetime limit', '1,230'); validateMarketDataRow(10, 'Infrastructure fee account balance', '0.00001'); diff --git a/apps/trading-e2e/src/integration/order-book.cy.ts b/apps/trading-e2e/src/integration/order-book.cy.ts index ae12be599..34cb68fce 100644 --- a/apps/trading-e2e/src/integration/order-book.cy.ts +++ b/apps/trading-e2e/src/integration/order-book.cy.ts @@ -6,7 +6,7 @@ const askVolume = 'ask-vol-9894185'; const bidVolume = 'bid-vol-9889001'; const askCumulative = 'cumulative-vol-9894185'; const bidCumulative = 'cumulative-vol-9889001'; -const midPrice = 'middle-mark-price-4612690000'; +const midPrice = 'last-traded-4612690000'; const priceResolution = 'resolution'; const dealTicketPrice = 'order-price'; const dealTicketSize = 'order-size'; diff --git a/apps/trading-e2e/src/integration/wallet-eth.cy.ts b/apps/trading-e2e/src/integration/wallet-eth.cy.ts index 9859ff4c9..a5a5f89cf 100644 --- a/apps/trading-e2e/src/integration/wallet-eth.cy.ts +++ b/apps/trading-e2e/src/integration/wallet-eth.cy.ts @@ -43,11 +43,10 @@ describe('ethereum wallet', { tags: '@smoke', testIsolation: true }, () => { // 0004-EWAL-005 // 0004-EWAL-006 - const ethWalletAddress = Cypress.env('ETHEREUM_WALLET_ADDRESS'); cy.getByTestId('Deposits').click(); cy.getByTestId('deposit-button').click(); connectEthereumWallet('MetaMask'); - cy.getByTestId('ethereum-address').should('have.text', ethWalletAddress); + cy.getByTestId('ethereum-address').should('have.text', '0xEe7D…d94F'); cy.getByTestId('disconnect-ethereum-wallet') .should('have.text', 'Disconnect') .click(); diff --git a/apps/trading/.env b/apps/trading/.env index fbd2a537f..78e6de583 100644 --- a/apps/trading/.env +++ b/apps/trading/.env @@ -13,7 +13,7 @@ NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72 NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground # Cosmic elevator flags diff --git a/apps/trading/.env.capsule b/apps/trading/.env.capsule index 4638a051a..6d0e681ed 100644 --- a/apps/trading/.env.capsule +++ b/apps/trading/.env.capsule @@ -13,7 +13,7 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/ NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session" diff --git a/apps/trading/.env.devnet b/apps/trading/.env.devnet index 9462cb56c..99d465c04 100644 --- a/apps/trading/.env.devnet +++ b/apps/trading/.env.devnet @@ -14,7 +14,7 @@ NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground # Cosmic elevator flags NX_SUCCESSOR_MARKETS=true diff --git a/apps/trading/.env.mainnet b/apps/trading/.env.mainnet index 44e6c8447..df13750fa 100644 --- a/apps/trading/.env.mainnet +++ b/apps/trading/.env.mainnet @@ -14,7 +14,7 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports NX_VEGA_CONSOLE_URL=https://console.vega.xyz NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-mainnet/codfcglpplgmmlokgilfkpcjnmkbfiel -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet-mainnet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet # TAG name of the current app version - TODO: bump to the latest upon release NX_APP_VERSION=v0.20.21-core-0.71.6 diff --git a/apps/trading/.env.mainnet-mirror b/apps/trading/.env.mainnet-mirror index aebcf5e35..9a575f33c 100644 --- a/apps/trading/.env.mainnet-mirror +++ b/apps/trading/.env.mainnet-mirror @@ -14,7 +14,7 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-mainnet/codfcglpplgmmlokgilfkpcjnmkbfiel -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet-mainnet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet # TAG name of the current app version - TODO: bump to the latest upon release NX_APP_VERSION=v0.20.19-core-0.71.6 diff --git a/apps/trading/.env.stagnet1 b/apps/trading/.env.stagnet1 index 0294d0d0b..4a9bc1e46 100644 --- a/apps/trading/.env.stagnet1 +++ b/apps/trading/.env.stagnet1 @@ -14,7 +14,7 @@ NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground # Cosmic elevator flags NX_SUCCESSOR_MARKETS=true diff --git a/apps/trading/.env.testnet b/apps/trading/.env.testnet index c673562b1..1e3dba3ca 100644 --- a/apps/trading/.env.testnet +++ b/apps/trading/.env.testnet @@ -15,7 +15,7 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports NX_VEGA_CONSOLE_URL=https://console.fairground.wtf NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground # Cosmic elevator flags NX_SUCCESSOR_MARKETS=true diff --git a/apps/trading/.env.validators-testnet b/apps/trading/.env.validators-testnet index c31b364b1..c8e48e938 100644 --- a/apps/trading/.env.validators-testnet +++ b/apps/trading/.env.validators-testnet @@ -16,7 +16,7 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn -NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/pl/firefox/addon/vega-wallet +NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground # Cosmic elevator flags NX_SUCCESSOR_MARKETS=false diff --git a/apps/trading/components/market-selector/market-selector-item.spec.tsx b/apps/trading/components/market-selector/market-selector-item.spec.tsx index 69b502dcf..4e43d1732 100644 --- a/apps/trading/components/market-selector/market-selector-item.spec.tsx +++ b/apps/trading/components/market-selector/market-selector-item.spec.tsx @@ -69,6 +69,7 @@ describe('MarketSelectorItem', () => { targetStake: '1000000', trigger: AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED, priceMonitoringBounds: null, + lastTradedPrice: '100', }; const candles = [ diff --git a/libs/assets/src/lib/asset-details-dialog.tsx b/libs/assets/src/lib/asset-details-dialog.tsx index f1bf66e39..1fb26fe48 100644 --- a/libs/assets/src/lib/asset-details-dialog.tsx +++ b/libs/assets/src/lib/asset-details-dialog.tsx @@ -97,7 +97,7 @@ export const AssetDetailsDialog = ({ }} > {content} -

+

{t( 'There is 1 unit of the settlement asset (%s) to every 1 quote unit.', [assetSymbol] diff --git a/libs/assets/src/lib/asset-details-table.tsx b/libs/assets/src/lib/asset-details-table.tsx index dcf179748..eca9a30a3 100644 --- a/libs/assets/src/lib/asset-details-table.tsx +++ b/libs/assets/src/lib/asset-details-table.tsx @@ -3,7 +3,11 @@ import { addDecimalsFormatNumber } from '@vegaprotocol/utils'; import { t } from '@vegaprotocol/i18n'; import type * as Schema from '@vegaprotocol/types'; import type { KeyValueTableRowProps } from '@vegaprotocol/ui-toolkit'; -import { CopyWithTooltip, Icon } from '@vegaprotocol/ui-toolkit'; +import { + CopyWithTooltip, + Icon, + truncateMiddle, +} from '@vegaprotocol/ui-toolkit'; import { KeyValueTable, KeyValueTableRow, @@ -56,7 +60,7 @@ export const rows: Rows = [ key: AssetDetail.ID, label: t('ID'), tooltip: '', - value: (asset) => asset.id, + value: (asset) => truncateMiddle(asset.id), }, { key: AssetDetail.TYPE, @@ -109,7 +113,9 @@ export const rows: Rows = [ return ( <> - {' '} + + {truncateMiddle(asset.source.contractAddress)} + {' '} + setOpen(open)} + trigger={ + + + + } + > + + {resolutions.map((r) => ( + setResolution(r)}> + {formatResolution(r)} + + ))} + + + + + ); +}; diff --git a/libs/market-depth/src/lib/orderbook-data.spec.ts b/libs/market-depth/src/lib/orderbook-data.spec.ts index 871ca4145..389cc2919 100644 --- a/libs/market-depth/src/lib/orderbook-data.spec.ts +++ b/libs/market-depth/src/lib/orderbook-data.spec.ts @@ -31,21 +31,12 @@ describe('compactRows', () => { it('counts cumulative vol', () => { const asks = compactRows(sell, VolumeType.ask, 10); const bids = compactRows(buy, VolumeType.bid, 10); - expect(asks[0].cumulativeVol.value).toEqual(4950); - expect(bids[0].cumulativeVol.value).toEqual(579); - expect(asks[10].cumulativeVol.value).toEqual(390); - expect(bids[10].cumulativeVol.value).toEqual(4950); - expect(bids[bids.length - 1].cumulativeVol.value).toEqual(4950); - expect(asks[asks.length - 1].cumulativeVol.value).toEqual(390); - }); - - it('updates relative data', () => { - const asks = compactRows(sell, VolumeType.ask, 10); - const bids = compactRows(buy, VolumeType.bid, 10); - expect(asks[0].cumulativeVol.relativeValue).toEqual(100); - expect(bids[0].cumulativeVol.relativeValue).toEqual(12); - expect(asks[10].cumulativeVol.relativeValue).toEqual(8); - expect(bids[10].cumulativeVol.relativeValue).toEqual(100); + expect(asks[0].cumulativeVol).toEqual(4950); + expect(bids[0].cumulativeVol).toEqual(579); + expect(asks[10].cumulativeVol).toEqual(390); + expect(bids[10].cumulativeVol).toEqual(4950); + expect(bids[bids.length - 1].cumulativeVol).toEqual(4950); + expect(asks[asks.length - 1].cumulativeVol).toEqual(390); }); }); diff --git a/libs/market-depth/src/lib/orderbook-data.ts b/libs/market-depth/src/lib/orderbook-data.ts index 8d54ae2e2..31be1491a 100644 --- a/libs/market-depth/src/lib/orderbook-data.ts +++ b/libs/market-depth/src/lib/orderbook-data.ts @@ -5,15 +5,11 @@ export enum VolumeType { bid, ask, } -export interface CumulativeVol { - value: number; - relativeValue?: number; -} export interface OrderbookRowData { price: string; - value: number; - cumulativeVol: CumulativeVol; + volume: number; + cumulativeVol: number; } export const getPriceLevel = (price: string | bigint, resolution: number) => { @@ -26,25 +22,6 @@ export const getPriceLevel = (price: string | bigint, resolution: number) => { return priceLevel.toString(); }; -const getMaxVolumes = (orderbookData: OrderbookRowData[]) => ({ - cumulativeVol: Math.max( - orderbookData[0]?.cumulativeVol.value, - orderbookData[orderbookData.length - 1]?.cumulativeVol.value - ), -}); - -// round instead of ceil so we will not show 0 if value if different than 0 -const toPercentValue = (value?: number) => Math.ceil((value ?? 0) * 100); - -const updateRelativeData = (data: OrderbookRowData[]) => { - const { cumulativeVol } = getMaxVolumes(data); - data.forEach((data, i) => { - data.cumulativeVol.relativeValue = toPercentValue( - data.cumulativeVol.value / cumulativeVol - ); - }); -}; - const updateCumulativeVolumeByType = ( data: OrderbookRowData[], dataType: VolumeType @@ -53,14 +30,13 @@ const updateCumulativeVolumeByType = ( const maxIndex = data.length - 1; if (dataType === VolumeType.bid) { for (let i = 0; i <= maxIndex; i++) { - data[i].cumulativeVol.value = - data[i].value + (i !== 0 ? data[i - 1].cumulativeVol.value : 0); + data[i].cumulativeVol = + data[i].volume + (i !== 0 ? data[i - 1].cumulativeVol : 0); } } else { for (let i = maxIndex; i >= 0; i--) { - data[i].cumulativeVol.value = - data[i].value + - (i !== maxIndex ? data[i + 1].cumulativeVol.value : 0); + data[i].cumulativeVol = + data[i].volume + (i !== maxIndex ? data[i + 1].cumulativeVol : 0); } } } @@ -75,6 +51,7 @@ export const compactRows = ( getPriceLevel(row.price, resolution) ); const orderbookData: OrderbookRowData[] = []; + Object.keys(groupedByLevel).forEach((price) => { const { volume } = groupedByLevel[price].pop() as PriceLevelFieldsFragment; let value = Number(volume); @@ -83,7 +60,11 @@ export const compactRows = ( value += Number(subRow.volume); subRow = groupedByLevel[price].pop(); } - orderbookData.push({ price, value, cumulativeVol: { value: 0 } }); + orderbookData.push({ + price, + volume: value, + cumulativeVol: 0, + }); }); orderbookData.sort((a, b) => { @@ -95,8 +76,9 @@ export const compactRows = ( } return 1; }); + updateCumulativeVolumeByType(orderbookData, dataType); - updateRelativeData(orderbookData); + return orderbookData; }; @@ -140,7 +122,7 @@ export interface MockDataGeneratorParams { numberOfSellRows: number; numberOfBuyRows: number; overlap: number; - midPrice?: string; + lastTradedPrice: string; bestStaticBidPrice: number; bestStaticOfferPrice: number; } @@ -148,14 +130,14 @@ export interface MockDataGeneratorParams { export const generateMockData = ({ numberOfSellRows, numberOfBuyRows, - midPrice, + lastTradedPrice, overlap, bestStaticBidPrice, bestStaticOfferPrice, }: MockDataGeneratorParams) => { let matrix = new Array(numberOfSellRows).fill(undefined); let price = - Number(midPrice) + (numberOfSellRows - Math.ceil(overlap / 2) + 1); + Number(lastTradedPrice) + (numberOfSellRows - Math.ceil(overlap / 2) + 1); const sell: PriceLevelFieldsFragment[] = matrix.map((row, i) => ({ price: (price -= 1).toString(), volume: (numberOfSellRows - i + 1).toString(), @@ -171,7 +153,7 @@ export const generateMockData = ({ return { asks: sell, bids: buy, - midPrice, + lastTradedPrice, bestStaticBidPrice: bestStaticBidPrice.toString(), bestStaticOfferPrice: bestStaticOfferPrice.toString(), }; diff --git a/libs/market-depth/src/lib/orderbook-manager.tsx b/libs/market-depth/src/lib/orderbook-manager.tsx index 2f6a0b003..dea18ba3c 100644 --- a/libs/market-depth/src/lib/orderbook-manager.tsx +++ b/libs/market-depth/src/lib/orderbook-manager.tsx @@ -17,7 +17,7 @@ export type OrderbookData = { interface OrderbookManagerProps { marketId: string; - onClick?: (args: { price?: string; size?: string }) => void; + onClick: (args: { price?: string; size?: string }) => void; } export const OrderbookManager = ({ @@ -61,15 +61,17 @@ export const OrderbookManager = ({ data={data} reload={reload} > - + {market && marketData && ( + + )} ); }; diff --git a/libs/market-depth/src/lib/orderbook-row.tsx b/libs/market-depth/src/lib/orderbook-row.tsx index 293b46065..82cc238c1 100644 --- a/libs/market-depth/src/lib/orderbook-row.tsx +++ b/libs/market-depth/src/lib/orderbook-row.tsx @@ -1,158 +1,149 @@ -import React, { memo } from 'react'; +import type { ReactNode } from 'react'; +import { memo } from 'react'; import { addDecimal, addDecimalsFixedFormatNumber } from '@vegaprotocol/utils'; -import { NumericCell, PriceCell } from '@vegaprotocol/datagrid'; +import { NumericCell } from '@vegaprotocol/datagrid'; import { VolumeType } from './orderbook-data'; import classNames from 'classnames'; +const HIDE_VOL_WIDTH = 190; +const HIDE_CUMULATIVE_VOL_WIDTH = 260; + interface OrderbookRowProps { - value: number; - cumulativeValue?: number; - cumulativeRelativeValue?: number; + volume: number; + cumulativeVolume: number; decimalPlaces: number; positionDecimalPlaces: number; price: string; - onClick?: (args: { price?: string; size?: string }) => void; + onClick: (args: { price?: string; size?: string }) => void; type: VolumeType; width: number; + maxVol: number; } -const HIDE_VOL_WIDTH = 150; -const HIDE_CUMULATIVE_VOL_WIDTH = 220; - -const CumulationBar = ({ - cumulativeValue = 0, - type, -}: { - cumulativeValue?: number; - type: VolumeType; -}) => { - return ( -

- ); -}; - -const CumulativeVol = memo( +export const OrderbookRow = memo( ({ - testId, - positionDecimalPlaces, - cumulativeValue, - onClick, - }: { - ask?: number; - bid?: number; - cumulativeValue?: number; - testId?: string; - className?: string; - positionDecimalPlaces: number; - onClick?: (size?: string | number) => void; - }) => { - const volume = cumulativeValue ? ( - - ) : null; - - return onClick && volume ? ( - - ) : ( -
- {volume} -
- ); - } -); -CumulativeVol.displayName = 'OrderBookCumulativeVol'; - -export const OrderbookRow = React.memo( - ({ - value, - cumulativeValue, - cumulativeRelativeValue, + volume, + cumulativeVolume, decimalPlaces, positionDecimalPlaces, price, onClick, type, width, + maxVol, }: OrderbookRowProps) => { const txtId = type === VolumeType.bid ? 'bid' : 'ask'; const cols = width >= HIDE_CUMULATIVE_VOL_WIDTH ? 3 : width >= HIDE_VOL_WIDTH ? 2 : 1; return ( -
- +
+
- - onClick && onClick({ price: addDecimal(price, decimalPlaces) }) - } - valueFormatted={addDecimalsFixedFormatNumber(price, decimalPlaces)} - className={ - type === VolumeType.ask - ? 'text-market-red dark:text-market-red' - : 'text-market-green-600 dark:text-market-green' - } - /> - {width >= HIDE_VOL_WIDTH && ( - - onClick && - value && - onClick({ - size: addDecimal(value, positionDecimalPlaces), - }) - } - value={value} + onClick({ price: addDecimal(price, decimalPlaces) })} + > + + + {width >= HIDE_VOL_WIDTH && ( + + onClick({ size: addDecimal(volume, positionDecimalPlaces) }) + } + > + + )} {width >= HIDE_CUMULATIVE_VOL_WIDTH && ( - - onClick && - cumulativeValue && onClick({ - size: addDecimal(cumulativeValue, positionDecimalPlaces), + size: addDecimal(cumulativeVolume, positionDecimalPlaces), }) } - positionDecimalPlaces={positionDecimalPlaces} - cumulativeValue={cumulativeValue} - /> + > + + )}
); } ); + OrderbookRow.displayName = 'OrderbookRow'; + +const OrderBookRowCell = ({ + children, + onClick, +}: { + children: ReactNode; + onClick: () => void; +}) => { + return ( + + ); +}; + +const CumulationBar = ({ + cumulativeVolume = 0, + type, + maxVol, +}: { + cumulativeVolume: number; + type: VolumeType; + maxVol: number; +}) => { + const width = (cumulativeVolume / maxVol) * 100; + return ( +
+ ); +}; diff --git a/libs/market-depth/src/lib/orderbook.spec.tsx b/libs/market-depth/src/lib/orderbook.spec.tsx index 00d9b48e5..68972cd62 100644 --- a/libs/market-depth/src/lib/orderbook.spec.tsx +++ b/libs/market-depth/src/lib/orderbook.spec.tsx @@ -1,7 +1,7 @@ import { render, waitFor, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { generateMockData, VolumeType } from './orderbook-data'; -import { Orderbook } from './orderbook'; +import { Orderbook, OrderbookMid } from './orderbook'; import * as orderbookData from './orderbook-data'; function mockOffsetSize(width: number, height: number) { @@ -24,7 +24,7 @@ describe('Orderbook', () => { numberOfSellRows: 100, numberOfBuyRows: 100, step: 1, - midPrice: '122900', + lastTradedPrice: '122900', bestStaticBidPrice: 122905, bestStaticOfferPrice: 122895, decimalPlaces: 3, @@ -44,13 +44,14 @@ describe('Orderbook', () => { positionDecimalPlaces={0} {...generateMockData(params)} assetSymbol="USD" + onClick={jest.fn()} /> ); await waitFor(() => - screen.getByTestId(`middle-mark-price-${params.midPrice}`) + screen.getByTestId(`last-traded-${params.lastTradedPrice}`) ); expect( - screen.getByTestId(`middle-mark-price-${params.midPrice}`) + screen.getByTestId(`last-traded-${params.lastTradedPrice}`) ).toHaveTextContent('122.90'); }); @@ -68,10 +69,10 @@ describe('Orderbook', () => { /> ); expect( - await screen.findByTestId(`middle-mark-price-${params.midPrice}`) + await screen.findByTestId(`last-traded-${params.lastTradedPrice}`) ).toBeInTheDocument(); // Before resolution change the price is 122.934 - await userEvent.click(await screen.getByTestId('price-122901')); + await userEvent.click(screen.getByTestId('price-122901')); expect(onClickSpy).toBeCalledWith({ price: '122.901' }); await userEvent.click(screen.getByTestId('resolution')); @@ -92,7 +93,7 @@ describe('Orderbook', () => { VolumeType.ask, 10 ); - await userEvent.click(await screen.getByTestId('price-12294')); + await userEvent.click(screen.getByTestId('price-12294')); expect(onClickSpy).toBeCalledWith({ price: '122.94' }); }); @@ -177,3 +178,48 @@ describe('Orderbook', () => { }); }); }); + +describe('OrderbookMid', () => { + const props = { + lastTradedPrice: '100', + decimalPlaces: 0, + assetSymbol: 'BTC', + bestAskPrice: '101', + bestBidPrice: '99', + }; + + it('renders no change until lastTradedPrice changes', () => { + const { rerender } = render(); + expect(screen.getByTestId(/last-traded/)).toHaveTextContent( + props.lastTradedPrice + ); + expect(screen.getByText(props.assetSymbol)).toBeInTheDocument(); + expect(screen.queryByTestId(/icon-/)).not.toBeInTheDocument(); + expect(screen.getByTestId('spread')).toHaveTextContent('(2)'); + + // rerender with no change should not show the icon + rerender(); + expect(screen.queryByTestId(/icon-/)).not.toBeInTheDocument(); + + rerender( + + ); + expect(screen.getByTestId('icon-arrow-up')).toBeInTheDocument(); + expect(screen.getByTestId('spread')).toHaveTextContent('(3)'); + + // rerender again with the same price, should still be set to 'up' + rerender( + + ); + expect(screen.getByTestId('icon-arrow-up')).toBeInTheDocument(); + expect(screen.getByTestId('spread')).toHaveTextContent('(4)'); + + rerender(); + expect(screen.getByTestId('icon-arrow-down')).toBeInTheDocument(); + }); +}); diff --git a/libs/market-depth/src/lib/orderbook.stories.tsx b/libs/market-depth/src/lib/orderbook.stories.tsx index 84400cddf..7346ef6bd 100644 --- a/libs/market-depth/src/lib/orderbook.stories.tsx +++ b/libs/market-depth/src/lib/orderbook.stories.tsx @@ -9,9 +9,9 @@ type Props = Omit & { const OrderbookMockDataProvider = ({ decimalPlaces, ...props }: Props) => { return ( -
+
{ decimalPlaces={decimalPlaces} {...generateMockData({ ...props })} assetSymbol="USD" + onClick={() => undefined} />
diff --git a/libs/market-depth/src/lib/orderbook.tsx b/libs/market-depth/src/lib/orderbook.tsx index 9ccc0a7c0..145ddbb30 100644 --- a/libs/market-depth/src/lib/orderbook.tsx +++ b/libs/market-depth/src/lib/orderbook.tsx @@ -1,25 +1,15 @@ import { useMemo, useRef, useState } from 'react'; import ReactVirtualizedAutoSizer from 'react-virtualized-auto-sizer'; -import { - addDecimalsFormatNumber, - formatNumberFixed, -} from '@vegaprotocol/utils'; +import { addDecimalsFormatNumber } from '@vegaprotocol/utils'; import { t } from '@vegaprotocol/i18n'; import { usePrevious } from '@vegaprotocol/react-helpers'; import { OrderbookRow } from './orderbook-row'; import type { OrderbookRowData } from './orderbook-data'; import { compactRows, VolumeType } from './orderbook-data'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, - Splash, - VegaIcon, - VegaIconNames, -} from '@vegaprotocol/ui-toolkit'; +import { Splash, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit'; import classNames from 'classnames'; import type { PriceLevelFieldsFragment } from './__generated__/MarketDepth'; +import { OrderbookControls } from './orderbook-controls'; // Sets row height, will be used to calculate number of rows that can be // displayed each side of the book without overflow @@ -27,20 +17,7 @@ export const rowHeight = 17; const rowGap = 1; const midHeight = 30; -type PriceChange = 'up' | 'down' | 'none'; - -const PRICE_CHANGE_ICON_MAP: Readonly> = { - up: VegaIconNames.ARROW_UP, - down: VegaIconNames.ARROW_DOWN, - none: VegaIconNames.BULLET, -}; -const PRICE_CHANGE_CLASS_MAP: Readonly> = { - up: 'text-market-green-600 dark:text-market-green', - down: 'text-market-red dark:text-market-red', - none: 'text-vega-blue-500', -}; - -const OrderbookTable = ({ +const OrderbookSide = ({ rows, resolution, type, @@ -48,14 +25,16 @@ const OrderbookTable = ({ positionDecimalPlaces, onClick, width, + maxVol, }: { rows: OrderbookRowData[]; resolution: number; decimalPlaces: number; positionDecimalPlaces: number; type: VolumeType; - onClick?: (args: { price?: string; size?: string }) => void; + onClick: (args: { price?: string; size?: string }) => void; width: number; + maxVol: number; }) => { return (
))}
@@ -90,31 +69,88 @@ const OrderbookTable = ({ ); }; +export const OrderbookMid = ({ + lastTradedPrice, + decimalPlaces, + assetSymbol, + bestAskPrice, + bestBidPrice, +}: { + lastTradedPrice: string; + decimalPlaces: number; + assetSymbol: string; + bestAskPrice: string; + bestBidPrice: string; +}) => { + const previousLastTradedPrice = usePrevious(lastTradedPrice); + const priceChangeRef = useRef<'up' | 'down' | 'none'>('none'); + const spread = (BigInt(bestAskPrice) - BigInt(bestBidPrice)).toString(); + + if (previousLastTradedPrice !== lastTradedPrice) { + priceChangeRef.current = + Number(previousLastTradedPrice) > Number(lastTradedPrice) ? 'down' : 'up'; + } + + return ( +
+ {priceChangeRef.current !== 'none' && ( + + + + )} + + {addDecimalsFormatNumber(lastTradedPrice, decimalPlaces)} + + {assetSymbol} + + ({addDecimalsFormatNumber(spread, decimalPlaces)}) + +
+ ); +}; + interface OrderbookProps { decimalPlaces: number; positionDecimalPlaces: number; - onClick?: (args: { price?: string; size?: string }) => void; - midPrice?: string; + onClick: (args: { price?: string; size?: string }) => void; + lastTradedPrice: string; bids: PriceLevelFieldsFragment[]; asks: PriceLevelFieldsFragment[]; - assetSymbol: string | undefined; + assetSymbol: string; } export const Orderbook = ({ decimalPlaces, positionDecimalPlaces, onClick, - midPrice, + lastTradedPrice, asks, bids, assetSymbol, }: OrderbookProps) => { const [resolution, setResolution] = useState(1); - const resolutions = new Array( - Math.max(midPrice?.toString().length ?? 0, decimalPlaces + 1) - ) - .fill(null) - .map((v, i) => Math.pow(10, i)); const groupedAsks = useMemo(() => { return compactRows(asks, VolumeType.ask, resolution); @@ -123,44 +159,11 @@ export const Orderbook = ({ const groupedBids = useMemo(() => { return compactRows(bids, VolumeType.bid, resolution); }, [bids, resolution]); - const [isOpen, setOpen] = useState(false); - const previousMidPrice = usePrevious(midPrice); - const priceChangeRef = useRef<'up' | 'down' | 'none'>('none'); - if (midPrice && previousMidPrice !== midPrice) { - priceChangeRef.current = - (previousMidPrice || '') > midPrice ? 'down' : 'up'; - } - const priceChangeIcon = ( - - - - ); - - const formatResolution = (r: number) => { - return formatNumberFixed( - Math.log10(r) - decimalPlaces > 0 - ? Math.pow(10, Math.log10(r) - decimalPlaces) - : 0, - decimalPlaces - Math.log10(r) - ); - }; - - const increaseResolution = () => { - const index = resolutions.indexOf(resolution); - if (index < resolutions.length - 1) { - setResolution(resolutions[index + 1]); - } - }; - - const decreaseResolution = () => { - const index = resolutions.indexOf(resolution); - if (index > 0) { - setResolution(resolutions[index - 1]); - } - }; + // get the best bid/ask, note that we are using the pre aggregated + // values so we can render the most accurate spread in the mid section + const bestAskPrice = asks[0] ? asks[0].price : '0'; + const bestBidPrice = bids[0] ? bids[0].price : '0'; return (
@@ -171,21 +174,30 @@ export const Orderbook = ({ 1, Math.floor((height - midHeight) / 2 / (rowHeight + rowGap)) ); - const askRows = groupedAsks?.slice(limit * -1) ?? []; - const bidRows = groupedBids?.slice(0, limit) ?? []; + const askRows = groupedAsks.slice(limit * -1); + const bidRows = groupedBids.slice(0, limit); + + // this is used for providing a scale to render the volume + // bars based on the visible book + const deepestVisibleAsk = askRows[0]; + const deepestVisibleBid = bidRows[bidRows.length - 1]; + const maxVol = Math.max( + deepestVisibleAsk?.cumulativeVol || 0, + deepestVisibleBid?.cumulativeVol || 0 + ); return (
{askRows.length || bidRows.length ? ( <> - -
- {midPrice && ( - <> - - {addDecimalsFormatNumber(midPrice, decimalPlaces)} - - {assetSymbol} - {priceChangeIcon} - - )} -
- + ) : ( -
+
{t('No data')}
)} @@ -228,59 +235,13 @@ export const Orderbook = ({ }}
-
- - setOpen(open)} - trigger={ - formatResolution(item).length) - ) + 3 - }ch`, - }} - > - -
- {formatResolution(resolution)} -
-
- } - > - - {resolutions.map((r) => ( - setResolution(r)}> - {formatResolution(r)} - - ))} - -
- +
+
); diff --git a/libs/markets/src/lib/__generated__/market-data.ts b/libs/markets/src/lib/__generated__/market-data.ts index 2ce7201b7..385775ebc 100644 --- a/libs/markets/src/lib/__generated__/market-data.ts +++ b/libs/markets/src/lib/__generated__/market-data.ts @@ -3,23 +3,23 @@ import * as Types from '@vegaprotocol/types'; import { gql } from '@apollo/client'; import * as Apollo from '@apollo/client'; const defaultOptions = {} as const; -export type MarketDataUpdateFieldsFragment = { __typename?: 'ObservableMarketData', marketId: string, auctionEnd?: string | null, auctionStart?: string | null, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, indicativePrice: string, indicativeVolume: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, marketValueProxy: string, markPrice: string, midPrice: string, openInterest: string, staticMidPrice: string, suppliedStake?: string | null, targetStake?: string | null, trigger: Types.AuctionTrigger, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null }; +export type MarketDataUpdateFieldsFragment = { __typename?: 'ObservableMarketData', marketId: string, auctionEnd?: string | null, auctionStart?: string | null, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, indicativePrice: string, indicativeVolume: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, marketValueProxy: string, markPrice: string, midPrice: string, openInterest: string, staticMidPrice: string, suppliedStake?: string | null, targetStake?: string | null, trigger: Types.AuctionTrigger, lastTradedPrice: string, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null }; export type MarketDataUpdateSubscriptionVariables = Types.Exact<{ marketId: Types.Scalars['ID']; }>; -export type MarketDataUpdateSubscription = { __typename?: 'Subscription', marketsData: Array<{ __typename?: 'ObservableMarketData', marketId: string, auctionEnd?: string | null, auctionStart?: string | null, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, indicativePrice: string, indicativeVolume: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, marketValueProxy: string, markPrice: string, midPrice: string, openInterest: string, staticMidPrice: string, suppliedStake?: string | null, targetStake?: string | null, trigger: Types.AuctionTrigger, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null }> }; +export type MarketDataUpdateSubscription = { __typename?: 'Subscription', marketsData: Array<{ __typename?: 'ObservableMarketData', marketId: string, auctionEnd?: string | null, auctionStart?: string | null, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, indicativePrice: string, indicativeVolume: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, marketValueProxy: string, markPrice: string, midPrice: string, openInterest: string, staticMidPrice: string, suppliedStake?: string | null, targetStake?: string | null, trigger: Types.AuctionTrigger, lastTradedPrice: string, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null }> }; -export type MarketDataFieldsFragment = { __typename?: 'MarketData', auctionEnd?: string | null, auctionStart?: string | null, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, indicativePrice: string, indicativeVolume: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, marketValueProxy: string, markPrice: string, midPrice: string, openInterest: string, staticMidPrice: string, suppliedStake?: string | null, targetStake?: string | null, trigger: Types.AuctionTrigger, market: { __typename?: 'Market', id: string }, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null }; +export type MarketDataFieldsFragment = { __typename?: 'MarketData', auctionEnd?: string | null, auctionStart?: string | null, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, indicativePrice: string, indicativeVolume: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, marketValueProxy: string, markPrice: string, midPrice: string, openInterest: string, staticMidPrice: string, suppliedStake?: string | null, targetStake?: string | null, trigger: Types.AuctionTrigger, lastTradedPrice: string, market: { __typename?: 'Market', id: string }, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null }; export type MarketDataQueryVariables = Types.Exact<{ marketId: Types.Scalars['ID']; }>; -export type MarketDataQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', data?: { __typename?: 'MarketData', auctionEnd?: string | null, auctionStart?: string | null, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, indicativePrice: string, indicativeVolume: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, marketValueProxy: string, markPrice: string, midPrice: string, openInterest: string, staticMidPrice: string, suppliedStake?: string | null, targetStake?: string | null, trigger: Types.AuctionTrigger, market: { __typename?: 'Market', id: string }, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null } | null } }> } | null }; +export type MarketDataQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', data?: { __typename?: 'MarketData', auctionEnd?: string | null, auctionStart?: string | null, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, indicativePrice: string, indicativeVolume: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, marketValueProxy: string, markPrice: string, midPrice: string, openInterest: string, staticMidPrice: string, suppliedStake?: string | null, targetStake?: string | null, trigger: Types.AuctionTrigger, lastTradedPrice: string, market: { __typename?: 'Market', id: string }, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null } | null } }> } | null }; export const MarketDataUpdateFieldsFragmentDoc = gql` fragment MarketDataUpdateFields on ObservableMarketData { @@ -56,6 +56,7 @@ export const MarketDataUpdateFieldsFragmentDoc = gql` suppliedStake targetStake trigger + lastTradedPrice } `; export const MarketDataFieldsFragmentDoc = gql` @@ -95,6 +96,7 @@ export const MarketDataFieldsFragmentDoc = gql` suppliedStake targetStake trigger + lastTradedPrice } `; export const MarketDataUpdateDocument = gql` diff --git a/libs/markets/src/lib/market-data.graphql b/libs/markets/src/lib/market-data.graphql index 35272316b..fb760b16a 100644 --- a/libs/markets/src/lib/market-data.graphql +++ b/libs/markets/src/lib/market-data.graphql @@ -32,6 +32,7 @@ fragment MarketDataUpdateFields on ObservableMarketData { suppliedStake targetStake trigger + lastTradedPrice } subscription MarketDataUpdate($marketId: ID!) { @@ -76,6 +77,7 @@ fragment MarketDataFields on MarketData { suppliedStake targetStake trigger + lastTradedPrice } query MarketData($marketId: ID!) { diff --git a/libs/markets/src/lib/market-data.mock.ts b/libs/markets/src/lib/market-data.mock.ts index 496000768..d248acb92 100644 --- a/libs/markets/src/lib/market-data.mock.ts +++ b/libs/markets/src/lib/market-data.mock.ts @@ -62,6 +62,7 @@ const marketDataFields: MarketDataFieldsFragment = { markPrice: '4612690058', midPrice: '4612690000', openInterest: '0', + lastTradedPrice: '4612690000', priceMonitoringBounds: [ { minValidPrice: '654701', @@ -99,6 +100,7 @@ const marketDataUpdateFields: MarketDataUpdateFieldsFragment = { marketValueProxy: '', markPrice: '4612690058', midPrice: '0', + lastTradedPrice: '0', openInterest: '0', staticMidPrice: '0', trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED, diff --git a/libs/react-helpers/src/lib/format/number.tsx b/libs/react-helpers/src/lib/format/number.tsx index a16c94551..299d03c52 100644 --- a/libs/react-helpers/src/lib/format/number.tsx +++ b/libs/react-helpers/src/lib/format/number.tsx @@ -1,9 +1,14 @@ import { BigNumber } from 'bignumber.js'; -import { getUserLocale, formatNumber } from '@vegaprotocol/utils'; +import { + getUserLocale, + formatNumber, + getUnlimitedThreshold, +} from '@vegaprotocol/utils'; const INFINITY = '∞'; const DEFAULT_COMPACT_ABOVE = 1_000_000; const DEFAULT_COMPACT_CAP = new BigNumber(1e24); + /** * Compacts given number to human readable format. * @param number @@ -35,6 +40,10 @@ export const CompactNumber = ({ const decimalPlaces = (decimals === 'infer' ? number.decimalPlaces() : decimals) || 0; + if (number.isGreaterThan(getUnlimitedThreshold(decimalPlaces))) { + return {INFINITY}; + } + if (number.isLessThan(DEFAULT_COMPACT_ABOVE)) { return ( {formatNumber(number, decimalPlaces)} diff --git a/libs/utils/src/lib/format/number.spec.ts b/libs/utils/src/lib/format/number.spec.ts index 8ff305247..d36dfb719 100644 --- a/libs/utils/src/lib/format/number.spec.ts +++ b/libs/utils/src/lib/format/number.spec.ts @@ -5,7 +5,9 @@ import { addDecimalsFormatNumberQuantum, formatNumber, formatNumberPercentage, + getUnlimitedThreshold, isNumeric, + quantumDecimalPlaces, toDecimal, toNumberParts, } from './number'; @@ -156,3 +158,63 @@ describe('number utils', () => { }); }); }); + +describe('quantumDecimalPlaces', () => { + it.each([ + ['1', 1, 3], + ['10', 1, 2], + ['100', 1, 1], + ['1000', 1, 0], + ['1', 2, 4], + ['10', 2, 3], + ['100', 2, 2], + ['1000', 2, 1], + ['1', 3, 5], + ['10', 3, 4], + ['100', 3, 3], + ['1000', 3, 2], + ['1', 18, 20], + ['1000000000', 18, 11], + ['5000000000', 18, 11], + ['1000000000000000000', 18, 2], + ])( + 'converts quantum %s of %d decimal places to %d quant. decimal places', + (quantum, decimals, output) => { + expect(quantumDecimalPlaces(quantum, decimals)).toEqual(output); + } + ); +}); + +describe('getUnlimitedThreshold', () => { + it.each([ + [ + 0, + '9.26336713898529563388567880069503262826159877325124512315660672063305037119488e+76', + ], + [ + 1, + '9.26336713898529563388567880069503262826159877325124512315660672063305037119488e+75', + ], + [ + 2, + '9.26336713898529563388567880069503262826159877325124512315660672063305037119488e+74', + ], + [ + 3, + '9.26336713898529563388567880069503262826159877325124512315660672063305037119488e+73', + ], + [ + 10, + '9.26336713898529563388567880069503262826159877325124512315660672063305037119488e+66', + ], + [ + 18, + '9.26336713898529563388567880069503262826159877325124512315660672063305037119488e+58', + ], + ])( + 'given %d decimal places it returns unlimited threshold %s', + (decimals, output) => { + expect(getUnlimitedThreshold(decimals).toString()).toEqual(output); + } + ); +}); diff --git a/libs/utils/src/lib/format/number.ts b/libs/utils/src/lib/format/number.ts index d3a8a2382..e0d035a50 100644 --- a/libs/utils/src/lib/format/number.ts +++ b/libs/utils/src/lib/format/number.ts @@ -4,6 +4,18 @@ import memoize from 'lodash/memoize'; import { getUserLocale } from '../get-user-locale'; +/** + * A raw unformatted value greater than this is considered and displayed + * as UNLIMITED. + */ +export const UNLIMITED_THRESHOLD = new BigNumber(2).pow(256).times(0.8); +/** + * Gets the unlimited threshold value for given decimal places. + * @param decimalPlaces the asset's decimal places + */ +export const getUnlimitedThreshold = (decimalPlaces: number) => + UNLIMITED_THRESHOLD.dividedBy(Math.pow(10, decimalPlaces)); + const MIN_FRACTION_DIGITS = 2; const MAX_FRACTION_DIGITS = 20; @@ -90,6 +102,25 @@ export const formatNumberFixed = ( return getFixedNumberFormat(formatDecimals).format(Number(rawValue)); }; +export const quantumDecimalPlaces = ( + /** Raw asset's quantum value */ + rawQuantum: number | string, + /** Asset's decimal places */ + decimalPlaces: number +) => { + // if raw quantum value is an empty string then it'll evaluate to 0 + // this check ignores NaNs and zeroes + const formatDecimals = + isNaN(Number(rawQuantum)) || Number(rawQuantum) === 0 + ? decimalPlaces + : Math.max( + 0, + Math.log10(100 / Number(addDecimal(rawQuantum, decimalPlaces))) + ); + + return Math.ceil(formatDecimals); +}; + export const addDecimalsFormatNumberQuantum = ( rawValue: string | number, decimalPlaces: number, diff --git a/specs/6003-ORDB-order_book.md b/specs/6003-ORDB-order_book.md index 56acdc4a2..de2a87823 100644 --- a/specs/6003-ORDB-order_book.md +++ b/specs/6003-ORDB-order_book.md @@ -11,4 +11,7 @@ As a market user I want to see information about orders existing in the market. - I **Must** see prices sorted descending (6003-ORDB-007) - I **Must** be able to set a resolution of data (6003-ORDB-008) - When I click specific price, it **Must** be copied to deal ticket form (6003-ORDB-009) -- Order is removed from orderbook if traded away(6003-ORDB-010) +- Order is removed from orderbook if traded away (6003-ORDB-010) +- Spread (bestAsk - bestOffer) is show in the mid secion (6003-ORDB-011) +- Cumulative volume is displayed visually (volume bars) as a proportion of the entire book volume (6003-ORDB-012) +- Mid section shows the last traded price movement using an arrow (6003-ORDB-013) diff --git a/vegacapsule/config.hcl b/vegacapsule/config.hcl index 7aca9f010..9559d2cc7 100644 --- a/vegacapsule/config.hcl +++ b/vegacapsule/config.hcl @@ -37,14 +37,11 @@ EOT auth_soft_fail = true } docker_service "postgres-1" { - image = "vegaprotocol/timescaledb:2.8.0-pg14" + # Read me for more details: https://github.com/vegaprotocol/docker/tree/main/timescaledb#timescaledb + image = "vegaprotocol/vegacapsule-timescaledb:2.8.0-pg14-v0.0.1" cmd = "postgres" args = [] - env = { - POSTGRES_USER="vega" - POSTGRES_PASSWORD="vega" - POSTGRES_DBS="vega0,vega1,vega2,vega3,vega4,vega5,vega6,vega7,vega8,vega9,vega10,vega11,vega12,vega13,vega14,vega15,vega16,vega17,vega18,vega19,vega20,vega21,vega22,vega23,vega24,vega25" - } + env = {} static_port { value = 5232