Compare commits

..
725 changed files with 13828 additions and 21558 deletions
+3 -3
View File
@@ -32,14 +32,14 @@ runs:
- name: Import fairground network
shell: bash
if: ${{ inputs.capsule==false }}
run: vegawallet network import --from-url="https://raw.githubusercontent.com/vegaprotocol/networks-internal/master/stagnet3/stagnet3.toml" --force --home ~/.vegacapsule/testnet/wallet
run: vegawallet network import --from-url="https://raw.githubusercontent.com/vegaprotocol/networks/master/fairground/fairground.toml" --force --home ~/.vegacapsule/testnet/wallet
- name: Start service using fairground network
shell: bash
if: ${{ inputs.capsule==false }}
run: vegawallet service run --network stagnet3 --automatic-consent --no-version-check --home ~/.vegacapsule/testnet/wallet &
run: vegawallet service run --network fairground --automatic-consent --home ~/.vegacapsule/testnet/wallet &
- name: Start service using capsule network
shell: bash
if: ${{ inputs.capsule==true }}
if: ${{ inputs.capsule }}
run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet &
@@ -33,7 +33,7 @@ jobs:
env:
GO111MODULE: 'on'
GOBIN: /home/runner/go/bin
VEGA_VERSION: 'v0.58.0'
VEGA_VERSION: 'v0.57.0'
steps:
#######
## Setup flags
@@ -49,7 +49,7 @@ jobs:
# See if we capsule is needed for this project
- name: Set capsule flag
if: ${{ github.event.inputs.project == 'explorer-e2e' || github.event.inputs.project == 'token-e2e'}}
if: ${{ github.event.inputs.project == 'explorer-e2e' || github.event.inputs.project == 'token-e2e' }}
run: echo RUN_CAPSULE=true >> $GITHUB_ENV
#######
@@ -142,7 +142,7 @@ jobs:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPRESS_ETH_WALLET_MNEMONIC }}
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: false
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: true
######
## Upload logs
@@ -15,7 +15,7 @@ jobs:
env:
GO111MODULE: 'on'
GOBIN: /home/runner/go/bin
VEGA_VERSION: 'v0.58.0'
VEGA_VERSION: 'v0.57.0'
RUN_CAPSULE: true
steps:
#######
@@ -101,7 +101,7 @@ jobs:
working-directory: frontend-monorepo
- name: Run Cypress tests
run: yarn nx run-many --skip-nx-cache --target=e2e --all --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome --parallel=1
run: yarn nx run-many --skip-nx-cache --target=e2e --all --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
env:
GO111MODULE: 'on'
GOBIN: /home/runner/go/bin
VEGA_VERSION: 'v0.58.0'
VEGA_VERSION: 'v0.57.0'
steps:
#######
## Setup langs
+1 -1
View File
@@ -3,7 +3,7 @@ name: Generate queries
on:
push:
branches:
- develop
- master
jobs:
master:
-2
View File
@@ -42,5 +42,3 @@ jobs:
run: yarn nx affected:test
- name: Build affected
run: yarn nx affected:build
- name: Build affected spec
run: yarn nx affected --target=build-spec
Vendored
-20
View File
@@ -1,20 +0,0 @@
@Library('vega-shared-library') _
def commitHash = 'UNKNOWN'
pipeline {
agent any
options {
skipDefaultCheckout true
parallelsAlwaysFailFast()
}
stages {
stage('approbation') {
steps {
sh 'printenv'
checkout scm
runApprobation ignoreFailure: false, frontendBranch: env.BRANCH_NAME, type: 'frontend'
}
}
}
}
+25 -7
View File
@@ -1,8 +1,26 @@
# App configuration variables
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json
NX_VEGA_URL=https://api.n01.stagnet3.vega.xyz/graphql
NX_VEGA_ENV=STAGNET3
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
# React Environment Variables
# https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#expanding-environment-variables-in-env
# Netlify Environment Variables
# https://www.netlify.com/docs/continuous-deployment/#environment-variables
NX_VERSION=$npm_package_version
NX_REPOSITORY_URL=$REPOSITORY_URL
NX_BRANCH=$BRANCH
NX_PULL_REQUEST=$PULL_REQUEST
NX_HEAD=$HEAD
NX_COMMIT_REF=$COMMIT_REF
NX_CONTEXT=$CONTEXT
NX_REVIEW_ID=$REVIEW_ID
NX_INCOMING_HOOK_TITLE=$INCOMING_HOOK_TITLE
NX_INCOMING_HOOK_URL=$INCOMING_HOOK_URL
NX_INCOMING_HOOK_BODY=$INCOMING_HOOK_BODY
NX_URL=$URL
NX_DEPLOY_URL=$DEPLOY_URL
NX_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
NX_VEGA_ENV=TESTNET
NX_VEGA_WALLET_URL=http://localhost:1789
-1
View File
@@ -1 +0,0 @@
declare module '*.scss';
@@ -27,7 +27,7 @@ describe('market selector', { tags: '@smoke' }, () => {
aliasQuery(req, 'MarketTags', generateMarketTags());
aliasQuery(req, 'MarketPositions', generateMarketPositions());
aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
aliasQuery(req, 'PartyBalance', generatePartyBalance());
aliasQuery(req, 'PartyBalanceQuery', generatePartyBalance());
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
aliasQuery(req, 'MarketNames', generateMarketNames());
@@ -3,7 +3,6 @@ import {
generateSimpleMarkets,
generateMarketsCandles,
generateMarketsData,
generateMarket,
} from '../support/mocks/generate-markets';
import { generateDealTicket } from '../support/mocks/generate-deal-ticket';
import { generateMarketTags } from '../support/mocks/generate-market-tags';
@@ -28,11 +27,10 @@ describe('Market trade', { tags: '@smoke' }, () => {
aliasQuery(req, 'MarketTags', generateMarketTags());
aliasQuery(req, 'MarketPositions', generateMarketPositions());
aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
aliasQuery(req, 'PartyBalance', generatePartyBalance());
aliasQuery(req, 'PartyBalanceQuery', generatePartyBalance());
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
aliasQuery(req, 'MarketDepth', generateMarketDepth());
aliasQuery(req, 'Market', generateMarket());
});
cy.visit('/markets');
cy.wait('@Markets').then((response) => {
@@ -298,7 +296,11 @@ describe('Market trade', { tags: '@smoke' }, () => {
cy.get('#step-3-panel').find('dd').eq(4).should('have.text', ' - ');
cy.getByTestId('place-order').should('be.enabled').click();
cy.getByTestId('place-order').click();
cy.getByTestId('dialog-title').should(
'have.text',
'Awaiting network confirmation'
);
}
});
@@ -8,8 +8,10 @@ import {
emptyPositions,
generateMargins,
} from '../support/mocks/generate-positions';
import { generateAccounts } from '../support/mocks/generate-accounts';
import { generateAssets } from '../support/mocks/generate-assets';
import {
generateAccounts,
generateAssets,
} from '../support/mocks/generate-accounts';
import { generateOrders } from '../support/mocks/generate-orders';
import { generateFills } from '../support/mocks/generate-fills';
import {
+2 -5
View File
@@ -21,14 +21,11 @@ import registerCypressGrep from 'cypress-grep';
import { aliasQuery } from '@vegaprotocol/cypress';
registerCypressGrep();
before(() => {
beforeEach(() => {
// Mock chainId fetch which happens on every page for wallet connection
cy.mockGQL((req) => {
aliasQuery(req, 'ChainId', {
statistics: {
__typename: 'Statistics',
chainId: 'vega-fairground-202210041151',
},
statistics: { __typename: 'Statistics', chainId: 'test-chain-id' },
});
});
});
@@ -1,6 +1,5 @@
import type { Market } from '@vegaprotocol/market-list';
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
import type { SingleMarketFieldsFragment } from '@vegaprotocol/market-list';
export const protoCandles = [
{ open: '9556163', close: '9587028', __typename: 'Candle' },
@@ -124,24 +123,3 @@ export const protoMarket: Market = {
},
__typename: 'Market',
};
export const singleMarket: SingleMarketFieldsFragment = {
...protoMarket,
tradableInstrument: {
...protoMarket.tradableInstrument,
instrument: {
...protoMarket.tradableInstrument.instrument,
product: {
...protoMarket.tradableInstrument.instrument.product,
settlementAsset: {
...protoMarket.tradableInstrument.instrument.product.settlementAsset,
id: 'dai-id',
name: 'DAI Name',
},
oracleSpecForTradingTermination: {
id: 'oid',
},
},
},
},
};
@@ -1,6 +1,6 @@
import merge from 'lodash/merge';
import type { AccountsQuery } from '@vegaprotocol/accounts';
import { AccountType } from '@vegaprotocol/types';
import type { AccountsQuery, AssetsQuery } from '@vegaprotocol/accounts';
import { AccountType, Schema as Types } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
export const generateAccounts = (
@@ -12,7 +12,7 @@ export const generateAccounts = (
id: Cypress.env('VEGA_PUBLIC_KEY'),
accounts: [
{
__typename: 'AccountBalance',
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
market: null,
@@ -22,7 +22,7 @@ export const generateAccounts = (
},
},
{
__typename: 'AccountBalance',
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
market: {
@@ -35,7 +35,7 @@ export const generateAccounts = (
},
},
{
__typename: 'AccountBalance',
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_MARGIN,
balance: '1000',
market: {
@@ -48,7 +48,7 @@ export const generateAccounts = (
},
},
{
__typename: 'AccountBalance',
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_MARGIN,
balance: '1000',
market: {
@@ -61,7 +61,7 @@ export const generateAccounts = (
},
},
{
__typename: 'AccountBalance',
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
market: null,
@@ -75,3 +75,43 @@ export const generateAccounts = (
};
return merge(defaultAccounts, override);
};
export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
const defaultAssets: AssetsQuery = {
assetsConnection: {
edges: [
{
node: {
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
name: 'Euro',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
name: 'DAI',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-0',
symbol: 'AST0',
decimals: 5,
name: 'Asto',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
],
},
};
return merge(defaultAssets, override);
};
@@ -1,120 +0,0 @@
import merge from 'lodash/merge';
import type { AssetsQuery } from '@vegaprotocol/assets';
import { Schema as Types } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
const defaultAssets: AssetsQuery = {
assetsConnection: {
edges: [
{
node: {
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
name: 'Euro',
source: {
__typename: 'ERC20',
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
lifetimeLimit: '1',
withdrawThreshold: '2',
},
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '1',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'AccountBalance',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'AccountBalance',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'AccountBalance',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'AccountBalance',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'AccountBalance',
},
__typename: 'Asset',
},
},
{
node: {
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
name: 'DAI',
source: {
__typename: 'ERC20',
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
lifetimeLimit: '1',
withdrawThreshold: '2',
},
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '1',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: {
balance: '2',
__typename: 'AccountBalance',
},
takerFeeRewardAccount: {
balance: '3',
__typename: 'AccountBalance',
},
makerFeeRewardAccount: {
balance: '4',
__typename: 'AccountBalance',
},
lpFeeRewardAccount: {
balance: '5',
__typename: 'AccountBalance',
},
marketProposerRewardAccount: {
balance: '6',
__typename: 'AccountBalance',
},
__typename: 'Asset',
},
},
{
node: {
id: 'asset-0',
symbol: 'AST0',
decimals: 5,
name: 'Asto',
source: {
__typename: 'BuiltinAsset',
maxFaucetAmountMint: '3',
},
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '0',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: null,
takerFeeRewardAccount: null,
makerFeeRewardAccount: null,
lpFeeRewardAccount: null,
marketProposerRewardAccount: null,
__typename: 'Asset',
},
},
],
},
};
return merge(defaultAssets, override);
};
@@ -1,21 +1,13 @@
import type { DealTicketQuery } from '@vegaprotocol/deal-ticket';
import { MarketTradingMode, MarketState } from '@vegaprotocol/types';
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
export const generateDealTicket = (
override?: PartialDeep<DealTicketQuery>
): DealTicketQuery => {
const defaultResult: DealTicketQuery = {
export const generateDealTicket = () => {
return {
market: {
id: 'ca7768f6de84bf86a21bbb6b0109d9659c81917b0e0339b2c262566c9b581a15',
decimalPlaces: 5,
positionDecimalPlaces: 0,
state: MarketState.STATE_ACTIVE,
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
state: 'STATE_ACTIVE',
tradingMode: 'Continuous',
tradableInstrument: {
instrument: {
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
name: 'AAVEDAI Monthly (30 Jun 2022)',
product: {
quoteName: 'DAI',
@@ -23,7 +15,6 @@ export const generateDealTicket = (
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'Future',
@@ -36,17 +27,7 @@ export const generateDealTicket = (
lastTrade: { price: '9893006', __typename: 'Trade' },
__typename: 'MarketDepth',
},
fees: {
factors: {
makerFee: '0.0002',
infrastructureFee: '0.0005',
liquidityFee: '0.001',
__typename: 'FeeFactors',
},
__typename: 'Fees',
},
__typename: 'Market',
},
};
return merge(defaultResult, override);
};
@@ -1,5 +1,5 @@
import type { FillsQuery, FillFieldsFragment } from '@vegaprotocol/fills';
import { Schema } from '@vegaprotocol/types';
import { Side } from '@vegaprotocol/types';
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
@@ -17,7 +17,7 @@ export const generateFills = (
seller: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
},
aggressor: Schema.Side.SIDE_SELL,
aggressor: Side.SIDE_SELL,
buyerFee: {
infrastructureFee: '5000',
},
@@ -30,11 +30,11 @@ export const generateFills = (
seller: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
},
aggressor: Schema.Side.SIDE_BUY,
aggressor: Side.SIDE_BUY,
}),
generateFill({
id: '3',
aggressor: Schema.Side.SIDE_SELL,
aggressor: Side.SIDE_SELL,
market: {
id: 'market-2',
},
@@ -80,7 +80,7 @@ export const generateFill = (override?: PartialDeep<FillFieldsFragment>) => {
size: '50000',
buyOrder: 'buy-order',
sellOrder: 'sell-order',
aggressor: Schema.Side.SIDE_BUY,
aggressor: Side.SIDE_BUY,
buyer: {
__typename: 'Party',
id: 'buyer-id',
@@ -1,12 +1,12 @@
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
import type { MarketDepthQuery } from '../../../../../libs/market-depth/src/lib/__generated___/MarketDepth';
import type { MarketDepth } from '../../../../../libs/market-depth/src/lib/__generated__/MarketDepth';
export const generateMarketDepth = (
override?: PartialDeep<MarketDepthQuery>
): MarketDepthQuery => {
const defaultResult: MarketDepthQuery = {
override?: PartialDeep<MarketDepth>
): MarketDepth => {
const defaultResult: MarketDepth = {
market: {
id: 'a46bd7e5277087723b7ab835844dec3cef8b4445738101269624bf5537d5d423',
depth: {
@@ -12,9 +12,8 @@ import type {
MarketsDataQuery,
MarketDataFieldsFragment,
} from '@vegaprotocol/market-list';
import { protoMarket, protoCandles, singleMarket } from './commons';
import { protoMarket, protoCandles } from './commons';
import type { PartialDeep } from 'type-fest';
import type { MarketQuery } from '@vegaprotocol/market-list';
export const generateSimpleMarkets = (): MarketsQuery => {
const markets: Market[] = [
@@ -1378,11 +1377,3 @@ export const generatePositionsMarkets = () => {
},
};
};
export const generateMarket = (): MarketQuery => {
return {
market: {
...singleMarket,
},
};
};
@@ -1,12 +1,18 @@
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
import type { OrdersQuery, OrderFieldsFragment } from '@vegaprotocol/orders';
import { Schema } from '@vegaprotocol/types';
import type {
Orders,
Orders_party_ordersConnection_edges_node,
} from '@vegaprotocol/orders';
import {
OrderStatus,
OrderTimeInForce,
OrderType,
Side,
} from '@vegaprotocol/types';
export const generateOrders = (
override?: PartialDeep<OrdersQuery>
): OrdersQuery => {
const orders: OrderFieldsFragment[] = [
export const generateOrders = (override?: PartialDeep<Orders>): Orders => {
const orders: Orders_party_ordersConnection_edges_node[] = [
{
__typename: 'Order',
id: '066468C06549101DAF7BC51099E1412A0067DC08C246B7D8013C9D0CBF1E8EE7',
@@ -15,12 +21,12 @@ export const generateOrders = (
id: 'market-0',
},
size: '10',
type: Schema.OrderType.TYPE_LIMIT,
status: Schema.OrderStatus.STATUS_FILLED,
side: Schema.Side.SIDE_BUY,
type: OrderType.TYPE_LIMIT,
status: OrderStatus.STATUS_FILLED,
side: Side.SIDE_BUY,
remaining: '0',
price: '20000000',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
createdAt: new Date(2020, 1, 30).toISOString(),
updatedAt: null,
expiresAt: null,
@@ -36,12 +42,12 @@ export const generateOrders = (
id: 'market-1',
},
size: '1',
type: Schema.OrderType.TYPE_LIMIT,
status: Schema.OrderStatus.STATUS_FILLED,
side: Schema.Side.SIDE_BUY,
type: OrderType.TYPE_LIMIT,
status: OrderStatus.STATUS_FILLED,
side: Side.SIDE_BUY,
remaining: '0',
price: '100',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
createdAt: new Date(2020, 1, 29).toISOString(),
updatedAt: null,
expiresAt: null,
@@ -57,12 +63,12 @@ export const generateOrders = (
id: 'market-2',
},
size: '1',
type: Schema.OrderType.TYPE_LIMIT,
status: Schema.OrderStatus.STATUS_FILLED,
side: Schema.Side.SIDE_BUY,
type: OrderType.TYPE_LIMIT,
status: OrderStatus.STATUS_FILLED,
side: Side.SIDE_BUY,
remaining: '0',
price: '20000',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
createdAt: new Date(2020, 1, 28).toISOString(),
updatedAt: null,
expiresAt: null,
@@ -78,12 +84,12 @@ export const generateOrders = (
id: 'market-3',
},
size: '1',
type: Schema.OrderType.TYPE_LIMIT,
status: Schema.OrderStatus.STATUS_ACTIVE,
side: Schema.Side.SIDE_BUY,
type: OrderType.TYPE_LIMIT,
status: OrderStatus.STATUS_ACTIVE,
side: Side.SIDE_BUY,
remaining: '0',
price: '100000',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
createdAt: new Date(2020, 1, 27).toISOString(),
updatedAt: null,
expiresAt: null,
@@ -99,12 +105,12 @@ export const generateOrders = (
id: 'market-3',
},
size: '10',
type: Schema.OrderType.TYPE_LIMIT,
status: Schema.OrderStatus.STATUS_PARTIALLY_FILLED,
side: Schema.Side.SIDE_SELL,
type: OrderType.TYPE_LIMIT,
status: OrderStatus.STATUS_PARTIALLY_FILLED,
side: Side.SIDE_SELL,
remaining: '3',
price: '100000',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
createdAt: new Date(2020, 1, 27).toISOString(),
updatedAt: null,
expiresAt: null,
@@ -114,7 +120,7 @@ export const generateOrders = (
},
];
const defaultResult: OrdersQuery = {
const defaultResult: Orders = {
party: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
ordersConnection: {
@@ -1,17 +1,10 @@
import merge from 'lodash/merge';
import type { PartyBalanceQuery } from '@vegaprotocol/deal-ticket';
import type { PartialDeep } from 'type-fest';
import { AccountType } from '@vegaprotocol/types';
export const generatePartyBalance = (
override?: PartialDeep<PartyBalanceQuery>
): PartyBalanceQuery => {
const defaultResult: PartyBalanceQuery = {
export const generatePartyBalance = () => {
return {
party: {
accounts: [
{
balance: '88474051',
type: AccountType.ACCOUNT_TYPE_GENERAL,
type: 'ACCOUNT_TYPE_GENERAL',
asset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
@@ -19,11 +12,11 @@ export const generatePartyBalance = (
decimals: 5,
__typename: 'Asset',
},
__typename: 'AccountBalance',
__typename: 'Account',
},
{
balance: '100000000',
type: AccountType.ACCOUNT_TYPE_GENERAL,
type: 'ACCOUNT_TYPE_GENERAL',
asset: {
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
symbol: 'tEURO',
@@ -31,11 +24,11 @@ export const generatePartyBalance = (
decimals: 5,
__typename: 'Asset',
},
__typename: 'AccountBalance',
__typename: 'Account',
},
{
balance: '3412867',
type: AccountType.ACCOUNT_TYPE_GENERAL,
type: 'ACCOUNT_TYPE_GENERAL',
asset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
@@ -43,11 +36,11 @@ export const generatePartyBalance = (
decimals: 5,
__typename: 'Asset',
},
__typename: 'AccountBalance',
__typename: 'Account',
},
{
balance: '70007',
type: AccountType.ACCOUNT_TYPE_GENERAL,
type: 'ACCOUNT_TYPE_GENERAL',
asset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
@@ -55,12 +48,10 @@ export const generatePartyBalance = (
decimals: 5,
__typename: 'Asset',
},
__typename: 'AccountBalance',
__typename: 'Account',
},
],
__typename: 'Party',
},
};
return merge(defaultResult, override);
};
@@ -8,7 +8,7 @@ export const generatePartyMarketData = () => {
balance: '1200000',
asset: { id: 'fBTC', decimals: 5, __typename: 'Asset' },
market: null,
__typename: 'AccountBalance',
__typename: 'Account',
},
],
marginsConnection: { edges: null, __typename: 'MarginConnection' },
@@ -1,15 +1,14 @@
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
import type {
PositionsQuery,
PositionFieldsFragment,
MarginsQuery,
Positions,
Positions_party_positionsConnection_edges_node,
} from '@vegaprotocol/positions';
export const generatePositions = (
override?: PartialDeep<PositionsQuery>
): PositionsQuery => {
const nodes: PositionFieldsFragment[] = [
override?: PartialDeep<Positions>
): Positions => {
const nodes: Positions_party_positionsConnection_edges_node[] = [
{
__typename: 'Position',
realisedPNL: '0',
@@ -48,7 +47,7 @@ export const generatePositions = (
},
];
const defaultResult: PositionsQuery = {
const defaultResult: Positions = {
party: {
__typename: 'Party',
id: Cypress.env('VEGA_PUBLIC_KEY'),
@@ -67,7 +66,7 @@ export const generatePositions = (
return merge(defaultResult, override);
};
export const emptyPositions = (): PositionsQuery => {
export const emptyPositions = () => {
return {
party: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
@@ -77,7 +76,7 @@ export const emptyPositions = (): PositionsQuery => {
};
};
export const generateMargins = (): MarginsQuery => {
export const generateMargins = () => {
return {
party: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
@@ -120,7 +119,7 @@ export const generateMargins = (): MarginsQuery => {
},
{
node: {
__typename: 'MarginLevels',
m_typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
+1 -1
View File
@@ -9,5 +9,5 @@
"allowJs": true,
"types": ["cypress", "node", "cypress-real-events", "cypress-grep"]
},
"include": ["src/**/*.ts", "src/**/*.js", "./declaration.d.ts"]
"include": ["src/**/*.ts", "src/**/*.js"]
}
-7
View File
@@ -1,7 +0,0 @@
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/sandbox-network.json
NX_VEGA_URL=https://api.sandbox.vega.xyz/graphql
NX_VEGA_ENV=SANDBOX
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","STAGNET1":"https://stagnet1.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/sandbox-network.json
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/docs/testnet
-10
View File
@@ -1,10 +0,0 @@
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet1-network.json
NX_VEGA_ENV=STAGNET1
NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://stagnet1.console.vega.xyz\",\"STAGNET3\":\"https://stagnet3.console.vega.xyz\"}
NX_VEGA_TOKEN_URL=https://stagnet1.token.vega.xyz
NX_VEGA_URL=https://api.n00.stagnet1.vega.xyz/graphql
NX_VEGA_WALLET_URL=http://localhost:1789
+1 -1
View File
@@ -4,4 +4,4 @@ NX_VEGA_URL=https://api.n01.stagnet3.vega.xyz/graphql
NX_VEGA_ENV=STAGNET3
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
NX_VEGA_EXPLORER_URL=https://staging2.explorer.vega.xyz
-7
View File
@@ -77,13 +77,6 @@
"nx build console-lite"
]
}
},
"build-spec": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "yarn tsc --project ./apps/console-lite/tsconfig.spec.json"
}
}
},
"tags": []
+5 -1
View File
@@ -40,7 +40,11 @@ function App() {
<div className="max-h-full min-h-full dark:bg-lite-black dark:text-neutral-200 bg-white text-neutral-800 grid grid-rows-[min-content,1fr]">
<Header />
<Main />
<VegaConnectDialog connectors={Connectors} />
<VegaConnectDialog
connectors={Connectors}
dialogOpen={vegaWalletDialog.connect}
setDialogOpen={vegaWalletDialog.setConnect}
/>
<VegaManageDialog
dialogOpen={vegaWalletDialog.manage}
setDialogOpen={vegaWalletDialog.setManage}
@@ -0,0 +1,65 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
import { AccountType } from "@vegaprotocol/types";
// ====================================================
// GraphQL query operation: PartyBalanceQuery
// ====================================================
export interface PartyBalanceQuery_party_accounts_asset {
__typename: "Asset";
/**
* The ID of the asset
*/
id: string;
/**
* The symbol of the asset (e.g: GBP)
*/
symbol: string;
/**
* The full name of the asset (e.g: Great British Pound)
*/
name: string;
/**
* The precision of the asset. Should match the decimal precision of the asset on its native chain, e.g: for ERC20 assets, it is often 18
*/
decimals: number;
}
export interface PartyBalanceQuery_party_accounts {
__typename: "Account";
/**
* Account type (General, Margin, etc)
*/
type: AccountType;
/**
* Balance as string - current account balance (approx. as balances can be updated several times per second)
*/
balance: string;
/**
* Asset, the 'currency'
*/
asset: PartyBalanceQuery_party_accounts_asset;
}
export interface PartyBalanceQuery_party {
__typename: "Party";
/**
* Collateral accounts relating to a party
*/
accounts: PartyBalanceQuery_party_accounts[] | null;
}
export interface PartyBalanceQuery {
/**
* An entity that is trading on the Vega network
*/
party: PartyBalanceQuery_party | null;
}
export interface PartyBalanceQueryVariables {
partyId: string;
}
@@ -8,7 +8,7 @@ export type PartyBalanceQueryQueryVariables = Types.Exact<{
}>;
export type PartyBalanceQueryQuery = { __typename?: 'Query', party?: { __typename?: 'Party', accounts?: Array<{ __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } }> | null } | null };
export type PartyBalanceQueryQuery = { __typename?: 'Query', party?: { __typename?: 'Party', accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } }> | null } | null };
export const PartyBalanceQueryDocument = gql`
@@ -1,24 +1,23 @@
import React from 'react';
import { render } from '@testing-library/react';
import type {
AccountFragment,
DealTicketMarketFragment,
} from '@vegaprotocol/deal-ticket';
PartyBalanceQuery_party_accounts,
PartyBalanceQuery_party_accounts_asset,
} from './__generated__/PartyBalanceQuery';
import { DealTicketBalance } from './deal-ticket-balance';
import { AccountType } from '@vegaprotocol/types';
const tDAI: DealTicketMarketFragment['tradableInstrument']['instrument']['product']['settlementAsset'] =
{
__typename: 'Asset',
id: '1',
symbol: 'tDAI',
name: 'TDAI',
decimals: 2,
};
const tDAI: PartyBalanceQuery_party_accounts_asset = {
__typename: 'Asset',
id: '1',
symbol: 'tDAI',
name: 'TDAI',
decimals: 2,
};
const accounts: AccountFragment[] = [
const accounts: PartyBalanceQuery_party_accounts[] = [
{
__typename: 'AccountBalance',
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '1000000',
asset: tDAI,
@@ -1,15 +1,14 @@
import * as React from 'react';
import classNames from 'classnames';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import type { PartyBalanceQuery_party_accounts } from './__generated__/PartyBalanceQuery';
import { useSettlementAccount } from '../../hooks/use-settlement-account';
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
import { AccountType } from '@vegaprotocol/types';
import type {
AccountFragment,
DealTicketMarketFragment,
} from '@vegaprotocol/deal-ticket';
import { useSettlementAccount } from '@vegaprotocol/deal-ticket';
interface DealTicketBalanceProps {
settlementAsset: DealTicketMarketFragment['tradableInstrument']['instrument']['product']['settlementAsset'];
accounts: AccountFragment[];
accounts: PartyBalanceQuery_party_accounts[];
isWalletConnected: boolean;
className?: string;
}
@@ -27,7 +26,7 @@ export const DealTicketBalance = ({
accounts,
AccountType.ACCOUNT_TYPE_GENERAL
);
const formattedNumber =
const formatedNumber =
settlementAccount?.balance &&
settlementAccount.asset.decimals &&
addDecimalsFormatNumber(
@@ -38,7 +37,7 @@ export const DealTicketBalance = ({
const balance = (
<p className="text-blue text-lg font-semibold">
{settlementAccount
? t(`${formattedNumber}`)
? t(`${formatedNumber}`)
: `No ${settlementAssetSymbol} left to trade`}
</p>
);
@@ -1,8 +1,9 @@
import * as React from 'react';
import { useParams } from 'react-router-dom';
import { gql, useQuery } from '@apollo/client';
import {
DealTicketManager,
DealTicketContainer as Container,
usePartyBalanceQuery,
} from '@vegaprotocol/deal-ticket';
import { Loader } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers';
@@ -10,20 +11,41 @@ import { useVegaWallet } from '@vegaprotocol/wallet';
import { DealTicketSteps } from './deal-ticket-steps';
import { DealTicketBalance } from './deal-ticket-balance';
import Baubles from './baubles-decor';
import type { PartyBalanceQuery } from './__generated__/PartyBalanceQuery';
import ConnectWallet from '../wallet-connector';
const tempEmptyText = (
<p>{t('Please select a market from the markets page')}</p>
);
const PARTY_BALANCE_QUERY = gql`
query PartyBalanceQuery($partyId: ID!) {
party(id: $partyId) {
accounts {
type
balance
asset {
id
symbol
name
decimals
}
}
}
}
`;
export const DealTicketContainer = () => {
const { marketId } = useParams<{ marketId: string }>();
const { pubKey } = useVegaWallet();
const { data: partyData, loading } = usePartyBalanceQuery({
variables: { partyId: pubKey || '' },
skip: !pubKey,
});
const { data: partyData, loading } = useQuery<PartyBalanceQuery>(
PARTY_BALANCE_QUERY,
{
variables: { partyId: pubKey },
skip: !pubKey,
}
);
const loader = <Loader />;
@@ -48,7 +70,7 @@ export const DealTicketContainer = () => {
return (
<DealTicketManager market={data.market}>
{loading ? loader : balance}
<DealTicketSteps market={data.market} />
<DealTicketSteps market={data.market} partyData={partyData} />
</DealTicketManager>
);
}}
@@ -1,9 +1,10 @@
import React from 'react';
import type { ReactNode } from 'react';
import { t } from '@vegaprotocol/react-helpers';
import { Icon, Tooltip, TrafficLight } from '@vegaprotocol/ui-toolkit';
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
import { IconNames } from '@blueprintjs/icons';
import * as constants from './constants';
import { TrafficLight } from '../traffic-light';
interface DealTicketEstimatesProps {
quoteName?: string;
@@ -16,6 +17,45 @@ interface DealTicketEstimatesProps {
slippage?: string;
}
interface DataTitleProps {
children: ReactNode;
quoteName?: string;
}
export const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => (
<dt>
{children}
{quoteName && <small> ({quoteName})</small>}
</dt>
);
interface ValueTooltipProps {
value?: string;
children?: ReactNode;
description: string;
id?: string;
}
export const ValueTooltipRow = ({
value,
children,
description,
id,
}: ValueTooltipProps) => (
<dd className="flex gap-x-2 items-center">
{value || children}
<Tooltip align="center" description={description}>
<div className="cursor-help" id={id || ''} tabIndex={-1}>
<Icon
name={IconNames.ISSUE}
className="block rotate-180"
ariaLabel={description}
/>
</div>
</Tooltip>
</dd>
);
export const DealTicketEstimates = ({
price,
quoteName,
@@ -91,42 +131,3 @@ export const DealTicketEstimates = ({
)}
</dl>
);
interface DataTitleProps {
children: ReactNode;
quoteName?: string;
}
export const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => (
<dt>
{children}
{quoteName && <small> ({quoteName})</small>}
</dt>
);
interface ValueTooltipProps {
value?: string;
children?: ReactNode;
description: string;
id?: string;
}
export const ValueTooltipRow = ({
value,
children,
description,
id,
}: ValueTooltipProps) => (
<dd className="flex gap-x-2 items-center">
{value || children}
<Tooltip align="center" description={description}>
<div className="cursor-help" id={id || ''} tabIndex={-1}>
<Icon
name={IconNames.ISSUE}
className="block rotate-180"
ariaLabel={description}
/>
</div>
</Tooltip>
</dd>
);
@@ -1,4 +1,5 @@
import { DealTicketEstimates } from '@vegaprotocol/deal-ticket';
import React from 'react';
import { DealTicketEstimates } from './deal-ticket-estimates';
import { DealTicketSizeInput } from './deal-ticket-size-input';
interface DealTicketSizeProps {
@@ -1,19 +1,11 @@
import React, { useCallback, useState } from 'react';
import { t } from '@vegaprotocol/react-helpers';
import {
Dialog,
Icon,
Intent,
Tooltip,
TrafficLight,
} from '@vegaprotocol/ui-toolkit';
import * as constants from './constants';
import { TrafficLight } from '../traffic-light';
import { Dialog, Icon, Intent, Tooltip } from '@vegaprotocol/ui-toolkit';
import { InputSetter } from '../../components/input-setter';
import { IconNames } from '@blueprintjs/icons';
import {
DataTitle,
EST_SLIPPAGE,
ValueTooltipRow,
} from '@vegaprotocol/deal-ticket';
import { DataTitle, ValueTooltipRow } from './deal-ticket-estimates';
interface DealTicketSlippageProps {
step?: number;
@@ -48,12 +40,12 @@ export const DealTicketSlippage = ({
const formLabel = (
<label className="flex items-center mb-1">
<span className="mr-1">{t('Adjust slippage tolerance')}</span>
<Tooltip align="center" description={EST_SLIPPAGE}>
<Tooltip align="center" description={constants.EST_SLIPPAGE}>
<div className="cursor-help" tabIndex={-1}>
<Icon
name={IconNames.ISSUE}
className="block rotate-180"
ariaLabel={EST_SLIPPAGE}
ariaLabel={constants.EST_SLIPPAGE}
/>
</div>
</Tooltip>
@@ -91,7 +83,7 @@ export const DealTicketSlippage = ({
<DataTitle>{t('Est. Price Impact / Slippage')}</DataTitle>
<div className="flex">
<div className="mr-1">
<ValueTooltipRow description={EST_SLIPPAGE}>
<ValueTooltipRow description={constants.EST_SLIPPAGE}>
<TrafficLight value={value} q1={1} q2={5}>
{value}%
</TrafficLight>
@@ -3,13 +3,6 @@ import { useNavigate } from 'react-router-dom';
import { useForm, Controller } from 'react-hook-form';
import { Stepper } from '../stepper';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import {
useOrderCloseOut,
useOrderMargin,
usePartyBalanceQuery,
useMaximumPositionSize,
useCalculateSlippage,
} from '@vegaprotocol/deal-ticket';
import {
getDefaultOrder,
useOrderValidation,
@@ -19,13 +12,12 @@ import { InputError } from '@vegaprotocol/ui-toolkit';
import { BigNumber } from 'bignumber.js';
import { MarketSelector } from '@vegaprotocol/deal-ticket';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { VegaTxStatus } from '@vegaprotocol/wallet';
import { useVegaWallet, VegaTxStatus } from '@vegaprotocol/wallet';
import {
t,
addDecimalsFormatNumber,
toDecimal,
removeDecimal,
addDecimalsFormatNumber,
} from '@vegaprotocol/react-helpers';
import {
useOrderSubmit,
@@ -38,14 +30,23 @@ import { DealTicketSize } from './deal-ticket-size';
import MarketNameRenderer from '../simple-market-list/simple-market-renderer';
import SideSelector, { SIDE_NAMES } from './side-selector';
import ReviewTrade from './review-trade';
import { Schema } from '@vegaprotocol/types';
import type { PartyBalanceQuery } from './__generated__/PartyBalanceQuery';
import useOrderCloseOut from '../../hooks/use-order-closeout';
import useOrderMargin from '../../hooks/use-order-margin';
import useMaximumPositionSize from '../../hooks/use-maximum-position-size';
import useCalculateSlippage from '../../hooks/use-calculate-slippage';
import { Side, OrderType } from '@vegaprotocol/types';
import { DealTicketSlippage } from './deal-ticket-slippage';
interface DealTicketMarketProps {
market: DealTicketMarketFragment;
partyData?: PartyBalanceQuery;
}
export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
export const DealTicketSteps = ({
market,
partyData,
}: DealTicketMarketProps) => {
const navigate = useNavigate();
const setMarket = useCallback(
(marketId: string) => {
@@ -67,11 +68,15 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
const emptyString = ' - ';
const step = toDecimal(market.positionDecimalPlaces);
const orderType = watch('type');
const orderTimeInForce = watch('timeInForce');
const orderSide = watch('side');
const orderSize = watch('size');
const order = watch();
const { message: invalidText, isDisabled } = useOrderValidation({
market,
orderType: order.type,
orderTimeInForce: order.timeInForce,
orderType,
orderTimeInForce,
fieldErrors: errors,
});
const { submit, transaction, finalizedOrder, Dialog } = useOrderSubmit();
@@ -82,14 +87,9 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
partyId: pubKey || '',
});
const { data: partyBalance } = usePartyBalanceQuery({
variables: { partyId: pubKey || '' },
skip: !pubKey,
});
const maxTrade = useMaximumPositionSize({
partyId: pubKey || '',
accounts: partyBalance?.party?.accounts || [],
accounts: partyData?.party?.accounts || [],
marketId: market.id,
settlementAssetId:
market.tradableInstrument.instrument.product.settlementAsset.id,
@@ -97,11 +97,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
order,
});
const estCloseOut = useOrderCloseOut({
order,
market,
partyData: partyBalance,
});
const estCloseOut = useOrderCloseOut({ order, market, partyData });
const slippage = useCalculateSlippage({ marketId: market.id, order });
const [slippageValue, setSlippageValue] = useState(
slippage ? parseFloat(slippage) : 0
@@ -118,7 +114,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
const price = useMemo(() => {
if (slippage && market?.depth?.lastTrade?.price) {
const isLong = order.side === Schema.Side.SIDE_BUY;
const isLong = order.side === Side.SIDE_BUY;
const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus'](
parseFloat(slippage) / 100
);
@@ -134,26 +130,26 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
const notionalSize = useMemo(() => {
if (price) {
const size = new BigNumber(price).multipliedBy(order.size).toNumber();
const size = new BigNumber(price).multipliedBy(orderSize).toNumber();
return addDecimalsFormatNumber(size, market.decimalPlaces);
}
return null;
}, [market.decimalPlaces, order.size, price]);
}, [market.decimalPlaces, orderSize, price]);
const fees = useMemo(() => {
if (estMargin?.totalFees && notionalSize) {
const percentage = new BigNumber(estMargin?.totalFees)
if (estMargin?.fees && notionalSize) {
const percentage = new BigNumber(estMargin?.fees)
.dividedBy(notionalSize)
.multipliedBy(100)
.decimalPlaces(2)
.toString();
return `${estMargin.totalFees} (${percentage}%)`;
return `${estMargin.fees} (${percentage}%)`;
}
return null;
}, [estMargin?.totalFees, notionalSize]);
}, [estMargin?.fees, notionalSize]);
const max = useMemo(() => {
return new BigNumber(maxTrade)
@@ -161,10 +157,6 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
.toNumber();
}, [market.positionDecimalPlaces, maxTrade]);
useEffect(() => {
setSlippageValue(slippage ? parseFloat(slippage) : 0);
}, [slippage]);
const onSizeChange = useCallback(
(value: number) => {
const newVal = new BigNumber(value)
@@ -182,7 +174,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
(value: number) => {
if (market?.depth?.lastTrade?.price) {
if (value) {
const isLong = order.side === Schema.Side.SIDE_BUY;
const isLong = order.side === Side.SIDE_BUY;
const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus'](
value / 100
);
@@ -193,11 +185,11 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
setValue('price', bestAskPrice);
if (order.type === Schema.OrderType.TYPE_MARKET) {
setValue('type', Schema.OrderType.TYPE_LIMIT);
if (orderType === OrderType.TYPE_MARKET) {
setValue('type', OrderType.TYPE_LIMIT);
}
} else {
setValue('type', Schema.OrderType.TYPE_MARKET);
setValue('type', OrderType.TYPE_MARKET);
setValue('price', market?.depth?.lastTrade?.price);
}
}
@@ -207,8 +199,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
market.decimalPlaces,
market?.depth?.lastTrade?.price,
order.side,
order.type,
setSlippageValue,
orderType,
setValue,
]
);
@@ -255,7 +246,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
)}
/>
),
value: SIDE_NAMES[order.side] || '',
value: SIDE_NAMES[orderSide] || '',
},
{
label: t('Choose Position Size'),
@@ -267,7 +258,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
min={step}
max={max}
onSizeChange={onSizeChange}
size={new BigNumber(order.size).toNumber()}
size={new BigNumber(orderSize).toNumber()}
name="size"
price={formattedPrice || emptyString}
positionDecimalPlaces={market.positionDecimalPlaces}
@@ -276,7 +267,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
.symbol
}
notionalSize={notionalSize || emptyString}
estCloseOut={estCloseOut || emptyString}
estCloseOut={estCloseOut}
fees={fees || emptyString}
estMargin={estMargin?.margin || emptyString}
/>
@@ -286,9 +277,9 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
/>
</>
) : (
t('Loading...')
'loading...'
),
value: order.size,
value: orderSize,
},
{
label: t('Review Trade'),
@@ -306,7 +297,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
isDisabled={isDisabled}
transactionStatus={transactionStatus}
order={order}
estCloseOut={estCloseOut || emptyString}
estCloseOut={estCloseOut}
estMargin={estMargin?.margin || emptyString}
price={formattedPrice || emptyString}
quoteName={
@@ -321,15 +312,9 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
title={getOrderDialogTitle(finalizedOrder?.status)}
intent={getOrderDialogIntent(finalizedOrder?.status)}
icon={getOrderDialogIcon(finalizedOrder?.status)}
content={{
Complete: (
<OrderFeedback
transaction={transaction}
order={finalizedOrder}
/>
),
}}
/>
>
<OrderFeedback transaction={transaction} order={finalizedOrder} />
</Dialog>
</div>
),
disabled: true,
@@ -4,18 +4,19 @@ import {
KeyValueTable,
KeyValueTableRow,
} from '@vegaprotocol/ui-toolkit';
import * as React from 'react';
import classNames from 'classnames';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import { DealTicketEstimates } from '@vegaprotocol/deal-ticket';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { SIDE_NAMES } from './side-selector';
import SimpleMarketExpires from '../simple-market-list/simple-market-expires';
import { gql, useQuery } from '@apollo/client';
import type {
MarketTags,
MarketTagsVariables,
} from './__generated__/MarketTags';
import { Schema } from '@vegaprotocol/types';
import { MarketExpires } from '@vegaprotocol/market-info';
import { DealTicketEstimates } from './deal-ticket-estimates';
import { Side } from '@vegaprotocol/types';
export const MARKET_TAGS_QUERY = gql`
query MarketTags($marketId: ID!) {
@@ -72,10 +73,9 @@ export default ({
<div
className={classNames(
{
'buyButton dark:buyButtonDark':
order.side === Schema.Side.SIDE_BUY,
'buyButton dark:buyButtonDark': order.side === Side.SIDE_BUY,
'sellButton dark:sellButtonDark':
order.side === Schema.Side.SIDE_SELL,
order.side === Side.SIDE_SELL,
},
'px-2 py-1 inline text-ui-small'
)}
@@ -86,7 +86,7 @@ export default ({
<div>
{tagsData?.market?.tradableInstrument.instrument.metadata
.tags && (
<MarketExpires
<SimpleMarketExpires
tags={
tagsData?.market.tradableInstrument.instrument.metadata.tags
}
@@ -2,16 +2,16 @@ import React from 'react';
import classNames from 'classnames';
import { FormGroup } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers';
import { Schema } from '@vegaprotocol/types';
import { Side } from '@vegaprotocol/types';
interface SideSelectorProps {
value: Schema.Side;
onSelect: (side: Schema.Side) => void;
value: Side;
onSelect: (side: Side) => void;
}
export const SIDE_NAMES: Record<Schema.Side, string> = {
[Schema.Side.SIDE_BUY]: t('Long'),
[Schema.Side.SIDE_SELL]: t('Short'),
export const SIDE_NAMES: Record<Side, string> = {
[Side.SIDE_BUY]: t('Long'),
[Side.SIDE_SELL]: t('Short'),
};
export default ({ value, onSelect }: SideSelectorProps) => {
@@ -31,9 +31,9 @@ export default ({ value, onSelect }: SideSelectorProps) => {
className={classNames(
'px-8 py-2',
'buyButton hover:buyButton dark:buyButtonDark dark:hover:buyButtonDark',
{ selected: value === Schema.Side.SIDE_BUY }
{ selected: value === Side.SIDE_BUY }
)}
onClick={() => onSelect(Schema.Side.SIDE_BUY)}
onClick={() => onSelect(Side.SIDE_BUY)}
>
{t('Long')}
</button>
@@ -43,9 +43,9 @@ export default ({ value, onSelect }: SideSelectorProps) => {
className={classNames(
'px-8 py-2',
'sellButton hover:sellButton dark:sellButtonDark dark:hover:sellButtonDark',
{ selected: value === Schema.Side.SIDE_SELL }
{ selected: value === Side.SIDE_SELL }
)}
onClick={() => onSelect(Schema.Side.SIDE_SELL)}
onClick={() => onSelect(Side.SIDE_SELL)}
>
{t('Short')}
</button>
@@ -1,12 +1,32 @@
import { useMemo } from 'react';
import { gql, useQuery } from '@apollo/client';
import { DepositManager } from '@vegaprotocol/deposits';
import { t } from '@vegaprotocol/react-helpers';
import { enabledAssetsProvider } from '@vegaprotocol/assets';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { getEnabledAssets, t } from '@vegaprotocol/react-helpers';
import { Networks, useEnvironment } from '@vegaprotocol/environment';
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { Web3Container } from '@vegaprotocol/web3';
import type { DepositAssets } from './__generated__/DepositAssets';
const DEPOSITS_QUERY = gql`
query DepositAssets {
assetsConnection {
edges {
node {
id
name
symbol
decimals
status
source {
... on ERC20 {
contractAddress
}
}
}
}
}
}
`;
/**
* Fetches data required for the Deposit page
@@ -14,19 +34,20 @@ import { Web3Container } from '@vegaprotocol/web3';
export const DepositContainer = () => {
const { VEGA_ENV } = useEnvironment();
const { pubKey } = useVegaWallet();
const variables = useMemo(() => ({ partyId: pubKey }), [pubKey]);
const { data, loading, error } = useDataProvider({
dataProvider: enabledAssetsProvider,
variables,
const { data, loading, error } = useQuery<DepositAssets>(DEPOSITS_QUERY, {
variables: { partyId: pubKey },
skip: !pubKey,
});
const assets = getEnabledAssets(data);
return (
<AsyncRenderer data={data} loading={loading} error={error}>
{data && data.length ? (
<AsyncRenderer<DepositAssets> data={data} loading={loading} error={error}>
{assets.length ? (
<Web3Container>
<DepositManager
assets={data}
assets={assets}
isFaucetable={VEGA_ENV !== Networks.MAINNET}
/>
</Web3Container>
@@ -1,16 +1,12 @@
import React, { useContext } from 'react';
import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit';
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import Logo from './logo';
import { VegaWalletConnectButton } from '../vega-wallet-connect-button';
import LocalContext from '../../context/local-context';
const Header = () => {
const { updateVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
updateVegaWalletDialog: store.updateVegaWalletDialog,
}));
const {
vegaWalletDialog: { setManage },
vegaWalletDialog: { setConnect, setManage },
theme,
toggleTheme,
} = useContext(LocalContext);
@@ -22,7 +18,7 @@ const Header = () => {
<Logo />
<div className="flex items-center gap-2 ml-auto relative z-10">
<VegaWalletConnectButton
setConnectDialog={updateVegaWalletDialog}
setConnectDialog={setConnect}
setManageDialog={setManage}
/>
<ThemeSwitcher theme={theme} onToggle={toggleTheme} className="-my-4" />
@@ -22,9 +22,15 @@ const AccountsManager = () => {
const variables = useMemo(() => ({ partyId }), [partyId]);
const update = useCallback(
({ data }: { data: AccountFields[] | null }) => {
dataRef.current = data;
gridRef.current?.api?.refreshInfiniteCache();
return true;
if (!gridRef.current?.api) {
return false;
}
if (dataRef.current?.length) {
dataRef.current = data;
gridRef.current.api.refreshInfiniteCache();
return true;
}
return false;
},
[gridRef]
);
@@ -33,9 +39,7 @@ const AccountsManager = () => {
update,
variables,
});
if (!dataRef.current && data) {
dataRef.current = data;
}
dataRef.current = data;
const getRows = async ({
successCallback,
startRow,
@@ -12,7 +12,7 @@ import {
t,
} from '@vegaprotocol/react-helpers';
import BigNumber from 'bignumber.js';
import { Schema } from '@vegaprotocol/types';
import { Side } from '@vegaprotocol/types';
interface Props {
partyId: string;
@@ -118,13 +118,13 @@ const useColumnDefinitions = ({ partyId }: Props) => {
const taker = t('Taker');
const maker = t('Maker');
if (data?.buyer.id === partyId) {
if (value === Schema.Side.SIDE_BUY) {
if (value === Side.SIDE_BUY) {
return taker;
} else {
return maker;
}
} else if (data?.seller.id === partyId) {
if (value === Schema.Side.SIDE_SELL) {
if (value === Side.SIDE_SELL) {
return taker;
} else {
return maker;
@@ -67,26 +67,20 @@ const OrdersManager = () => {
<orderCancel.Dialog
title={getCancelDialogTitle(orderCancel.cancelledOrder?.status)}
intent={getCancelDialogIntent(orderCancel.cancelledOrder?.status)}
content={{
Complete: (
<OrderFeedback
transaction={orderCancel.transaction}
order={orderCancel.cancelledOrder}
/>
),
}}
/>
>
<OrderFeedback
transaction={orderCancel.transaction}
order={orderCancel.cancelledOrder}
/>
</orderCancel.Dialog>
<orderEdit.Dialog
title={getEditDialogTitle(orderEdit.updatedOrder?.status)}
content={{
Complete: (
<OrderFeedback
transaction={orderEdit.transaction}
order={orderEdit.updatedOrder}
/>
),
}}
/>
>
<OrderFeedback
transaction={orderEdit.transaction}
order={orderEdit.updatedOrder}
/>
</orderEdit.Dialog>
{editOrder && (
<OrderEditDialog
isOpen={Boolean(editOrder)}
@@ -96,7 +90,7 @@ const OrdersManager = () => {
order={editOrder}
onSubmit={(fields) => {
setEditOrder(null);
orderEdit.edit({ price: fields.limitPrice });
orderEdit.edit({ price: fields.entryPrice });
}}
/>
)}
@@ -12,16 +12,19 @@ import {
t,
} from '@vegaprotocol/react-helpers';
import type {
OrderFieldsFragment,
Orders_party_ordersConnection_edges_node,
Order,
CancelOrderArgs,
} from '@vegaprotocol/orders';
import { isOrderActive } from '@vegaprotocol/orders';
import {
OrderRejectionReasonMapping,
OrderStatus,
OrderType,
OrderStatusMapping,
OrderTypeMapping,
Schema,
Side,
OrderTimeInForce,
OrderTimeInForceMapping,
} from '@vegaprotocol/types';
@@ -57,15 +60,21 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
cellClass: 'font-mono !flex h-full items-center',
width: 80,
cellClassRules: {
[positiveClassNames]: ({ data }: { data: OrderFieldsFragment }) =>
data?.side === Schema.Side.SIDE_BUY,
[negativeClassNames]: ({ data }: { data: OrderFieldsFragment }) =>
data?.side === Schema.Side.SIDE_SELL,
[positiveClassNames]: ({
data,
}: {
data: Orders_party_ordersConnection_edges_node;
}) => data?.side === Side.SIDE_BUY,
[negativeClassNames]: ({
data,
}: {
data: Orders_party_ordersConnection_edges_node;
}) => data?.side === Side.SIDE_SELL,
},
valueFormatter: ({ value, data }: ValueFormatterParams) => {
if (value && data && data.market) {
const prefix = data
? data.side === Schema.Side.SIDE_BUY
? data.side === Side.SIDE_BUY
? '+'
: '-'
: '';
@@ -83,8 +92,8 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
valueFormatter: ({
value,
}: ValueFormatterParams & {
value?: OrderFieldsFragment['type'];
}) => OrderTypeMapping[value as Schema.OrderType],
value?: Orders_party_ordersConnection_edges_node['type'];
}) => OrderTypeMapping[value as OrderType],
},
{
colId: 'status',
@@ -97,7 +106,7 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
value?: StatusKey;
}) => {
if (value && data && data.market) {
if (value === Schema.OrderStatus.STATUS_REJECTED) {
if (value === OrderStatus.STATUS_REJECTED) {
return `${OrderStatusMapping[value as StatusKey]}: ${
data.rejectionReason &&
OrderRejectionReasonMapping[
@@ -121,7 +130,7 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
data,
value,
}: ValueFormatterParams & {
value?: OrderFieldsFragment['remaining'];
value?: Orders_party_ordersConnection_edges_node['remaining'];
}) => {
if (value && data && data.market) {
const dps = data.market.positionDecimalPlaces;
@@ -147,13 +156,13 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
value,
data,
}: ValueFormatterParams & {
value?: OrderFieldsFragment['price'];
value?: Orders_party_ordersConnection_edges_node['price'];
}) => {
if (
value === undefined ||
!data ||
!data.market ||
data.type === Schema.OrderType.TYPE_MARKET
data.type === OrderType.TYPE_MARKET
) {
return '-';
}
@@ -172,7 +181,7 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
}) => {
if (value && data?.market) {
if (
value === Schema.OrderTimeInForce.TIME_IN_FORCE_GTT &&
value === OrderTimeInForce.TIME_IN_FORCE_GTT &&
data.expiresAt
) {
const expiry = getDateTimeFormat().format(
@@ -194,7 +203,7 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
valueFormatter: ({
value,
}: ValueFormatterParams & {
value?: OrderFieldsFragment['createdAt'];
value?: Orders_party_ordersConnection_edges_node['createdAt'];
}) => {
return value ? getDateTimeFormat().format(new Date(value)) : value;
},
@@ -206,7 +215,7 @@ const useColumnDefinitions = ({ setEditOrder, orderCancel }: Props) => {
valueFormatter: ({
value,
}: ValueFormatterParams & {
value?: OrderFieldsFragment['updatedAt'];
value?: Orders_party_ordersConnection_edges_node['updatedAt'];
}) => {
return value ? getDateTimeFormat().format(new Date(value)) : '-';
},
@@ -7,7 +7,10 @@ import {
signedNumberCssClassRules,
t,
} from '@vegaprotocol/react-helpers';
import type { Position } from '@vegaprotocol/positions';
import type {
PositionsTableValueFormatterParams,
Position,
} from '@vegaprotocol/positions';
import { AmountCell } from '@vegaprotocol/positions';
import type {
CellRendererSelectorResult,
@@ -17,7 +20,6 @@ import type {
ColDef,
} from 'ag-grid-community';
import { MarketTradingMode } from '@vegaprotocol/types';
import type { VegaValueFormatterParams } from '@vegaprotocol/ui-toolkit';
import { Intent, ProgressBarCell } from '@vegaprotocol/ui-toolkit';
const EmptyCell = () => '';
@@ -75,7 +77,9 @@ const useColumnDefinitions = () => {
value,
data,
node,
}: VegaValueFormatterParams<Position, 'openVolume'>) => {
}: PositionsTableValueFormatterParams & {
value: Position['openVolume'];
}) => {
let ret;
if (value && data) {
ret = node?.rowPinned
@@ -103,7 +107,9 @@ const useColumnDefinitions = () => {
value,
data,
node,
}: VegaValueFormatterParams<Position, 'markPrice'>) => {
}: PositionsTableValueFormatterParams & {
value: Position['markPrice'];
}) => {
if (
data &&
value &&
@@ -180,8 +186,9 @@ const useColumnDefinitions = () => {
valueFormatter: ({
value,
node,
}: VegaValueFormatterParams<Position, 'currentLeverage'>) =>
value === undefined ? '' : formatNumber(value.toString(), 1),
}: PositionsTableValueFormatterParams & {
value: Position['currentLeverage'];
}) => (value === undefined ? '' : formatNumber(value.toString(), 1)),
},
{
colId: 'marginallocated',
@@ -222,8 +229,10 @@ const useColumnDefinitions = () => {
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<Position, 'realisedPNL'>) =>
value === undefined || data === undefined
}: PositionsTableValueFormatterParams & {
value: Position['realisedPNL'];
}) =>
value === undefined
? ''
: addDecimalsFormatNumber(value.toString(), data.decimals),
cellRenderer: 'PriceFlashCell',
@@ -240,8 +249,10 @@ const useColumnDefinitions = () => {
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<Position, 'unrealisedPNL'>) =>
value === undefined || data === undefined
}: PositionsTableValueFormatterParams & {
value: Position['unrealisedPNL'];
}) =>
value === undefined
? ''
: addDecimalsFormatNumber(value.toString(), data.decimals),
cellRenderer: 'PriceFlashCell',
@@ -255,7 +266,9 @@ const useColumnDefinitions = () => {
type: 'rightAligned',
valueFormatter: ({
value,
}: VegaValueFormatterParams<Position, 'updatedAt'>) => {
}: PositionsTableValueFormatterParams & {
value: Position['updatedAt'];
}) => {
if (!value) {
return '';
}
@@ -1,8 +1,8 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { MarketExpires } from './market-expires';
import SimpleMarketExpires from './simple-market-expires';
describe('MarketExpires', () => {
describe('SimpleMarketExpires', () => {
describe('should properly parse different tags', () => {
it('settlement:date', () => {
const tags = [
@@ -12,7 +12,7 @@ describe('MarketExpires', () => {
'settlement:notadate',
'settlement:20220525T1200',
];
render(<MarketExpires tags={tags} />);
render(<SimpleMarketExpires tags={tags} />);
expect(screen.getByText('May 25')).toBeInTheDocument();
});
@@ -22,7 +22,7 @@ describe('MarketExpires', () => {
'settlement:20220525T1200',
'settlement-date:2022-04-25T1200',
];
render(<MarketExpires tags={tags} />);
render(<SimpleMarketExpires tags={tags} />);
expect(screen.getByText('Apr 25')).toBeInTheDocument();
});
@@ -32,7 +32,7 @@ describe('MarketExpires', () => {
'settlement-date:20220525T1200',
'settlement-expiry-date:2022-03-25T12:00:00',
];
render(<MarketExpires tags={tags} />);
render(<SimpleMarketExpires tags={tags} />);
expect(screen.getByText('Mar 25')).toBeInTheDocument();
});
@@ -42,7 +42,7 @@ describe('MarketExpires', () => {
'settlemenz:20220525T1200',
'settlemenx-date:20220425T1200',
];
const { container } = render(<MarketExpires tags={tags} />);
const { container } = render(<SimpleMarketExpires tags={tags} />);
expect(container.firstChild).toBeNull();
});
});
@@ -0,0 +1,34 @@
import React from 'react';
import { format, isValid, parseISO } from 'date-fns';
import { EXPIRE_DATE_FORMAT } from '../../constants';
const SimpleMarketExpires = ({
tags,
}: {
tags?: ReadonlyArray<string> | null;
}) => {
if (tags) {
const dateFound = tags.reduce<Date | null>((agg, tag) => {
const parsed = parseISO(
(tag.match(/^settlement.*:/) &&
tag
.split(':')
.filter((item, i) => i)
.join(':')) as string
);
if (isValid(parsed)) {
agg = parsed;
}
return agg;
}, null);
return dateFound ? (
<div className="p-2 text-ui-small border border-pink text-pink inline-block">{`${format(
dateFound as Date,
EXPIRE_DATE_FORMAT
)}`}</div>
) : null;
}
return null;
};
export default SimpleMarketExpires;
@@ -4,7 +4,6 @@ import type { AgGridReact } from 'ag-grid-react';
import {
useScreenDimensions,
useDataProvider,
useYesterday,
} from '@vegaprotocol/react-helpers';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import type { MarketState } from '@vegaprotocol/types';
@@ -34,13 +33,13 @@ const SimpleMarketList = () => {
const statusesRef = useRef<Record<string, MarketState | ''>>({});
const gridRef = useRef<AgGridReact | null>(null);
const yesterday = useYesterday();
const variables = useMemo(() => {
const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600;
return {
since: new Date(yesterday).toISOString(),
since: new Date(yesterday * 1000).toISOString(),
interval: Interval.INTERVAL_I1H,
};
}, [yesterday]);
}, []);
const { data, error, loading } = useDataProvider({
dataProvider: marketsWithCandlesProvider,
variables,
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import classNames from 'classnames';
import { InView } from 'react-intersection-observer';
import { useDataProvider, useYesterday } from '@vegaprotocol/react-helpers';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import type { Candle } from '@vegaprotocol/market-list';
import { marketCandlesProvider } from '@vegaprotocol/market-list';
import { Interval } from '@vegaprotocol/types';
@@ -68,13 +68,13 @@ const SimpleMarketPercentChangeWrapper = (props: Props) => {
};
const SimpleMarketPercentChange = ({ candles, marketId, setValue }: Props) => {
const yesterday = useYesterday();
const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600;
const { data } = useDataProvider({
dataProvider: marketCandlesProvider,
variables: {
marketId,
interval: Interval.INTERVAL_I1D,
since: new Date(yesterday).toISOString(),
since: new Date(yesterday * 1000).toISOString(),
},
});
@@ -1,6 +1,6 @@
import classNames from 'classnames';
import SimpleMarketExpires from './simple-market-expires';
import type { Market } from '@vegaprotocol/market-list';
import { MarketExpires } from '@vegaprotocol/market-info';
interface Props {
market: Market;
@@ -19,7 +19,7 @@ const MarketNameRenderer = ({ market, isMobile }: Props) => {
{isMobile
? market.tradableInstrument.instrument.code
: market.tradableInstrument.instrument.name}{' '}
<MarketExpires
<SimpleMarketExpires
tags={market.tradableInstrument.instrument.metadata.tags}
/>
</div>
@@ -15,8 +15,8 @@ import {
} from '@testing-library/react';
import { MockedProvider } from '@apollo/react-testing';
import { MarketState } from '@vegaprotocol/types';
import type { Market } from '@vegaprotocol/market-list';
import SimpleMarketToolbar from './simple-market-toolbar';
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
import { markets as filterData } from './mocks/market-filters.json';
const mockedNavigate = jest.fn();
@@ -35,23 +35,35 @@ describe('SimpleMarketToolbar', () => {
const routes = useRoutes([
{
path: '/',
element: <SimpleMarketToolbar data={filterData as Market[]} />,
element: (
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
),
},
{
path: 'markets',
children: [
{
path: `:state`,
element: <SimpleMarketToolbar data={filterData as Market[]} />,
element: (
<SimpleMarketToolbar
data={filterData as SimpleMarkets_markets[]}
/>
),
children: [
{
path: `:product`,
element: <SimpleMarketToolbar data={filterData as Market[]} />,
element: (
<SimpleMarketToolbar
data={filterData as SimpleMarkets_markets[]}
/>
),
children: [
{
path: `:asset`,
element: (
<SimpleMarketToolbar data={filterData as Market[]} />
<SimpleMarketToolbar
data={filterData as SimpleMarkets_markets[]}
/>
),
},
],
@@ -59,7 +71,9 @@ describe('SimpleMarketToolbar', () => {
],
},
],
element: <SimpleMarketToolbar data={filterData as Market[]} />,
element: (
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
),
},
]);
const location = useLocation();
@@ -152,7 +166,7 @@ describe('SimpleMarketToolbar', () => {
}));
render(
<MockedProvider mocks={[]} addTypename={false}>
<SimpleMarketToolbar data={filterData as Market[]} />
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
</MockedProvider>,
{ wrapper: BrowserRouter }
);
@@ -173,7 +187,7 @@ describe('SimpleMarketToolbar', () => {
(useParams as jest.Mock).mockImplementation(() => ({}));
render(
<MockedProvider mocks={[]} addTypename={false}>
<SimpleMarketToolbar data={filterData as Market[]} />
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
</MockedProvider>,
{ wrapper: BrowserRouter }
);
@@ -197,7 +211,7 @@ describe('SimpleMarketToolbar', () => {
}));
render(
<MockedProvider mocks={[]} addTypename={false}>
<SimpleMarketToolbar data={filterData as Market[]} />
<SimpleMarketToolbar data={filterData as SimpleMarkets_markets[]} />
</MockedProvider>,
{ wrapper: BrowserRouter }
);
@@ -1,4 +1,4 @@
import { useCallback, useMemo, useState } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import classNames from 'classnames';
import { useNavigate, useParams, Link } from 'react-router-dom';
import {
@@ -14,11 +14,11 @@ import {
Icon,
} from '@vegaprotocol/ui-toolkit';
import { MarketState } from '@vegaprotocol/types';
import useMarketFiltersData from '../../hooks/use-markets-filter';
import type { Market } from '@vegaprotocol/market-list';
import { HorizontalMenu } from '../horizontal-menu';
import type { HorizontalMenuItem } from '../horizontal-menu';
import * as constants from './constants';
import { useMarketFilters } from '../../hooks/use-markets-filter';
interface Props {
data: Market[];
@@ -27,7 +27,7 @@ interface Props {
const SimpleMarketToolbar = ({ data }: Props) => {
const navigate = useNavigate();
const params = useParams();
const { products, assetsPerProduct } = useMarketFilters(data);
const { products, assetsPerProduct } = useMarketFiltersData(data);
const [isOpen, setOpen] = useState(false);
const onStateChange = useCallback(
@@ -1,3 +1,4 @@
import React from 'react';
import type { ReactNode } from 'react';
import classNames from 'classnames';
@@ -1,12 +1,13 @@
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import { t } from '@vegaprotocol/react-helpers';
import { Button } from '@vegaprotocol/ui-toolkit';
import * as React from 'react';
import { useContext } from 'react';
import LocalContext from '../../context/local-context';
const ConnectWallet = () => {
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
const {
vegaWalletDialog: { setConnect },
} = useContext(LocalContext);
return (
<section
className="p-8 bg-white-normal dark:bg-offBlack"
@@ -16,7 +17,7 @@ const ConnectWallet = () => {
{t('Please connect your Vega wallet to make a trade')}
</h3>
<div className="mb-4">
<Button variant="primary" onClick={openVegaWalletDialog} size="lg">
<Button variant="primary" onClick={() => setConnect(true)} size="lg">
{t('Connect Vega wallet')}
</Button>
</div>
@@ -3,6 +3,7 @@ import { t } from '@vegaprotocol/react-helpers';
import type { Market } from '@vegaprotocol/market-list';
export const DATE_FORMAT = 'dd MMMM yyyy HH:mm';
export const EXPIRE_DATE_FORMAT = 'MMM dd';
export const TRADABLE_STATES = {
[MarketState.STATE_ACTIVE]: true,
@@ -1,7 +1,9 @@
import { createContext } from 'react';
export interface VegaWalletDialogState {
connect: boolean;
manage: boolean;
setConnect: (isOpen: boolean) => void;
setManage: (isOpen: boolean) => void;
}
@@ -26,6 +26,5 @@ query EstimateOrder(
marginLevels {
initialLevel
}
totalFeeAmount
}
}
@@ -3,9 +3,6 @@ query MarketMarkPrice($marketId: ID!) {
decimalPlaces
data {
markPrice
market {
id
}
}
}
}
@@ -0,0 +1,52 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL query operation: MarketMarkPrice
// ====================================================
export interface MarketMarkPrice_market_data {
__typename: "MarketData";
/**
* The mark price (an unsigned integer)
*/
markPrice: string;
}
export interface MarketMarkPrice_market {
__typename: "Market";
/**
* 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;
/**
* marketData for the given market
*/
data: MarketMarkPrice_market_data | null;
}
export interface MarketMarkPrice {
/**
* An instrument that is trading on the Vega network
*/
market: MarketMarkPrice_market | null;
}
export interface MarketMarkPriceVariables {
marketId: string;
}
@@ -0,0 +1,118 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
import { AccountType } from "@vegaprotocol/types";
// ====================================================
// GraphQL query operation: PartyMarketData
// ====================================================
export interface PartyMarketData_party_accounts_asset {
__typename: "Asset";
/**
* The ID of the asset
*/
id: string;
/**
* The precision of the asset. Should match the decimal precision of the asset on its native chain, e.g: for ERC20 assets, it is often 18
*/
decimals: number;
}
export interface PartyMarketData_party_accounts_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
}
export interface PartyMarketData_party_accounts {
__typename: "Account";
/**
* Account type (General, Margin, etc)
*/
type: AccountType;
/**
* Balance as string - current account balance (approx. as balances can be updated several times per second)
*/
balance: string;
/**
* Asset, the 'currency'
*/
asset: PartyMarketData_party_accounts_asset;
/**
* Market (only relevant to margin accounts)
*/
market: PartyMarketData_party_accounts_market | null;
}
export interface PartyMarketData_party_marginsConnection_edges_node_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
}
export interface PartyMarketData_party_marginsConnection_edges_node {
__typename: "MarginLevels";
/**
* Market in which the margin is required for this party
*/
market: PartyMarketData_party_marginsConnection_edges_node_market;
/**
* This is the minimum margin required for a party to place a new order on the network (unsigned integer)
*/
initialLevel: string;
/**
* Minimal margin for the position to be maintained in the network (unsigned integer)
*/
maintenanceLevel: string;
/**
* If the margin is between maintenance and search, the network will initiate a collateral search (unsigned integer)
*/
searchLevel: string;
}
export interface PartyMarketData_party_marginsConnection_edges {
__typename: "MarginEdge";
node: PartyMarketData_party_marginsConnection_edges_node;
}
export interface PartyMarketData_party_marginsConnection {
__typename: "MarginConnection";
/**
* The margin levels in this connection
*/
edges: PartyMarketData_party_marginsConnection_edges[] | null;
}
export interface PartyMarketData_party {
__typename: "Party";
/**
* Party identifier
*/
id: string;
/**
* Collateral accounts relating to a party
*/
accounts: PartyMarketData_party_accounts[] | null;
/**
* Margin levels for a market
*/
marginsConnection: PartyMarketData_party_marginsConnection | null;
}
export interface PartyMarketData {
/**
* An entity that is trading on the Vega network
*/
party: PartyMarketData_party | null;
}
export interface PartyMarketDataVariables {
partyId: string;
}
@@ -0,0 +1,64 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
import { Side, OrderTimeInForce, OrderType } from "@vegaprotocol/types";
// ====================================================
// GraphQL query operation: EstimateOrder
// ====================================================
export interface EstimateOrder_estimateOrder_fee {
__typename: "TradeFee";
/**
* The maker fee, paid by the aggressive party to the other party (the one who had an order in the book)
*/
makerFee: string;
/**
* The infrastructure fee, a fee paid to the validators to maintain the Vega network
*/
infrastructureFee: string;
/**
* The fee paid to the liquidity providers that committed liquidity to the market
*/
liquidityFee: string;
}
export interface EstimateOrder_estimateOrder_marginLevels {
__typename: "MarginLevels";
/**
* This is the minimum margin required for a party to place a new order on the network (unsigned integer)
*/
initialLevel: string;
}
export interface EstimateOrder_estimateOrder {
__typename: "OrderEstimate";
/**
* The estimated fee if the order was to trade
*/
fee: EstimateOrder_estimateOrder_fee;
/**
* The margin requirement for this order
*/
marginLevels: EstimateOrder_estimateOrder_marginLevels;
}
export interface EstimateOrder {
/**
* Return an estimation of the potential cost for a new order
*/
estimateOrder: EstimateOrder_estimateOrder;
}
export interface EstimateOrderVariables {
marketId: string;
partyId: string;
price?: string | null;
size: string;
side: Side;
timeInForce: OrderTimeInForce;
expiration?: string | null;
type: OrderType;
}
@@ -0,0 +1,109 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
import { AccountType } from "@vegaprotocol/types";
// ====================================================
// GraphQL query operation: MarketPositions
// ====================================================
export interface MarketPositions_party_accounts_asset {
__typename: "Asset";
/**
* The precision of the asset. Should match the decimal precision of the asset on its native chain, e.g: for ERC20 assets, it is often 18
*/
decimals: number;
}
export interface MarketPositions_party_accounts_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
}
export interface MarketPositions_party_accounts {
__typename: "Account";
/**
* Account type (General, Margin, etc)
*/
type: AccountType;
/**
* Balance as string - current account balance (approx. as balances can be updated several times per second)
*/
balance: string;
/**
* Asset, the 'currency'
*/
asset: MarketPositions_party_accounts_asset;
/**
* Market (only relevant to margin accounts)
*/
market: MarketPositions_party_accounts_market | null;
}
export interface MarketPositions_party_positionsConnection_edges_node_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
}
export interface MarketPositions_party_positionsConnection_edges_node {
__typename: "Position";
/**
* Open volume (uint64)
*/
openVolume: string;
/**
* Market relating to this position
*/
market: MarketPositions_party_positionsConnection_edges_node_market;
}
export interface MarketPositions_party_positionsConnection_edges {
__typename: "PositionEdge";
/**
* The position
*/
node: MarketPositions_party_positionsConnection_edges_node;
}
export interface MarketPositions_party_positionsConnection {
__typename: "PositionConnection";
/**
* The positions in this connection
*/
edges: MarketPositions_party_positionsConnection_edges[] | null;
}
export interface MarketPositions_party {
__typename: "Party";
/**
* Party identifier
*/
id: string;
/**
* Collateral accounts relating to a party
*/
accounts: MarketPositions_party_accounts[] | null;
/**
* Trading positions relating to a party
*/
positionsConnection: MarketPositions_party_positionsConnection | null;
}
export interface MarketPositions {
/**
* An entity that is trading on the Vega network
*/
party: MarketPositions_party | null;
}
export interface MarketPositionsVariables {
partyId: string;
}
@@ -15,7 +15,7 @@ export type EstimateOrderQueryVariables = Types.Exact<{
}>;
export type EstimateOrderQuery = { __typename?: 'Query', estimateOrder: { __typename?: 'OrderEstimate', totalFeeAmount: string, fee: { __typename?: 'TradeFee', makerFee: string, infrastructureFee: string, liquidityFee: string }, marginLevels: { __typename?: 'MarginLevels', initialLevel: string } } };
export type EstimateOrderQuery = { __typename?: 'Query', estimateOrder: { __typename?: 'OrderEstimate', fee: { __typename?: 'TradeFee', makerFee: string, infrastructureFee: string, liquidityFee: string }, marginLevels: { __typename?: 'MarginLevels', initialLevel: string } } };
export const EstimateOrderDocument = gql`
@@ -38,7 +38,6 @@ export const EstimateOrderDocument = gql`
marginLevels {
initialLevel
}
totalFeeAmount
}
}
`;
@@ -8,7 +8,7 @@ export type MarketMarkPriceQueryVariables = Types.Exact<{
}>;
export type MarketMarkPriceQuery = { __typename?: 'Query', market?: { __typename?: 'Market', decimalPlaces: number, data?: { __typename?: 'MarketData', markPrice: string, market: { __typename?: 'Market', id: string } } | null } | null };
export type MarketMarkPriceQuery = { __typename?: 'Query', market?: { __typename?: 'Market', decimalPlaces: number, data?: { __typename?: 'MarketData', markPrice: string } | null } | null };
export const MarketMarkPriceDocument = gql`
@@ -17,9 +17,6 @@ export const MarketMarkPriceDocument = gql`
decimalPlaces
data {
markPrice
market {
id
}
}
}
}
@@ -8,7 +8,7 @@ export type MarketPositionsQueryVariables = Types.Exact<{
}>;
export type MarketPositionsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accounts?: Array<{ __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', decimals: number }, market?: { __typename?: 'Market', id: string } | null }> | null, positionsConnection?: { __typename?: 'PositionConnection', edges?: Array<{ __typename?: 'PositionEdge', node: { __typename?: 'Position', openVolume: string, market: { __typename?: 'Market', id: string } } }> | null } | null } | null };
export type MarketPositionsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', decimals: number }, market?: { __typename?: 'Market', id: string } | null }> | null, positionsConnection?: { __typename?: 'PositionConnection', edges?: Array<{ __typename?: 'PositionEdge', node: { __typename?: 'Position', openVolume: string, market: { __typename?: 'Market', id: string } } }> | null } | null } | null };
export const MarketPositionsDocument = gql`
@@ -8,7 +8,7 @@ export type PartyMarketDataQueryVariables = Types.Exact<{
}>;
export type PartyMarketDataQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accounts?: Array<{ __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, decimals: number }, market?: { __typename?: 'Market', id: string } | null }> | null, marginsConnection?: { __typename?: 'MarginConnection', edges?: Array<{ __typename?: 'MarginEdge', node: { __typename?: 'MarginLevels', initialLevel: string, maintenanceLevel: string, searchLevel: string, market: { __typename?: 'Market', id: string } } }> | null } | null } | null };
export type PartyMarketDataQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, decimals: number }, market?: { __typename?: 'Market', id: string } | null }> | null, marginsConnection?: { __typename?: 'MarginConnection', edges?: Array<{ __typename?: 'MarginEdge', node: { __typename?: 'MarginLevels', initialLevel: string, maintenanceLevel: string, searchLevel: string, market: { __typename?: 'Market', id: string } } }> | null } | null } | null };
export const PartyMarketDataDocument = gql`
@@ -1,8 +1,8 @@
import { MockedProvider } from '@apollo/client/testing';
import { renderHook } from '@testing-library/react';
import { Schema } from '@vegaprotocol/types';
import { Side } from '@vegaprotocol/types';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useCalculateSlippage } from './use-calculate-slippage';
import useCalculateSlippage from './use-calculate-slippage';
const mockData = {
decimalPlaces: 0,
@@ -59,6 +59,11 @@ let mockOrderBookData = {
data: mockData,
};
jest.mock('@vegaprotocol/market-depth', () => ({
...jest.requireActual('@vegaprotocol/market-depth'),
useOrderBookData: jest.fn(() => mockOrderBookData),
}));
jest.mock('@vegaprotocol/react-helpers', () => ({
...jest.requireActual('@vegaprotocol/react-helpers'),
useDataProvider: jest.fn(() => ({
@@ -66,7 +71,6 @@ jest.mock('@vegaprotocol/react-helpers', () => ({
marketsConnection: [],
},
})),
useThrottledDataProvider: jest.fn(() => mockOrderBookData),
}));
describe('useCalculateSlippage Hook', () => {
@@ -82,7 +86,7 @@ describe('useCalculateSlippage Hook', () => {
marketId: 'marketId',
order: {
size: '10',
side: Schema.Side.SIDE_BUY,
side: Side.SIDE_BUY,
} as OrderSubmissionBody['orderSubmission'],
}),
{
@@ -99,7 +103,7 @@ describe('useCalculateSlippage Hook', () => {
marketId: 'marketId',
order: {
size: '10',
side: Schema.Side.SIDE_SELL,
side: Side.SIDE_SELL,
} as OrderSubmissionBody['orderSubmission'],
}),
{
@@ -125,7 +129,7 @@ describe('useCalculateSlippage Hook', () => {
marketId: 'marketId',
order: {
size: '10',
side: Schema.Side.SIDE_SELL,
side: Side.SIDE_SELL,
} as OrderSubmissionBody['orderSubmission'],
}),
{
@@ -1,15 +1,14 @@
import { useMemo } from 'react';
import { marketDepthProvider } from '@vegaprotocol/market-depth';
import { Schema } from '@vegaprotocol/types';
import { Side } from '@vegaprotocol/types';
import { useOrderBookData } from '@vegaprotocol/market-depth';
import { marketProvider } from '@vegaprotocol/market-list';
import type { SingleMarketFieldsFragment } from '@vegaprotocol/market-list';
import type { Market } from '@vegaprotocol/market-list';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { BigNumber } from 'bignumber.js';
import {
formatNumber,
toBigNum,
useDataProvider,
useThrottledDataProvider,
} from '@vegaprotocol/react-helpers';
interface Props {
@@ -17,22 +16,19 @@ interface Props {
order: OrderSubmissionBody['orderSubmission'];
}
export const useCalculateSlippage = ({ marketId, order }: Props) => {
const useCalculateSlippage = ({ marketId, order }: Props) => {
const variables = useMemo(() => ({ marketId }), [marketId]);
const { data } = useThrottledDataProvider(
{
dataProvider: marketDepthProvider,
variables,
},
5000
);
const { data: market } = useDataProvider<SingleMarketFieldsFragment, never>({
const { data } = useOrderBookData({
variables,
throttleMilliseconds: 5000,
});
const { data: market } = useDataProvider<Market, never>({
dataProvider: marketProvider,
noUpdate: true,
variables,
});
const volPriceArr =
data?.depth[order.side === Schema.Side.SIDE_BUY ? 'sell' : 'buy'] || [];
data?.depth[order.side === Side.SIDE_BUY ? 'sell' : 'buy'] || [];
if (volPriceArr.length && market) {
const decimals = market.decimalPlaces ?? 0;
const positionDecimals = market.positionDecimalPlaces ?? 0;
@@ -73,3 +69,5 @@ export const useCalculateSlippage = ({ marketId, order }: Props) => {
}
return null;
};
export default useCalculateSlippage;
@@ -7,9 +7,12 @@ describe('local values hook', () => {
const { result } = renderHook(() => useLocalValues('light', setTheme));
expect(result.current.vegaWalletDialog).toBeDefined();
expect(result.current.vegaWalletDialog.manage).toBe(false);
expect(result.current.vegaWalletDialog.connect).toBe(false);
act(() => {
result.current.vegaWalletDialog.setConnect(true);
result.current.vegaWalletDialog.setManage(true);
});
expect(result.current.vegaWalletDialog.manage).toBe(true);
expect(result.current.vegaWalletDialog.connect).toBe(true);
});
});
@@ -2,16 +2,17 @@ import { useMemo, useState } from 'react';
import type { LocalValues } from '../context/local-context';
const useLocalValues = (theme: 'light' | 'dark', toggleTheme: () => void) => {
const [connect, setConnect] = useState<boolean>(false);
const [manage, setManage] = useState<boolean>(false);
const [menuOpen, setMenuOpen] = useState(false);
return useMemo<LocalValues>(
() => ({
vegaWalletDialog: { manage, setManage },
vegaWalletDialog: { connect, manage, setConnect, setManage },
menu: { menuOpen, setMenuOpen, onToggle: () => setMenuOpen(!menuOpen) },
theme,
toggleTheme,
}),
[manage, theme, toggleTheme, menuOpen]
[connect, manage, theme, toggleTheme, menuOpen]
);
};
@@ -0,0 +1,38 @@
import { gql, useQuery } from '@apollo/client';
import { useMemo, useRef } from 'react';
import type {
MarketMarkPrice,
MarketMarkPriceVariables,
} from './__generated__/MarketMarkPrice';
const MARKET_MARK_PRICE = gql`
query MarketMarkPrice($marketId: ID!) {
market(id: $marketId) {
decimalPlaces
data {
markPrice
}
}
}
`;
export default (marketId: string) => {
const memoRef = useRef<MarketMarkPrice | null>(null);
const { data } = useQuery<MarketMarkPrice, MarketMarkPriceVariables>(
MARKET_MARK_PRICE,
{
pollInterval: 5000,
variables: { marketId },
skip: !marketId,
}
);
return useMemo(() => {
if (
data &&
data.market?.data?.markPrice !== memoRef.current?.market?.data?.markPrice
) {
memoRef.current = data;
}
return memoRef.current;
}, [data, memoRef]);
};
@@ -1,5 +1,5 @@
import { renderHook } from '@testing-library/react';
import { useMarketPositions } from './use-market-positions';
import useMarketPositions from './use-market-positions';
let mockNotEmptyData = {
party: {
@@ -0,0 +1,78 @@
import { gql, useQuery } from '@apollo/client';
import { BigNumber } from 'bignumber.js';
import type {
MarketPositions,
MarketPositionsVariables,
} from './__generated__/marketPositions';
const MARKET_POSITIONS_QUERY = gql`
query MarketPositions($partyId: ID!) {
party(id: $partyId) {
id
accounts {
type
balance
asset {
decimals
}
market {
id
}
}
positionsConnection {
edges {
node {
openVolume
market {
id
}
}
}
}
}
}
`;
interface Props {
marketId: string;
partyId: string;
}
export type PositionMargin = {
openVolume: BigNumber;
balance: BigNumber;
balanceDecimals?: number;
} | null;
export default ({ marketId, partyId }: Props): PositionMargin => {
const { data } = useQuery<MarketPositions, MarketPositionsVariables>(
MARKET_POSITIONS_QUERY,
{
pollInterval: 5000,
variables: { partyId },
skip: !partyId,
fetchPolicy: 'no-cache',
}
);
const account = data?.party?.accounts?.find(
(nodes) => nodes.market?.id === marketId
);
if (account) {
const balance = new BigNumber(account.balance || 0);
const openVolume = new BigNumber(
data?.party?.positionsConnection?.edges?.find(
(nodes) => nodes.node.market.id === marketId
)?.node.openVolume || 0
);
if (!balance.isZero() && !openVolume.isZero()) {
return {
balance,
balanceDecimals: account?.asset.decimals,
openVolume,
};
}
}
return null;
};
@@ -1,7 +1,7 @@
import type { Market } from '@vegaprotocol/market-list';
import { useEffect, useState } from 'react';
export const useMarketFilters = (data: Market[]) => {
const useMarketFilters = (data: Market[]) => {
const [products, setProducts] = useState<string[]>([]);
const [assetsPerProduct, setAssetsPerProduct] = useState<
Record<string, string[]>
@@ -36,3 +36,5 @@ export const useMarketFilters = (data: Market[]) => {
}, [data]);
return { products, assetsPerProduct };
};
export default useMarketFilters;
@@ -1,10 +1,14 @@
import { renderHook } from '@testing-library/react';
import { AccountType, Schema } from '@vegaprotocol/types';
import useMaximumPositionSize from './use-maximum-position-size';
import type { PartyBalanceQuery_party_accounts } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
import {
AccountType,
OrderTimeInForce,
OrderType,
Side,
} from '@vegaprotocol/types';
import type { PositionMargin } from './use-market-positions';
import { BigNumber } from 'bignumber.js';
import { useMaximumPositionSize } from './use-maximum-position-size';
import type { AccountFragment as Account } from './__generated__/PartyBalance';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
const defaultMockMarketPositions = {
openVolume: new BigNumber(1),
@@ -13,8 +17,8 @@ const defaultMockMarketPositions = {
let mockMarketPositions: PositionMargin | null = defaultMockMarketPositions;
const mockAccount: Account = {
__typename: 'AccountBalance',
const mockAccount: PartyBalanceQuery_party_accounts = {
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '200000',
asset: {
@@ -26,12 +30,11 @@ const mockAccount: Account = {
},
};
const mockOrder: OrderSubmissionBody['orderSubmission'] = {
type: Schema.OrderType.TYPE_MARKET,
const mockOrder = {
type: OrderType.TYPE_MARKET,
size: '1',
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
marketId: 'market-id',
side: Side.SIDE_BUY,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_IOC,
};
jest.mock('./use-settlement-account', () => {
@@ -39,18 +42,9 @@ jest.mock('./use-settlement-account', () => {
useSettlementAccount: jest.fn(() => mockAccount),
};
});
jest.mock('./use-market-positions', () => jest.fn(() => mockMarketPositions));
jest.mock('./use-market-positions', () => ({
useMarketPositions: ({
marketId,
partyId,
}: {
marketId: string;
partyId: string;
}) => mockMarketPositions,
}));
describe('useMaximumPositionSize', () => {
describe('useMaximumPositionSize Hook', () => {
it('should return correct size when no open positions', () => {
mockMarketPositions = null;
const price = '50';
@@ -87,7 +81,7 @@ describe('useMaximumPositionSize', () => {
it('should return correct size when open positions and opposite side', () => {
const price = '50';
mockOrder.side = Schema.Side.SIDE_SELL;
mockOrder.side = Side.SIDE_SELL;
mockMarketPositions = defaultMockMarketPositions;
const expected = 4001;
const { result } = renderHook(() =>
@@ -1,13 +1,13 @@
import { useMarketPositions } from './use-market-positions';
import useMarketPositions from './use-market-positions';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { PartyBalanceQuery_party_accounts } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
import { useSettlementAccount } from './use-settlement-account';
import { AccountType, Schema } from '@vegaprotocol/types';
import { AccountType, Side } from '@vegaprotocol/types';
import { BigNumber } from 'bignumber.js';
import type { AccountFragment as Account } from './__generated__/PartyBalance';
interface Props {
partyId: string;
accounts: Account[];
accounts: PartyBalanceQuery_party_accounts[];
marketId: string;
price?: string;
settlementAssetId: string;
@@ -17,7 +17,7 @@ interface Props {
const getSize = (balance: string, price: string) =>
new BigNumber(balance).dividedBy(new BigNumber(price));
export const useMaximumPositionSize = ({
export default ({
marketId,
accounts,
partyId,
@@ -47,10 +47,8 @@ export const useMaximumPositionSize = ({
}
const isSameSide =
(marketPositions.openVolume.isPositive() &&
order.side === Schema.Side.SIDE_BUY) ||
(marketPositions.openVolume.isNegative() &&
order.side === Schema.Side.SIDE_SELL);
(marketPositions.openVolume.isPositive() && order.side === Side.SIDE_BUY) ||
(marketPositions.openVolume.isNegative() && order.side === Side.SIDE_SELL);
const adjustedForVolume = new BigNumber(size)[isSameSide ? 'minus' : 'plus'](
marketPositions.openVolume
@@ -1,17 +1,17 @@
import * as React from 'react';
import { renderHook } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import useOrderCloseOut from './use-order-closeout';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { PartyBalanceQuery } from './__generated__/PartyBalance';
import { useOrderCloseOut } from './use-order-closeout';
import type { DealTicketMarketFragment } from '../components/deal-ticket/__generated___/DealTicket';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import type { PartyBalanceQuery } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'),
useVegaWallet: jest.fn().mockReturnValue('wallet-pub-key'),
}));
describe('useOrderCloseOut', () => {
describe('useOrderCloseOut Hook', () => {
const order = { size: '2', side: 'SIDE_BUY' };
const market = {
decimalPlaces: 5,
@@ -44,7 +44,7 @@ describe('useOrderCloseOut', () => {
},
};
it('should return proper null value', () => {
it('return proper buy value', () => {
const { result } = renderHook(
() =>
useOrderCloseOut({
@@ -58,10 +58,10 @@ describe('useOrderCloseOut', () => {
),
}
);
expect(result.current).toEqual(null);
expect(result.current).toEqual(' - ');
});
it('should return proper sell value', () => {
it('return proper sell value', () => {
const { result } = renderHook(
() =>
useOrderCloseOut({
@@ -81,7 +81,7 @@ describe('useOrderCloseOut', () => {
expect(result.current).toEqual('1.00000');
});
it('should return proper empty value', () => {
it('return proper empty value', () => {
const { result } = renderHook(
() =>
useOrderCloseOut({
@@ -1,14 +1,49 @@
import { BigNumber } from 'bignumber.js';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import type { PartyBalanceQuery } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
import { useSettlementAccount } from './use-settlement-account';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { addDecimal, formatNumber } from '@vegaprotocol/react-helpers';
import { useMarketPositions } from './use-market-positions';
import { useMarketDataMarkPrice } from './use-market-data-mark-price';
import { usePartyMarketDataQuery } from './__generated__/PartyMarketData';
import { Schema } from '@vegaprotocol/types';
import type { DealTicketMarketFragment } from '../components/deal-ticket/__generated___/DealTicket';
import type { PartyBalanceQuery } from './__generated__/PartyBalance';
import { useSettlementAccount } from './use-settlement-account';
import { gql, useQuery } from '@apollo/client';
import useMarketPositions from './use-market-positions';
import useMarketData from './use-market-data';
import type {
PartyMarketData,
PartyMarketDataVariables,
} from './__generated__/PartyMarketData';
import { Side } from '@vegaprotocol/types';
const CLOSEOUT_PRICE_QUERY = gql`
query PartyMarketData($partyId: ID!) {
party(id: $partyId) {
id
accounts {
type
balance
asset {
id
decimals
}
market {
id
}
}
marginsConnection {
edges {
node {
market {
id
}
initialLevel
maintenanceLevel
searchLevel
}
}
}
}
}
`;
interface Props {
order: OrderSubmissionBody['orderSubmission'];
@@ -16,23 +51,22 @@ interface Props {
partyData?: PartyBalanceQuery;
}
export const useOrderCloseOut = ({
order,
market,
partyData,
}: Props): string | null => {
const useOrderCloseOut = ({ order, market, partyData }: Props): string => {
const { pubKey } = useVegaWallet();
const account = useSettlementAccount(
market.tradableInstrument.instrument.product.settlementAsset.id,
partyData?.party?.accounts || []
);
const { data } = usePartyMarketDataQuery({
pollInterval: 5000,
variables: { partyId: pubKey || '' },
skip: !pubKey,
});
const { data } = useQuery<PartyMarketData, PartyMarketDataVariables>(
CLOSEOUT_PRICE_QUERY,
{
pollInterval: 5000,
variables: { partyId: pubKey || '' },
skip: !pubKey,
}
);
const markPriceData = useMarketDataMarkPrice(market.id);
const markPriceData = useMarketData(market.id);
const marketPositions = useMarketPositions({
marketId: market.id,
partyId: pubKey || '',
@@ -60,10 +94,10 @@ export const useOrderCloseOut = ({
);
const volume = new BigNumber(
addDecimal(
marketPositions?.openVolume.toString() || '0',
marketPositions?.openVolume.toNumber() || 0,
market.positionDecimalPlaces
)
)[order.side === Schema.Side.SIDE_BUY ? 'plus' : 'minus'](order.size);
)[order.side === Side.SIDE_BUY ? 'plus' : 'minus'](order.size);
const markPrice = new BigNumber(
addDecimal(
markPriceData?.market?.data?.markPrice || 0,
@@ -78,5 +112,7 @@ export const useOrderCloseOut = ({
if (closeOut.isPositive()) {
return formatNumber(closeOut, market.decimalPlaces);
}
return null;
return ' - ';
};
export default useOrderCloseOut;
@@ -2,9 +2,9 @@ import { renderHook } from '@testing-library/react';
import { useQuery } from '@apollo/client';
import { BigNumber } from 'bignumber.js';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import type { PositionMargin } from './use-market-positions';
import { useOrderMargin } from './use-order-margin';
import type { DealTicketMarketFragment } from '../components/deal-ticket/__generated___/DealTicket';
import useOrderMargin from './use-order-margin';
let mockEstimateData = {
estimateOrder: {
@@ -27,18 +27,9 @@ let mockMarketPositions: PositionMargin = {
openVolume: new BigNumber(1),
balance: new BigNumber(100000),
};
jest.mock('./use-market-positions', () => jest.fn(() => mockMarketPositions));
jest.mock('./use-market-positions', () => ({
useMarketPositions: ({
marketId,
partyId,
}: {
marketId: string;
partyId: string;
}) => mockMarketPositions,
}));
describe('useOrderMargin', () => {
describe('useOrderMargin Hook', () => {
const order = {
size: '2',
side: 'SIDE_BUY',
@@ -59,7 +50,7 @@ describe('useOrderMargin', () => {
jest.clearAllMocks();
});
it('should calculate margin correctly', () => {
it('margin should be properly calculated', () => {
const { result } = renderHook(() =>
useOrderMargin({
order: order as OrderSubmissionBody['orderSubmission'],
@@ -77,7 +68,7 @@ describe('useOrderMargin', () => {
);
});
it('should calculate fees correctly', () => {
it('fees should be properly calculated', () => {
const { result } = renderHook(() =>
useOrderMargin({
order: order as OrderSubmissionBody['orderSubmission'],
@@ -85,10 +76,10 @@ describe('useOrderMargin', () => {
partyId,
})
);
expect(result.current?.totalFees).toEqual('300000');
expect(result.current?.fees).toEqual('300000');
});
it('should not subtract initialMargin if there is no position', () => {
it('if there is no positions initialMargin should not be subtracted', () => {
mockMarketPositions = null;
const { result } = renderHook(() =>
useOrderMargin({
@@ -104,7 +95,7 @@ describe('useOrderMargin', () => {
);
});
it('should return empty value if API fails', () => {
it('if api fails, should return empty value', () => {
mockEstimateData = {
estimateOrder: {
fee: {
@@ -0,0 +1,119 @@
import { BigNumber } from 'bignumber.js';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { gql, useQuery } from '@apollo/client';
import type {
EstimateOrder,
EstimateOrderVariables,
EstimateOrder_estimateOrder_fee,
} from './__generated__/estimateOrder';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import { Side } from '@vegaprotocol/types';
import { addDecimal, removeDecimal } from '@vegaprotocol/react-helpers';
import useMarketPositions from './use-market-positions';
import useMarketData from './use-market-data';
export const ESTIMATE_ORDER_QUERY = gql`
query EstimateOrder(
$marketId: ID!
$partyId: ID!
$price: String
$size: String!
$side: Side!
$timeInForce: OrderTimeInForce!
$expiration: String
$type: OrderType!
) {
estimateOrder(
marketId: $marketId
partyId: $partyId
price: $price
size: $size
side: $side
timeInForce: $timeInForce
expiration: $expiration
type: $type
) {
fee {
makerFee
infrastructureFee
liquidityFee
}
marginLevels {
initialLevel
}
}
}
`;
interface Props {
order: OrderSubmissionBody['orderSubmission'];
market: DealTicketMarketFragment;
partyId: string;
}
const addFees = (feeObj: EstimateOrder_estimateOrder_fee) => {
return new BigNumber(feeObj.makerFee)
.plus(feeObj.liquidityFee)
.plus(feeObj.infrastructureFee);
};
export interface OrderMargin {
margin: string;
fees: string | null;
}
const useOrderMargin = ({
order,
market,
partyId,
}: Props): OrderMargin | null => {
const marketPositions = useMarketPositions({ marketId: market.id, partyId });
const markPriceData = useMarketData(market.id);
const { data } = useQuery<EstimateOrder, EstimateOrderVariables>(
ESTIMATE_ORDER_QUERY,
{
variables: {
marketId: market.id,
partyId,
price: markPriceData?.market?.data?.markPrice || '',
size: removeDecimal(
BigNumber.maximum(
0,
new BigNumber(marketPositions?.openVolume || 0)[
order.side === Side.SIDE_BUY ? 'plus' : 'minus'
](order.size)
).toString(),
market.positionDecimalPlaces
),
side: order.side === Side.SIDE_BUY ? Side.SIDE_BUY : Side.SIDE_SELL,
timeInForce: order.timeInForce,
type: order.type,
},
skip:
!partyId ||
!market.id ||
!order.size ||
!markPriceData?.market?.data?.markPrice,
}
);
if (data?.estimateOrder.marginLevels.initialLevel) {
const fees =
data?.estimateOrder?.fee && addFees(data.estimateOrder.fee).toString();
return {
margin: addDecimal(
BigNumber.maximum(
0,
new BigNumber(data.estimateOrder.marginLevels.initialLevel).minus(
marketPositions?.balance || 0
)
).toString(),
market.decimalPlaces
),
fees: addDecimal(fees, market.decimalPlaces),
};
}
return null;
};
export default useOrderMargin;
@@ -1,13 +1,13 @@
import { renderHook } from '@testing-library/react';
import { useSettlementAccount } from './use-settlement-account';
import type { PartyBalanceQuery_party_accounts } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
import { AccountType } from '@vegaprotocol/types';
import type { AccountFragment as Account } from './__generated__/PartyBalance';
describe('useSettlementAccount Hook', () => {
it('should filter accounts by settlementAssetId', () => {
const accounts: Account[] = [
const accounts: PartyBalanceQuery_party_accounts[] = [
{
__typename: 'AccountBalance',
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '2000000000000000000000',
asset: {
@@ -19,7 +19,7 @@ describe('useSettlementAccount Hook', () => {
},
},
{
__typename: 'AccountBalance',
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '1000000000',
asset: {
@@ -31,7 +31,7 @@ describe('useSettlementAccount Hook', () => {
},
},
{
__typename: 'AccountBalance',
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '5000000000000000000',
asset: {
@@ -43,7 +43,7 @@ describe('useSettlementAccount Hook', () => {
},
},
{
__typename: 'AccountBalance',
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_MARGIN,
balance: '5000000000000000000',
asset: {
@@ -75,12 +75,12 @@ describe('useSettlementAccount Hook', () => {
});
it('should return null if no accounts', () => {
const accounts: Account[] = [];
const accounts: PartyBalanceQuery_party_accounts[] = [];
const settlementAssetId =
'6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61';
const { result } = renderHook(() =>
useSettlementAccount(settlementAssetId, accounts)
);
expect(result.current).toBe(null);
expect(result.current).toBe(undefined);
});
});
@@ -1,12 +1,12 @@
import type { PartyBalanceQuery_party_accounts } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
import type { AccountType } from '@vegaprotocol/types';
import { useMemo } from 'react';
import type { AccountFragment as Account } from './__generated__/PartyBalance';
export const useSettlementAccount = (
settlementAssetId: string,
accounts: Account[],
accounts: PartyBalanceQuery_party_accounts[],
type?: AccountType
): Account | null => {
): PartyBalanceQuery_party_accounts | null => {
const callback = () =>
accounts.find((account) => {
if (type) {
@@ -16,5 +16,5 @@ export const useSettlementAccount = (
return account.asset.id === settlementAssetId;
});
const account = useMemo(callback, [accounts, settlementAssetId, type]);
return account || null;
return account as PartyBalanceQuery_party_accounts;
};
+4 -2
View File
@@ -3,9 +3,11 @@
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node", "@testing-library/jest-dom"]
"types": ["jest", "node", "@testing-library/jest-dom"],
"jsx": "react",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
},
"files": ["../../node_modules/@nrwl/react/typings/cssmodule.d.ts"],
"include": [
"**/*.test.ts",
"**/*.spec.ts",
+2 -1
View File
@@ -10,7 +10,7 @@ module.exports = defineConfig({
},
baseUrl: 'http://localhost:3000',
fileServerFolder: '.',
fixturesFolder: './src/fixtures',
fixturesFolder: false,
specPattern: '**/*.cy.{js,jsx,ts,tsx}',
modifyObstructiveCode: false,
supportFile: './src/support/index.js',
@@ -27,6 +27,7 @@ module.exports = defineConfig({
networkQueryUrl: 'http://localhost:3028/query',
ethUrl: 'https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
commitHash: 'dev',
CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS: true,
tsConfig: 'tsconfig.json',
grepTags: '@regression @smoke @slow',
grepFilterSpecs: true,
@@ -1,121 +0,0 @@
{
"eighteenDecimal": [
"governance.proposal.asset.minProposerBalance",
"governance.proposal.asset.minVoterBalance",
"governance.proposal.freeform.minProposerBalance",
"governance.proposal.freeform.minVoterBalance",
"governance.proposal.market.minProposerBalance",
"governance.proposal.market.minVoterBalance",
"governance.proposal.updateMarket.minProposerBalance",
"governance.proposal.updateMarket.minVoterBalance",
"governance.proposal.updateNetParam.minProposerBalance",
"governance.proposal.updateNetParam.minVoterBalance",
"reward.staking.delegation.maxPayoutPerEpoch",
"reward.staking.delegation.maxPayoutPerParticipant",
"reward.staking.delegation.minimumValidatorStake",
"spam.protection.delegation.min.tokens",
"spam.protection.proposal.min.tokens",
"spam.protection.voting.min.tokens",
"validators.delegation.minAmount"
],
"fiveDecimal": [
"governance.proposal.updateAsset.minProposerBalance",
"governance.proposal.updateAsset.minVoterBalance",
"governance.proposal.updateAsset.requiredParticipation",
"governance.proposal.updateMarket.minProposerEquityLikeShare",
"market.fee.factors.infrastructureFee",
"market.fee.factors.makerFee",
"market.liquidity.bondPenaltyParameter",
"market.liquidity.maximumLiquidityFeeFactorLevel",
"market.liquidity.minimum.probabilityOfTrading.lpOrders",
"market.liquidity.probabilityOfTrading.tau.scaling",
"market.liquidity.stakeToCcySiskas",
"market.liquidity.targetstake.triggering.ratio",
"market.liquidityProvision.minLpStakeQuantumMultiple",
"market.liquidityProvision.shapes.maxSize",
"market.stake.target.scalingFactor",
"network.validators.ersatz.multipleOfTendermintValidators",
"network.validators.ersatz.rewardFactor",
"network.validators.incumbentBonus",
"network.validators.minimumEthereumEventsForNewValidator",
"network.validators.multisig.numberOfSigners",
"network.validators.tendermint.number",
"reward.staking.delegation.competitionLevel",
"reward.staking.delegation.delegatorShare",
"reward.staking.delegation.minValidators",
"reward.staking.delegation.optimalStakeMultiplier",
"reward.staking.delegation.payoutFraction",
"rewards.marketCreationQuantumMultiple",
"spam.pow.difficulty",
"spam.pow.increaseDifficulty",
"spam.pow.numberOfPastBlocks",
"spam.pow.numberOfTxPerBlock",
"spam.protection.max.batchSize",
"spam.protection.max.delegations",
"spam.protection.max.proposals",
"spam.protection.max.votes",
"spam.protection.maxUserTransfersPerEpoch",
"transfer.fee.factor",
"transfer.minTransferQuantumMultiple",
"snapshot.interval.length"
],
"json": [
"blockchains.ethereumConfig",
"market.margin.scalingFactors",
"market.monitor.price.defaultParameters"
],
"percentage": [
"governance.proposal.asset.requiredMajority",
"governance.proposal.asset.requiredParticipation",
"governance.proposal.freeform.requiredMajority",
"governance.proposal.freeform.requiredParticipation",
"governance.proposal.market.requiredMajority",
"governance.proposal.market.requiredParticipation",
"governance.proposal.updateMarket.requiredMajority",
"governance.proposal.updateMarket.requiredMajorityLP",
"governance.proposal.updateMarket.requiredParticipation",
"governance.proposal.updateMarket.requiredParticipationLP",
"governance.proposal.updateNetParam.requiredMajority",
"governance.proposal.updateNetParam.requiredParticipation",
"validators.vote.required"
],
"duration": [
"governance.proposal.asset.maxClose",
"governance.proposal.asset.maxEnact",
"governance.proposal.asset.minClose",
"governance.proposal.asset.minEnact",
"governance.proposal.freeform.maxClose",
"governance.proposal.freeform.minClose",
"governance.proposal.market.maxClose",
"governance.proposal.market.maxEnact",
"governance.proposal.market.minClose",
"governance.proposal.market.minEnact",
"governance.proposal.updateAsset.maxClose",
"governance.proposal.updateAsset.maxEnact",
"governance.proposal.updateAsset.minClose",
"governance.proposal.updateAsset.minEnact",
"governance.proposal.updateMarket.maxClose",
"governance.proposal.updateMarket.maxEnact",
"governance.proposal.updateMarket.minClose",
"governance.proposal.updateMarket.minEnact",
"governance.proposal.updateNetParam.maxClose",
"governance.proposal.updateNetParam.maxEnact",
"governance.proposal.updateNetParam.minClose",
"governance.proposal.updateNetParam.minEnact",
"market.auction.maximumDuration",
"market.auction.minimumDuration",
"market.liquidity.providers.fee.distributionTimeStep",
"market.stake.target.timeWindow",
"market.value.windowLength",
"network.checkpoint.timeElapsedBetweenCheckpoints",
"network.floatingPointUpdates.delay",
"reward.staking.delegation.payoutDelay",
"spam.pow.hashFunction",
"validators.epoch.length"
],
"date": [
"limits.assets.proposeEnabledFrom",
"limits.markets.proposeEnabledFrom"
],
"id": ["reward.asset"]
}
+57 -84
View File
@@ -1,8 +1,4 @@
context('Asset page', { tags: '@regression' }, function () {
before('gather system asset information', function () {
cy.get_asset_information().as('assetsInfo');
});
describe('Verify elements on page', function () {
const assetsNavigation = 'a[href="/assets"]';
const assetHeader = '[data-testid="asset-header"]';
@@ -11,63 +7,59 @@ context('Asset page', { tags: '@regression' }, function () {
before('Navigate to assets page', function () {
cy.visit('/');
cy.get(assetsNavigation).click();
// Check we have enough enough assets
const assetNames = Object.keys(this.assetsInfo);
assert.isAtLeast(
assetNames.length,
5,
'Ensuring we have at least 5 assets to test'
);
});
it('should be able to see assets page sections', function () {
const assetNames = Object.keys(this.assetsInfo);
assetNames.forEach((assetName) => {
cy.get(assetHeader)
.contains(assetName)
.should('be.visible')
.next()
.within(() => {
cy.get(jsonSection).should('not.be.empty');
});
});
it('Assets page is displayed', function () {
cy.common_validate_blocks_data_displayed(assetHeader);
});
it('should be able to see all asset details displayed in JSON', function () {
const assetNames = Object.keys(this.assetsInfo);
assetNames.forEach((assetName) => {
cy.get(assetHeader)
.contains(assetName)
.next()
.within(() => {
cy.get(jsonSection)
.invoke('text')
.convert_string_json_to_js_object()
.then((assetsListedInJson) => {
const assetInfo = this.assetsInfo[assetName];
assert.equal(assetsListedInJson.name, assetInfo.name);
assert.equal(assetsListedInJson.id, assetInfo.id);
assert.equal(assetsListedInJson.decimals, assetInfo.decimals);
assert.equal(assetsListedInJson.symbol, assetInfo.symbol);
assert.equal(
assetsListedInJson.source.__typename,
assetInfo.source.__typename
it('Assets and all asset details are displayed', function () {
cy.get_asset_information().then((assetsInfo) => {
const assetNames = Object.keys(assetsInfo);
assert.isAtLeast(
assetNames.length,
3,
'Ensuring we have at least 3 assets to test'
);
assetNames.forEach((assetName) => {
const assetInfo = assetsInfo[assetName];
cy.get(assetHeader).contains(assetInfo.symbol);
cy.get(assetHeader)
.contains(assetName)
.next()
.within(() => {
cy.get(jsonSection).within(() => {
cy.contains(`"name": "${assetName}"`).should('be.visible');
cy.contains(`"id": "${assetInfo.id}"`).should('be.visible');
cy.contains(`"decimals": ${assetInfo.decimals}`).should(
'be.visible'
);
cy.contains(`"symbol": "${assetInfo.symbol}"`).should(
'be.visible'
);
cy.contains(
`"__typename": "${assetInfo.infrastructureFeeAccount.__typename}"`
).should('be.visible');
cy.contains(
`"type": "${assetInfo.infrastructureFeeAccount.type}"`
).should('be.visible');
cy.contains(
`"balance": "${assetInfo.infrastructureFeeAccount.balance}"`
).should('be.visible');
cy.contains(
`"__typename": "${assetInfo.source.__typename}"`
).should('be.visible');
if (assetInfo.source.__typename == 'ERC20') {
assert.equal(
assetsListedInJson.source.contractAddress,
assetInfo.source.contractAddress
);
cy.contains(
`"contractAddress": "${assetInfo.source.contractAddress}"`
).should('be.visible');
}
if (assetInfo.source.__typename == 'BuiltinAsset') {
assert.equal(
assetsListedInJson.source.maxFaucetAmountMint,
assetInfo.source.maxFaucetAmountMint
);
cy.contains(
`"maxFaucetAmountMint": "${assetInfo.source.maxFaucetAmountMint}"`
).should('be.visible');
}
let knownAssetTypes = ['BuiltinAsset', 'ERC20'];
@@ -75,37 +67,28 @@ context('Asset page', { tags: '@regression' }, function () {
knownAssetTypes,
assetInfo.source.__typename,
`Checking that current asset type of ${assetInfo.source.__typename} /
is one of: ${knownAssetTypes}: /
If fail then we need to add extra tests for un-encountered asset types`
is one of: ${knownAssetTypes}: /
If fail then we need to add extra tests for un-encountered asset types`
);
});
});
});
});
});
});
it('should be able to switch assets between light and dark mode', function () {
it('Assets page able to switch between light and dark mode', function () {
const whiteThemeSelectedMenuOptionColor = 'rgb(255, 7, 127)';
const whiteThemeJsonFieldBackColor = 'rgb(255, 255, 255)';
const whiteThemeSideMenuBackgroundColor = 'rgb(255, 255, 255)';
const darkThemeSelectedMenuOptionColor = 'rgb(223, 255, 11)';
const darkThemeJsonFieldBackColor = 'rgb(38, 38, 38)';
const darkThemeSideMenuBackgroundColor = 'rgb(0, 0, 0)';
const blackThemeSelectedMenuOptionColor = 'rgb(223, 255, 11)';
const blackThemeJsonFieldBackColor = 'rgb(38, 38, 38)';
const blackThemeSideMenuBackgroundColor = 'rgb(0, 0, 0)';
const themeSwitcher = '[data-testid="theme-switcher"]';
const jsonFields = '.hljs';
const sideMenuBackground = '.absolute';
// Engage dark mode if not allready set
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.then((background_color) => {
if (background_color.includes(whiteThemeSideMenuBackgroundColor))
cy.get(themeSwitcher).click();
});
// Engage white mode
cy.get(themeSwitcher).click();
// White Mode
cy.get(themeSwitcher).click();
cy.get(assetsNavigation)
.should('have.css', 'background-color')
.and('include', whiteThemeSelectedMenuOptionColor);
@@ -120,29 +103,19 @@ context('Asset page', { tags: '@regression' }, function () {
cy.get(themeSwitcher).click();
cy.get(assetsNavigation)
.should('have.css', 'background-color')
.and('include', darkThemeSelectedMenuOptionColor);
.and('include', blackThemeSelectedMenuOptionColor);
cy.get(jsonFields)
.should('have.css', 'background-color')
.and('include', darkThemeJsonFieldBackColor);
.and('include', blackThemeJsonFieldBackColor);
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.and('include', darkThemeSideMenuBackgroundColor);
.and('include', blackThemeSideMenuBackgroundColor);
});
it('should be able to see assets page displayed in mobile', function () {
it('Assets page displayed in mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.get(assetsNavigation).click();
const assetNames = Object.keys(this.assetsInfo);
assetNames.forEach((assetName) => {
cy.get(assetHeader)
.contains(assetName)
.should('be.visible')
.next()
.within(() => {
cy.get(jsonSection).should('not.be.empty');
});
});
cy.common_validate_blocks_data_displayed(assetHeader);
});
});
});
+17 -251
View File
@@ -1,267 +1,33 @@
context('Network parameters page', { tags: '@smoke' }, function () {
before('navigate to network parameter page', function () {
cy.fixture('net_parameter_format_lookup').as('networkParameterFormat');
before('visit token home page', function () {
cy.visit('/');
});
describe('Verify elements on page', function () {
const networkParametersNavigation = 'a[href="/network-parameters"]';
const networkParametersHeader = '[data-testid="network-param-header"]';
const tableRows = '[data-testid="key-value-table-row"]';
before('navigate to network parameter page', function () {
cy.visit('/');
beforeEach('Navigate to network parameter page', function () {
cy.get(networkParametersNavigation).click();
});
it('should show network parameter heading at top of page', function () {
cy.get(networkParametersHeader)
.should('have.text', 'Network Parameters')
.and('be.visible');
it('Network paremeter page is displayed', function () {
verifyNetworkParametersPageDisplayed();
});
it('should list each of the network parameters available', function () {
cy.get_network_parameters().then((network_parameters) => {
const numberOfNetworkParametersInSystem =
Object.keys(network_parameters).length;
cy.get(tableRows).should(
'have.length',
numberOfNetworkParametersInSystem
);
});
});
it('should list each network parameter displayed with json - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (this.networkParameterFormat.json.includes(parameterName)) {
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.invoke('text')
.convert_string_json_to_js_object()
.then((jsonOnPage) => {
cy.wrap(parameterValue, { log: false })
.convert_string_json_to_js_object()
.then((jsonInSystem) =>
assert.deepEqual(
jsonOnPage,
jsonInSystem,
`Checking ${parameterName} has the correct value of ${jsonInSystem}`
)
);
});
}
});
});
});
it('should list each network parameter displayed as a percentage - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (this.networkParameterFormat.percentage.includes(parameterName)) {
const formattedPercentageParameter =
(parseFloat(parameterValue) * 100).toFixed(0) + '%';
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.invoke('text')
.then((parameterValueOnPage) => {
assert.equal(
parameterValueOnPage,
formattedPercentageParameter,
`Checking ${parameterName} has the correct value of ${formattedPercentageParameter}`
);
cy.contains(parameterValueOnPage).should('be.visible');
});
}
});
});
});
it('should list each network parameter displayed as an id - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (this.networkParameterFormat.id.includes(parameterName)) {
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.should('contain', parameterValue)
.and('be.visible')
.invoke('text');
}
});
});
});
it('should list each network parameter displayed as a date - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (this.networkParameterFormat.date.includes(parameterName)) {
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.should('contain', parameterValue)
.and('be.visible');
}
});
});
});
it('should list each network parameter displayed as a duration - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (this.networkParameterFormat.duration.includes(parameterName)) {
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.should('contain', parameterValue)
.and('be.visible');
}
});
});
});
it('should list each network parameter displayed as a currency value with four decimals - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (this.networkParameterFormat.fiveDecimal.includes(parameterName)) {
cy.convert_number_to_four_decimal(parameterValue)
.add_commas_to_number_if_large_enough()
.then((parameterValueFormatted) => {
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.invoke('text')
.then((parameterValueOnPage) => {
assert.equal(
parameterValueOnPage,
parameterValueFormatted,
`Checking ${parameterName} has the correct value of ${parameterValueFormatted}`
);
cy.contains(parameterValueOnPage).should('be.visible');
});
});
}
});
});
});
it('should list each network parameter displayed as a currency value with eighteen decimals - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (
this.networkParameterFormat.eighteenDecimal.includes(parameterName)
) {
cy.convert_number_to_eighteen_decimal(parameterValue)
.add_commas_to_number_if_large_enough()
.then((parameterValueFormatted) => {
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.invoke('text')
.then((parameterValueOnPage) => {
assert.equal(
parameterValueOnPage,
parameterValueFormatted,
`Checking ${parameterName} has the correct value of ${parameterValueFormatted}`
);
cy.contains(parameterValueOnPage).should('be.visible');
});
});
}
});
});
});
it('should be able to switch network parameter page - between light and dark mode', function () {
const whiteThemeSelectedMenuOptionColor = 'rgb(255, 7, 127)';
const whiteThemeJsonFieldBackColor = 'rgb(255, 255, 255)';
const whiteThemeSideMenuBackgroundColor = 'rgb(255, 255, 255)';
const darkThemeSelectedMenuOptionColor = 'rgb(223, 255, 11)';
const darkThemeJsonFieldBackColor = 'rgb(38, 38, 38)';
const darkThemeSideMenuBackgroundColor = 'rgb(0, 0, 0)';
const themeSwitcher = '[data-testid="theme-switcher"]';
const jsonFields = '.hljs';
const sideMenuBackground = '.absolute';
// Engage dark mode if not allready set
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.then((background_color) => {
if (background_color.includes(whiteThemeSideMenuBackgroundColor))
cy.get(themeSwitcher).click();
});
// Engage white mode
cy.get(themeSwitcher).click();
// White Mode
cy.get(networkParametersNavigation)
.should('have.css', 'background-color')
.and('include', whiteThemeSelectedMenuOptionColor);
cy.get(jsonFields)
.should('have.css', 'background-color')
.and('include', whiteThemeJsonFieldBackColor);
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.and('include', whiteThemeSideMenuBackgroundColor);
// Dark Mode
cy.get(themeSwitcher).click();
cy.get(networkParametersNavigation)
.should('have.css', 'background-color')
.and('include', darkThemeSelectedMenuOptionColor);
cy.get(jsonFields)
.should('have.css', 'background-color')
.and('include', darkThemeJsonFieldBackColor);
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.and('include', darkThemeSideMenuBackgroundColor);
});
it('should be able to see network parameters - on mobile', function () {
it('Network parameter page displayed on mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.get(networkParametersNavigation).click();
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.should('not.be.empty')
.and('be.visible');
});
});
verifyNetworkParametersPageDisplayed();
});
});
function verifyNetworkParametersPageDisplayed() {
cy.get('[data-testid="network-param-header"]').should(
'have.text',
'Network Parameters'
);
cy.common_verify_json_parameters(18);
cy.common_verify_json_string_values(6);
cy.common_verify_json_int_values(7);
}
});
+22 -118
View File
@@ -33,20 +33,6 @@ context('Parties page', { tags: '@regression' }, function () {
// Deliberate slow entry of party id/key - enabling transactions to sync
cy.get(partiesSearchBox).type(vegaWalletPublicKey, { delay: 120 });
cy.get(partiesSearchAction).click();
cy.get_connected_parties_accounts().as('party_accounts');
// Ensure balance of each party asset is correct
cy.get('@party_accounts').then((accounts) => {
assetsInTest.forEach((asset) => {
cy.get_asset_decimals(assetData[asset].id).then((assetDecimals) => {
assert.equal(
accounts[assetData[asset].id].balance,
assetData[asset].amount + assetDecimals,
`Checking ${assetData[asset].id} faucet was successfull`
);
});
});
});
});
it('should see party address id - having searched', function () {
@@ -56,7 +42,7 @@ context('Parties page', { tags: '@regression' }, function () {
.should('be.visible');
});
it('should see each asset and balance - within asset data section', function () {
it('should see each asset - within asset data section', function () {
assetsInTest.forEach((asset) => {
cy.contains(assetData[asset].name, txTimeout).should('be.visible');
cy.contains(assetData[asset].name)
@@ -102,97 +88,26 @@ context('Parties page', { tags: '@regression' }, function () {
it('should be able to see JSON of each asset containing correct balance and decimals', function () {
cy.get(partiesJsonSection).should('be.visible');
assetsInTest.forEach((assetInTest) => {
assetsInTest.forEach((asset) => {
cy.get(partiesJsonSection)
.invoke('text')
.convert_string_json_to_js_object()
.get_party_accounts_data_from_js_object()
.then((accountsListedInJson) => {
cy.get_asset_information().then((assetsInfo) => {
const assetInfo =
assetsInfo[accountsListedInJson[assetInTest].asset.name];
.get_party_accounts_data()
.then((accounts) => {
cy.get_asset_decimals(asset).then((assetDecimals) => {
assert.equal(
accountsListedInJson[assetInTest].asset.name,
assetInfo.name
accounts[asset].balance,
assetData[asset].amount + assetDecimals
);
assert.equal(
accountsListedInJson[assetInTest].asset.id,
assetInfo.id
);
assert.equal(
accountsListedInJson[assetInTest].asset.decimals,
assetInfo.decimals
);
assert.equal(
accountsListedInJson[assetInTest].asset.symbol,
assetInfo.symbol
);
assert.equal(
accountsListedInJson[assetInTest].asset.source.__typename,
assetInfo.source.__typename
);
cy.get_asset_decimals(assetInTest).then((assetDecimals) => {
assert.equal(
accountsListedInJson[assetInTest].balance,
assetData[assetInTest].amount + assetDecimals
);
});
});
});
});
});
it('should be able to switch parties page between light and dark mode', function () {
const whiteThemeSelectedMenuOptionColor = 'rgb(255, 7, 127)';
const whiteThemeJsonFieldBackColor = 'rgb(255, 255, 255)';
const whiteThemeSideMenuBackgroundColor = 'rgb(255, 255, 255)';
const darkThemeSelectedMenuOptionColor = 'rgb(223, 255, 11)';
const darkThemeJsonFieldBackColor = 'rgb(38, 38, 38)';
const darkThemeSideMenuBackgroundColor = 'rgb(0, 0, 0)';
const themeSwitcher = '[data-testid="theme-switcher"]';
const jsonFields = '.hljs';
const sideMenuBackground = '.absolute';
// Engage dark mode if not allready set
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.then((background_color) => {
if (background_color.includes(whiteThemeSideMenuBackgroundColor))
cy.get(themeSwitcher).click();
});
// Engage white mode
cy.get(themeSwitcher).click();
// White Mode
cy.get(partiesMenuHeader)
.should('have.css', 'background-color')
.and('include', whiteThemeSelectedMenuOptionColor);
cy.get(jsonFields)
.should('have.css', 'background-color')
.and('include', whiteThemeJsonFieldBackColor);
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.and('include', whiteThemeSideMenuBackgroundColor);
// Dark Mode
cy.get(themeSwitcher).click();
cy.get(partiesMenuHeader)
.should('have.css', 'background-color')
.and('include', darkThemeSelectedMenuOptionColor);
cy.get(jsonFields)
.should('have.css', 'background-color')
.and('include', darkThemeJsonFieldBackColor);
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.and('include', darkThemeSideMenuBackgroundColor);
});
after(
'teardown environment to prevent test data bleeding into other tests',
function () {
if (Cypress.env('TEARDOWN_NETWORK_AFTER_FLOWS')) {
if (Cypress.env('CYPRESS_TEARDOWN_NETWORK_AFTER_FLOWS')) {
cy.restart_vegacapsule_network();
}
}
@@ -207,39 +122,28 @@ context('Parties page', { tags: '@regression' }, function () {
});
});
Cypress.Commands.add('get_connected_parties_accounts', () => {
const mutation =
'{partiesConnection {edges{node{accountsConnection{edges{node{\
balance type asset {id symbol decimals}}}}}}}}';
cy.request({
method: 'POST',
url: `http://localhost:3028/query`,
body: {
query: mutation,
},
headers: { 'content-type': 'application/json' },
})
.its(
`body.data.partiesConnection.edges.1.node.accountsConnection.edges`
)
.then(function (response) {
let accounts = {};
response.forEach((account) => {
accounts[account.node.asset.id] = account.node;
});
return accounts;
});
});
Cypress.Commands.add(
'convert_string_json_to_js_object',
{ prevSubject: true },
(jsonBlobString) => {
return JSON.parse(jsonBlobString);
}
);
Cypress.Commands.add(
'get_party_accounts_data_from_js_object',
'get_party_accounts_data',
{ prevSubject: true },
(jsObject) => {
const accounts = jsObject.party.accounts.reduce(function (
account,
entry
) {
account[entry.asset.id] = entry;
account[entry.asset.id] = {
balance: entry.balance,
id: entry.asset.id,
decimals: entry.asset.decimals,
name: entry.asset.name,
};
return account;
},
{});
+16 -291
View File
@@ -1,300 +1,25 @@
context('Validator page', { tags: '@smoke' }, function () {
const validatorMenuHeading = 'a[href="/validators"]';
const tendermintDataHeader = '[data-testid="tendermint-header"]';
const vegaDataHeader = '[data-testid="vega-header"]';
const jsonSection = '.language-json';
before('Visit validators page and obtain data', function () {
cy.visit('/');
cy.get(validatorMenuHeading).click();
cy.get_validators().as('validators');
cy.get_nodes().as('nodes');
});
describe('Verify elements on page', function () {
before('Ensure at least two validators are present', function () {
assert.isAtLeast(
this.validators.length,
2,
'Ensuring at least two validators exist'
);
const validatorNavigation = 'a[href="/validators"]';
it('Validator page is displayed', function () {
cy.visit('/');
cy.get(validatorNavigation).click();
validateValidatorsDisplayed();
});
it('should be able to see validator page sections', function () {
cy.get(vegaDataHeader)
.contains('Vega data')
.and('is.visible')
.next()
.within(() => {
cy.get(jsonSection).should('not.be.empty');
});
cy.get(tendermintDataHeader)
.contains('Tendermint data')
.and('is.visible')
.next()
.within(() => {
cy.get(jsonSection).should('not.be.empty');
});
});
it('should be able to see relevant validator information in tendermint section', function () {
cy.get(tendermintDataHeader)
.contains('Tendermint data')
.next()
.within(() => {
cy.get(jsonSection)
.invoke('text')
.convert_string_json_to_js_object()
.then((validatorsInJson) => {
this.validators.forEach((validator, index) => {
const validatorInJson =
validatorsInJson.result.validators[index];
assert.equal(
validatorInJson.address,
validator.address,
`Checking that validator address shown in json matches system data`
);
cy.contains(validator.address).should('be.visible');
assert.equal(
validatorInJson.pub_key.type,
validator.pub_key.type,
`Checking that validator public key type shown in json matches system data`
);
cy.contains(validator.pub_key.type).should('be.visible');
assert.equal(
validatorInJson.pub_key.value,
validator.pub_key.value,
`Checking that validator public key value shown in json matches system data`
);
cy.contains(validator.pub_key.value).should('be.visible');
assert.equal(
validatorInJson.voting_power,
validator.voting_power,
`Checking that validator voting power in json matches system data`
);
cy.contains(validator.voting_power).should('be.visible');
// Proposer priority can change frequently mid test
// Therefore only checking the field name is present.
cy.contains('proposer_priority').should('be.visible');
});
});
});
});
it('should be able to see relevant node information in vega data section', function () {
cy.get(vegaDataHeader)
.contains('Vega data')
.next()
.within(() => {
cy.get(jsonSection)
.invoke('text')
.convert_string_json_to_js_object()
.then((nodesInJson) => {
this.nodes.forEach((node, index) => {
const nodeInJson = nodesInJson.nodes[index];
// Vegacapsule shows no info or null for following fields:
// name, infoURL, avatarUrl, location, epoch data
// Therefore, these values remain unchecked.
assert.equal(
nodeInJson.__typename,
node.__typename,
`Checking that node __typename shown in json matches system data`
);
cy.contains(node.__typename).should('be.visible');
assert.equal(
nodeInJson.id,
node.id,
`Checking that node id shown in json matches system data`
);
cy.contains(node.id).should('be.visible');
assert.equal(
nodeInJson.pubkey,
node.pubkey,
`Checking that node pubkey shown in json matches system data`
);
cy.contains(node.pubkey).should('be.visible');
assert.equal(
nodeInJson.tmPubkey,
node.tmPubkey,
`Checking that node tmPubkey shown in json matches system data`
);
cy.contains(node.tmPubkey).should('be.visible');
assert.equal(
nodeInJson.ethereumAddress,
node.ethereumAddress,
`Checking that node ethereumAddress shown in json matches system data`
);
cy.contains(node.ethereumAddress).should('be.visible');
assert.equal(
nodeInJson.stakedByOperator,
node.stakedByOperator,
`Checking that node stakedByOperator value shown in json matches system data`
);
cy.contains(node.stakedByOperator).should('be.visible');
assert.equal(
nodeInJson.stakedByDelegates,
node.stakedByDelegates,
`Checking that node stakedByDelegates value shown in json matches system data`
);
cy.contains(node.stakedByDelegates).should('be.visible');
assert.equal(
nodeInJson.stakedTotal,
node.stakedTotal,
`Checking that node stakedTotal shown in json matches system data`
);
cy.contains(node.stakedTotal).should('be.visible');
assert.equal(
nodeInJson.pendingStake,
node.pendingStake,
`Checking that node pendingStake shown in json matches system data`
);
cy.contains(node.pendingStake).should('be.visible');
assert.equal(
nodeInJson.status,
node.status,
`Checking that node status shown in json matches system data`
);
cy.contains(node.status).should('be.visible');
});
});
});
});
it('should be able to see validator page displayed on mobile', function () {
it('Validator page is displayed on mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.get(validatorMenuHeading).click();
cy.get(vegaDataHeader)
.contains('Vega data')
.and('is.visible')
.next()
.within(() => {
cy.get(jsonSection).should('not.be.empty');
});
cy.get(tendermintDataHeader)
.contains('Tendermint data')
.and('is.visible')
.next()
.within(() => {
cy.get(jsonSection).should('not.be.empty');
});
cy.get(tendermintDataHeader)
.contains('Tendermint data')
.next()
.within(() => {
this.validators.forEach((validator) => {
cy.contains(validator.address).should('be.visible');
cy.contains(validator.pub_key.type).should('be.visible');
cy.contains(validator.pub_key.value).should('be.visible');
cy.contains(validator.voting_power).should('be.visible');
// Proposer priority can change frequently mid test
// Therefore only checking the field name is present.
cy.contains('proposer_priority').should('be.visible');
});
});
cy.get(validatorNavigation).click();
validateValidatorsDisplayed();
});
it('should be able to switch validator page between light and dark mode', function () {
const whiteThemeSelectedMenuOptionColor = 'rgb(255, 7, 127)';
const whiteThemeJsonFieldBackColor = 'rgb(255, 255, 255)';
const whiteThemeSideMenuBackgroundColor = 'rgb(255, 255, 255)';
const darkThemeSelectedMenuOptionColor = 'rgb(223, 255, 11)';
const darkThemeJsonFieldBackColor = 'rgb(38, 38, 38)';
const darkThemeSideMenuBackgroundColor = 'rgb(0, 0, 0)';
const themeSwitcher = '[data-testid="theme-switcher"]';
const jsonFields = '.hljs';
const sideMenuBackground = '.absolute';
// Engage dark mode if not allready set
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.then((background_color) => {
if (background_color.includes(whiteThemeSideMenuBackgroundColor))
cy.get(themeSwitcher).click();
});
// Engage white mode
cy.get(themeSwitcher).click();
// White Mode
cy.get(validatorMenuHeading)
.should('have.css', 'background-color')
.and('include', whiteThemeSelectedMenuOptionColor);
cy.get(jsonFields)
.should('have.css', 'background-color')
.and('include', whiteThemeJsonFieldBackColor);
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.and('include', whiteThemeSideMenuBackgroundColor);
// Dark Mode
cy.get(themeSwitcher).click();
cy.get(validatorMenuHeading)
.should('have.css', 'background-color')
.and('include', darkThemeSelectedMenuOptionColor);
cy.get(jsonFields)
.should('have.css', 'background-color')
.and('include', darkThemeJsonFieldBackColor);
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.and('include', darkThemeSideMenuBackgroundColor);
});
Cypress.Commands.add('get_validators', () => {
cy.request({
method: 'GET',
url: `http://localhost:26617/validators`,
headers: { 'content-type': 'application/json' },
})
.its(`body.result.validators`)
.then(function (response) {
let validators = [];
response.forEach((account, index) => {
validators[index] = account;
});
return validators;
});
});
Cypress.Commands.add('get_nodes', () => {
const mutation =
'{nodes { id name infoUrl avatarUrl pubkey tmPubkey ethereumAddress \
location stakedByOperator stakedByDelegates stakedTotal pendingStake \
epochData { total offline online __typename } status name __typename}}';
cy.request({
method: 'POST',
url: `http://localhost:3028/query`,
body: {
query: mutation,
},
headers: { 'content-type': 'application/json' },
})
.its(`body.data.nodes`)
.then(function (response) {
let nodes = [];
response.forEach((node) => {
nodes.push(node);
});
return nodes;
});
});
function validateValidatorsDisplayed() {
cy.get('[data-testid="tendermint-header"]').should(
'have.text',
'Tendermint data'
);
cy.get('[data-testid="tendermint-data"]').should('not.be.empty');
}
});
});
@@ -1,5 +1,3 @@
import { BigNumber } from 'bignumber.js';
Cypress.Commands.add(
'common_validate_blocks_data_displayed',
function (headerTestId) {
@@ -27,6 +25,33 @@ Cypress.Commands.add('common_switch_to_mobile_and_click_toggle', function () {
cy.get('[data-testid="open-menu"]').click();
});
Cypress.Commands.add('common_verify_json_parameters', function (expectedNum) {
cy.get('.hljs-attr')
.should('have.length.at.least', expectedNum)
.each(($paramName) => {
cy.wrap($paramName).should('not.be.empty');
});
});
Cypress.Commands.add(
'common_verify_json_string_values',
function (expectedNum) {
cy.get('.hljs-string')
.should('have.length.at.least', expectedNum)
.each(($paramValue) => {
cy.wrap($paramValue).should('not.be.empty');
});
}
);
Cypress.Commands.add('common_verify_json_int_values', function (expectedNum) {
cy.get('.hljs-number')
.should('have.length.at.least', expectedNum)
.each(($paramValue) => {
cy.wrap($paramValue).should('not.be.empty');
});
});
Cypress.Commands.add('monitor_clipboard', () => {
cy.window().then((win) => {
return cy.stub(win, 'prompt').returns(win.prompt);
@@ -42,38 +67,3 @@ Cypress.Commands.add(
return clipboard.args[0][1];
}
);
Cypress.Commands.add(
'convert_string_json_to_js_object',
{ prevSubject: true },
(jsonBlobString) => {
// Note: this is a chaining function
return JSON.parse(jsonBlobString);
}
);
Cypress.Commands.add(
'add_commas_to_number_if_large_enough',
{ prevSubject: true },
(number) => {
// This will turn 10000000.0000 into 10,000,000.000
// Note: this is a chaining function
const beforeDecimal = number.split('.')[0];
const afterDecimal = number.split('.')[1];
const beforeDecimalWithCommas = beforeDecimal
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
const formattedValue = beforeDecimalWithCommas + '.' + afterDecimal;
return formattedValue;
}
);
Cypress.Commands.add('convert_number_to_eighteen_decimal', (number) => {
// this will take a number like this : 700000000000000000000
// and convert it to a number like this: 700.000000000000000000
return BigNumber((number / 1000000000000000000).toString()).toFixed(18);
});
Cypress.Commands.add('convert_number_to_four_decimal', (number) => {
return parseFloat(number).toFixed(4);
});
+1 -2
View File
@@ -2,11 +2,10 @@ NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-exp
NX_TENDERMINT_URL=https://n01.stagnet3.vega.xyz/tm
NX_TENDERMINT_WEBSOCKET_URL=wss://n01.stagnet3.vega.xyz/tm/websocket
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json
NX_VEGA_NETWORKS={\"MAINNET"\:\"https://explorer.vega.xyz"\,\"TESTNET\":\"https://explorer.fairground.wtf\"}
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
NX_VEGA_ENV=STAGNET3
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_BLOCK_EXPLORER=
# App flags
NX_EXPLORER_ASSETS=1
+1 -1
View File
@@ -3,7 +3,7 @@ NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-exp
NX_TENDERMINT_URL=http://localhost:26617
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
NX_VEGA_URL=http://localhost:3028/query
NX_VEGA_NETWORKS={\"MAINNET"\:\"https://explorer.vega.xyz"\,\"TESTNET\":\"https://explorer.fairground.wtf\"}
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
NX_VEGA_ENV=CUSTOM
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
+1 -2
View File
@@ -4,7 +4,6 @@ NX_TENDERMINT_URL=https://n04.d.vega.xyz/tm
NX_TENDERMINT_WEBSOCKET_URL=wss://n04.d.vega.xyz/tm/websocket
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/devnet-network.json
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
NX_VEGA_NETWORKS={\"MAINNET"\:\"https://explorer.vega.xyz"\,\"TESTNET\":\"https://explorer.fairground.wtf\"}
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
NX_VEGA_ENV=DEVNET
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_BLOCK_EXPLORER=

Some files were not shown because too many files have changed in this diff Show More