Compare commits

..
Author SHA1 Message Date
Dexter 0a92f62a66 ci: publish esm and cjs 2023-04-25 10:11:55 +01:00
daro-maj f589f4a9fa test(trading): tests for ac - 7005-FILL-fills (#3529) 2023-04-25 09:19:37 +01:00
dexturr b9869da492 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-25 06:07:52 +00:00
dexturr 653fec7025 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-25 00:15:25 +00:00
dexturr 8bf948578c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-24 18:09:08 +00:00
Dexter 11b08d16e4 ci: bump version 2023-04-24 15:56:05 +01:00
daro-maj 5081b11c93 test(trading): separated artifacts for logs and html report (#3519) 2023-04-24 15:28:42 +02:00
Dexter Edwards a1366e59ec fix(ui-toolkit): box size being wrong for multiline check boxes (#3527) 2023-04-24 12:10:52 +00:00
dexturr 0b035d5064 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-24 12:07:43 +00:00
dexturr e1a38f2197 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-24 06:07:22 +00:00
dexturr 8201e87050 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-24 00:16:56 +00:00
dexturr 3aaf4e724d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-23 18:07:11 +00:00
dexturr 6fe06e9f62 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-23 12:07:53 +00:00
dexturr cd8b0e7caf chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-23 06:06:56 +00:00
dexturr 4282faa9d9 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-23 00:16:16 +00:00
dexturr a24846fd06 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-22 18:07:13 +00:00
dexturr 72de53cf10 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-22 12:09:27 +00:00
dexturr f3c0313a59 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-22 06:07:33 +00:00
dexturr 4c0de8f22b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-22 00:16:38 +00:00
dexturr 254fb57af0 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-21 18:09:06 +00:00
Bartłomiej Głownia 6371199537 feat(trading): add negative oracle status banner (#3486) 2023-04-21 18:31:52 +02:00
Dexter Edwards 75cb48a4b9 chore(react-helpers): make log level customisable (#3474) 2023-04-21 16:29:30 +01:00
ArtandJoe 933878acf5 chore(ui-toolkit): leftover dependencies (#3485)
Co-authored-by: Joe <joe@vega.xyz>
2023-04-21 16:16:04 +01:00
Dexter Edwards 5995df8e68 chore(ui-toolkit,react-helpers,utils,tailwindcss-config): add more build targets (#3518) 2023-04-21 14:28:18 +00:00
Bartłomiej Głownia 4d5b7cf5e7 fix(trading): amend market list settlement asset column getter (#3487) 2023-04-21 16:08:41 +02:00
dexturr e1f60446f0 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-21 12:10:50 +00:00
daro-maj 7f271069ab test(trading): mocha reporter for e2e tests (#3465) 2023-04-21 13:36:31 +02:00
dexturr 1ae7af5d59 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-21 06:09:12 +00:00
dexturr b9c5d9ee96 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-21 00:14:39 +00:00
dexturr ae1768a669 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-20 18:07:37 +00:00
Joe Tsang a1bfe7f1a7 test(governance): e2e network upgrade proposal tests (#3477) 2023-04-20 18:38:09 +01:00
Sam KeenandDexter b0f1aeedae fix(governance): withdrawals bug (#3443)
Co-authored-by: Dexter <dexter.edwards93@gmail.com>
2023-04-20 17:18:17 +01:00
Joe Tsang da59e83b19 test(governance): e2e tests for rewards pagination (#3473) 2023-04-20 16:48:42 +01:00
Art 360624282d chore(web3): wallet connect v2 (#3324) 2023-04-20 17:20:59 +02:00
dexturr 9e054c7c85 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-20 12:09:40 +00:00
m.ray 911e927ab0 fix(wallet): fetch new keys without re-connecting the wallet (#3467) 2023-04-20 13:56:48 +02:00
ArtandMikołaj Młodzikowski e4a51061a3 chore(ci): bump typescript (#3444)
Co-authored-by: Mikołaj Młodzikowski <mikolaj.mlodzikowski@gmail.com>
2023-04-20 11:56:33 +00:00
Bartłomiej Głownia c15051d457 fix(trading): refactor market info accordion to avoid remount on candle reload (#3447) 2023-04-20 11:32:09 +02:00
Sam Keen 460ccdb3a2 feat(governance): associate form associate link (#3468) 2023-04-20 10:16:52 +01:00
dexturr 959fb9cf62 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-20 06:07:00 +00:00
dexturr 2c7170d0e9 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-20 00:15:44 +00:00
dexturr 8a28a4afd4 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-19 18:07:06 +00:00
Ciaran McGhie 48072eb4c3 chore(react-helpers): ugprade react-helpers to 0.2.0 and ui-toolkit to 0.11.0 (#3469) 2023-04-19 16:07:35 +01:00
Sam Keen ae92ff2580 feat(governance): protocol upgrade proposals list and details (#3363) 2023-04-19 13:44:36 +01:00
dexturr c99b7fbb02 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-19 12:07:50 +00:00
Joe Tsang a9b1767a42 fix(governance): fix flaky tests due to wallet teardown (#3460) 2023-04-19 11:54:04 +01:00
Ciaran McGhie 3cd60ad3e6 chore(ui-toolkit): bump ui toolkit to 0.10.0 (#3458) 2023-04-19 09:46:57 +01:00
Art 2f4bc9484b feat(environment): github releases (#3426) 2023-04-19 09:42:37 +01:00
187 changed files with 47118 additions and 2308 deletions
+2 -2
View File
@@ -26,7 +26,7 @@ jobs:
with:
path: node_modules
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
# comment out "resotre-keys" if you need to rebuild yarn from 0
# comment out "restore-keys" if you need to rebuild yarn from 0
restore-keys: |
${{ runner.os }}-cache-node-modules-
@@ -50,7 +50,7 @@ jobs:
secrets: inherit
lint-test-build:
timeout-minutes: 20
timeout-minutes: 35
needs: node-modules
runs-on: ubuntu-22.04
name: '(CI) lint + unit test + build'
+7 -1
View File
@@ -20,7 +20,7 @@ jobs:
project: ${{ fromJSON(inputs.projects) }}
name: ${{ matrix.project }}
runs-on: self-hosted-runner
timeout-minutes: 30
timeout-minutes: 40
steps:
# Checks if skip cache was requested
- name: Set skip-nx-cache flag
@@ -93,3 +93,9 @@ jobs:
with:
name: logs-${{ matrix.project }}
path: /home/runner/.vegacapsule/testnet/logs
- uses: actions/upload-artifact@v3
if: ${{ failure() }}
with:
name: test-report-${{ matrix.project }}
path: frontend-monorepo/apps/trading-e2e/cypress/reports
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
app: ${{ fromJSON(inputs.projects) }}
name: ${{ matrix.app }}
runs-on: ubuntu-22.04
timeout-minutes: 20
timeout-minutes: 25
steps:
- name: Check out code
uses: actions/checkout@v3
+3
View File
@@ -46,3 +46,6 @@ cypress.env.json
# Next.js
.next
#cypress
/apps/trading-e2e/cypress/reports/
+1
View File
@@ -21,6 +21,7 @@ module.exports = defineConfig({
chromeWebSecurity: false,
viewportWidth: 1440,
viewportHeight: 900,
testIsolation: false,
},
env: {
environment: 'CUSTOM',
+1 -1
View File
@@ -3,7 +3,7 @@ NX_TENDERMINT_URL=http://localhost:26617
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
NX_VEGA_ENV=CUSTOM
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
# App flags
NX_EXPLORER_ASSETS=1
+1 -1
View File
@@ -4,4 +4,4 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket
NX_VEGA_ENV=CUSTOM
NX_BLOCK_EXPLORER=
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
@@ -60,9 +60,11 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
<>
<MarketInfoTable
noBorder={false}
data={trigger}
data={{
maxValidPrice: trigger.maxValidPrice,
minValidPrice: trigger.minValidPrice,
}}
decimalPlaces={market.decimalPlaces}
omits={['referencePrice', '__typename']}
/>
<MarketInfoTable
noBorder={false}
+3 -1
View File
@@ -10,11 +10,13 @@ NX_ETHEREUM_CHAIN_ID=1440
NX_ETH_URL_CONNECT=1
NX_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
NX_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
#Test configuration variables
CYPRESS_FAIRGROUND=false
+1
View File
@@ -25,6 +25,7 @@ module.exports = defineConfig({
viewportWidth: 1440,
viewportHeight: 900,
numTestsKeptInMemory: 5,
testIsolation: false,
},
env: {
ethProviderUrl: 'http://localhost:8545/',
@@ -0,0 +1,38 @@
export const upgradeProposalsData = {
lastBlockHeight: '2014133',
protocolUpgradeProposals: {
edges: [
{
node: {
upgradeBlockHeight: '2015942',
vegaReleaseTag: 'v1',
approvers: [
'02a6531716b7a6d82779b7793c3ad2fcb47290ea2ff0912c56f61219bd9675ff',
'121934387281812a2d5e6913e5d57c0f85a8f169e2752347ee2e23b52d46623c',
'65c80e2f5f84e2109eec30810f137ba04cbbecaba8f27706c146cc6c6f90db29',
'bd6339d2428c79ac3bc9011771236d17bac92bcb1806423388d52fb440043aef',
],
status: 'PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED',
__typename: 'ProtocolUpgradeProposal',
},
__typename: 'ProtocolUpgradeProposalEdge',
},
{
node: {
upgradeBlockHeight: '1955065',
vegaReleaseTag: 'v0.71.0+dev-12156-bca1d57e',
approvers: [
'02a6531716b7a6d82779b7793c3ad2fcb47290ea2ff0912c56f61219bd9675ff',
'121934387281812a2d5e6913e5d57c0f85a8f169e2752347ee2e23b52d46623c',
'65c80e2f5f84e2109eec30810f137ba04cbbecaba8f27706c146cc6c6f90db29',
'bd6339d2428c79ac3bc9011771236d17bac92bcb1806423388d52fb440043aef',
],
status: 'PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED',
__typename: 'ProtocolUpgradeProposal',
},
__typename: 'ProtocolUpgradeProposalEdge',
},
],
__typename: 'ProtocolUpgradeProposalConnection',
},
};
@@ -0,0 +1,117 @@
export const nodeData = {
epoch: {
id: '204731',
timestamps: {
start: '2023-04-14T09:30:09.452005Z',
end: null,
expiry: '2023-04-14T09:31:09.452005Z',
__typename: 'EpochTimestamps',
},
__typename: 'Epoch',
},
nodesConnection: {
edges: [
{
node: {
avatarUrl:
'https://www.gravatar.com/avatar/y2hwc4xjds7zvlam3y4in94q2rcdimsn?d=identicon',
id: 'f337b5cc50c49a928e49129a2eca62277a81b4b7336b6e4131f8f0431e8db029',
name: 'lovely-fisherman',
pubkey:
'02a6531716b7a6d82779b7793c3ad2fcb47290ea2ff0912c56f61219bd9675ff',
stakedByOperator: '3000000000000000000000',
stakedByDelegates: '0',
stakedTotal: '3000000000000000000000',
pendingStake: '0',
rankingScore: {
rankingScore: '0.4999166805532412',
stakeScore: '0.2499583402766206',
performanceScore: '1',
votingPower: '2499',
status: 'VALIDATOR_NODE_STATUS_TENDERMINT',
__typename: 'RankingScore',
},
__typename: 'Node',
},
__typename: 'NodeEdge',
},
{
node: {
avatarUrl:
'https://www.gravatar.com/avatar/g1tw70qnoo0tf8ror30jefwhae92zy16?d=identicon',
id: 'cdadcf885556e372b6b39679d6ad46854d1d9c1e982da7ff2929544df01f9088',
name: 'magnificent-door',
pubkey:
'121934387281812a2d5e6913e5d57c0f85a8f169e2752347ee2e23b52d46623c',
stakedByOperator: '3000000000000000000000',
stakedByDelegates: '0',
stakedTotal: '3000000000000000000000',
pendingStake: '0',
rankingScore: {
rankingScore: '0.4999166805532412',
stakeScore: '0.2499583402766206',
performanceScore: '1',
votingPower: '2499',
status: 'VALIDATOR_NODE_STATUS_TENDERMINT',
__typename: 'RankingScore',
},
__typename: 'Node',
},
__typename: 'NodeEdge',
},
{
node: {
avatarUrl:
'https://www.gravatar.com/avatar/s2e7hp7soq5zdhxeap7p21onetsjiy6w?d=identicon',
id: '9a13de2548fef30d928e71e76004c98ec7ad9d8fc3ddcd16ddee210b28ea4cfc',
name: 'helpful-tree',
pubkey:
'bd6339d2428c79ac3bc9011771236d17bac92bcb1806423388d52fb440043aef',
stakedByOperator: '3000000000000000000000',
stakedByDelegates: '2000000000000000000',
stakedTotal: '3002000000000000000000',
pendingStake: '0',
rankingScore: {
rankingScore: '0.5002499583402766',
stakeScore: '0.2501249791701383',
performanceScore: '1',
votingPower: '2501',
status: 'VALIDATOR_NODE_STATUS_TENDERMINT',
__typename: 'RankingScore',
},
__typename: 'Node',
},
__typename: 'NodeEdge',
},
{
node: {
avatarUrl:
'https://www.gravatar.com/avatar/3gop683kg2cvd8rpv286hzagqt3yjsdq?d=identicon',
id: '93ac271ab95038333587e47d11461e6edc0126e6e77156281c545f4c5650a6d0',
name: 'easy-cookie',
pubkey:
'65c80e2f5f84e2109eec30810f137ba04cbbecaba8f27706c146cc6c6f90db29',
stakedByOperator: '3000000000000000000000',
stakedByDelegates: '0',
stakedTotal: '3000000000000000000000',
pendingStake: '0',
rankingScore: {
rankingScore: '0.4999166805532412',
stakeScore: '0.2499583402766206',
performanceScore: '1',
votingPower: '2499',
status: 'VALIDATOR_NODE_STATUS_TENDERMINT',
__typename: 'RankingScore',
},
__typename: 'Node',
},
__typename: 'NodeEdge',
},
],
__typename: 'NodesConnection',
},
nodeData: {
stakedTotal: '12002000000000000000000',
__typename: 'NodeData',
},
};
@@ -0,0 +1,325 @@
export const proposalsData = {
proposalsConnection: {
edges: [
{
node: {
id: 'e8ba9d268e12514644fd1fc7ff289292f4ce6489cc32cc73133aea52c04aef89',
rationale: {
title: 'Add asset Wrapped Ether',
description: 'Proposal to add asset WETH to Vega network',
__typename: 'ProposalRationale',
},
reference: '',
state: 'STATE_OPEN',
datetime: '2026-12-01T11:41:28.654288Z',
rejectionReason: null,
party: {
id: '69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f',
__typename: 'Party',
},
errorDetails: null,
terms: {
closingDatetime: '2026-12-01T11:45:33Z',
enactmentDatetime: '2026-12-01T11:45:43Z',
change: {
name: 'Wrapped Ether',
symbol: 'WETH',
decimals: 18,
quantum: '0.0008',
source: {
contractAddress: '0x9B18C6CaD886D5653783E2B25759124760F4407F',
withdrawThreshold: '1',
lifetimeLimit: '400000000000000000',
__typename: 'ERC20',
},
__typename: 'NewAsset',
},
__typename: 'ProposalTerms',
},
votes: {
yes: {
totalTokens: '0',
totalNumber: '0',
totalEquityLikeShareWeight: '0',
__typename: 'ProposalVoteSide',
},
no: {
totalTokens: '0',
totalNumber: '0',
totalEquityLikeShareWeight: '0',
__typename: 'ProposalVoteSide',
},
__typename: 'ProposalVotes',
},
__typename: 'Proposal',
},
__typename: 'ProposalEdge',
},
{
node: {
id: 'd848fc7881f13d366df5f61ab139d5fcfa72bf838151bb51b54381870e357931',
rationale: {
title: 'Add asset Dai Stablecoin',
description: 'Proposal to add asset DAI to Vega network',
__typename: 'ProposalRationale',
},
reference: '',
state: 'STATE_ENACTED',
datetime: '2022-11-29T15:49:57.80978Z',
rejectionReason: null,
party: {
id: '69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f',
__typename: 'Party',
},
errorDetails: null,
terms: {
closingDatetime: '2023-04-13T15:52:58Z',
enactmentDatetime: '2023-04-13T15:53:08Z',
change: {
name: 'Dai Stablecoin',
symbol: 'DAI',
decimals: 18,
quantum: '1',
source: {
contractAddress: '0xad018fB8ec00bfd622B91C83E684a6AC7bB8fbA4',
withdrawThreshold: '1',
lifetimeLimit: '500000000000000000000',
__typename: 'ERC20',
},
__typename: 'NewAsset',
},
__typename: 'ProposalTerms',
},
votes: {
yes: {
totalTokens: '0',
totalNumber: '0',
totalEquityLikeShareWeight: '0',
__typename: 'ProposalVoteSide',
},
no: {
totalTokens: '0',
totalNumber: '0',
totalEquityLikeShareWeight: '0',
__typename: 'ProposalVoteSide',
},
__typename: 'ProposalVotes',
},
__typename: 'Proposal',
},
__typename: 'ProposalEdge',
},
{
node: {
id: 'ccbd651b4a1167fd73c4a0340ac759fa0a31ca487ad46a13254b741ad71947ed',
rationale: {
title: 'New DAI market',
description: 'New DAI market',
__typename: 'ProposalRationale',
},
reference: '0VFQusmmESdrP5GuL8naB6lxfoE3RPGaEeo7abdN',
state: 'STATE_ENACTED',
datetime: '2022-11-26T19:36:19.26034Z',
rejectionReason: null,
party: {
id: '69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f',
__typename: 'Party',
},
errorDetails: null,
terms: {
closingDatetime: '2022-11-26T19:36:42Z',
enactmentDatetime: '2023-03-22T13:57:37Z',
change: {
instrument: {
name: 'UNIDAI Monthly (Dec 2022)',
code: 'UNIDAI.MF21',
futureProduct: {
settlementAsset: { symbol: 'tDAI', __typename: 'Asset' },
__typename: 'FutureProduct',
},
__typename: 'InstrumentConfiguration',
},
__typename: 'NewMarket',
},
__typename: 'ProposalTerms',
},
votes: {
yes: {
totalTokens: '0',
totalNumber: '0',
totalEquityLikeShareWeight: '0',
__typename: 'ProposalVoteSide',
},
no: {
totalTokens: '0',
totalNumber: '0',
totalEquityLikeShareWeight: '0',
__typename: 'ProposalVoteSide',
},
__typename: 'ProposalVotes',
},
__typename: 'Proposal',
},
__typename: 'ProposalEdge',
},
{
node: {
id: 'bc70383f0e9515b15542cf4c63590cd2ca46b3363ba7c4a72af0e62112b3951b',
rationale: {
title: 'USDC-III',
description: 'USDC-III D List test',
__typename: 'ProposalRationale',
},
reference: '',
state: 'STATE_ENACTED',
datetime: '2022-11-22T15:17:28.829605Z',
rejectionReason: null,
party: {
id: '69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f',
__typename: 'Party',
},
errorDetails: null,
terms: {
closingDatetime: '2022-11-22T15:18:56Z',
enactmentDatetime: '2022-11-22T15:19:06Z',
change: {
name: 'USDC-III',
symbol: 'USDC-III',
decimals: 18,
quantum: '1',
source: {
contractAddress: '0x1F1A067aEC530b66BA5128C9Db76825eC22c3C6b',
withdrawThreshold: '100000000000000000000000000',
lifetimeLimit: '1000000000000000000000000000',
__typename: 'ERC20',
},
__typename: 'NewAsset',
},
__typename: 'ProposalTerms',
},
votes: {
yes: {
totalTokens: '0',
totalNumber: '0',
totalEquityLikeShareWeight: '0',
__typename: 'ProposalVoteSide',
},
no: {
totalTokens: '0',
totalNumber: '0',
totalEquityLikeShareWeight: '0',
__typename: 'ProposalVoteSide',
},
__typename: 'ProposalVotes',
},
__typename: 'Proposal',
},
__typename: 'ProposalEdge',
},
{
node: {
id: '9d9b2a9d0179d0e4ccb317f6c4a5db0b905d893190bfb5e5499985ef313281c8',
rationale: {
title: 'New BTC market',
description: 'New BTC market',
__typename: 'ProposalRationale',
},
reference: 'AXeRWS3TvLBFDgWOSHQpKFJf3NTbnWK6310q02fZ',
state: 'STATE_ENACTED',
datetime: '2022-11-26T19:36:19.26034Z',
rejectionReason: null,
party: {
id: '69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f',
__typename: 'Party',
},
errorDetails: null,
terms: {
closingDatetime: '2022-11-26T19:36:42Z',
enactmentDatetime: '2023-03-22T13:57:37Z',
change: {
instrument: {
name: 'ETHBTC Quarterly (Feb 2023)',
code: 'ETHBTC.QM21',
futureProduct: {
settlementAsset: { symbol: 'tBTC', __typename: 'Asset' },
__typename: 'FutureProduct',
},
__typename: 'InstrumentConfiguration',
},
__typename: 'NewMarket',
},
__typename: 'ProposalTerms',
},
votes: {
yes: {
totalTokens: '0',
totalNumber: '0',
totalEquityLikeShareWeight: '0',
__typename: 'ProposalVoteSide',
},
no: {
totalTokens: '0',
totalNumber: '0',
totalEquityLikeShareWeight: '0',
__typename: 'ProposalVoteSide',
},
__typename: 'ProposalVotes',
},
__typename: 'Proposal',
},
__typename: 'ProposalEdge',
},
{
node: {
id: '9c48796e7988769ededc2b2b02220b00e93f65f23e8141bf1fd23a6983d95943',
rationale: {
title: 'Update governance.proposal.asset.requiredMajority',
description:
'Proposal to update governance.proposal.asset.requiredMajority to 300}',
__typename: 'ProposalRationale',
},
reference: '',
state: 'STATE_ENACTED',
datetime: '2022-11-22T13:22:52.370655Z',
rejectionReason: null,
party: {
id: '69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f',
__typename: 'Party',
},
errorDetails: null,
terms: {
closingDatetime: '2022-11-22T13:27:13Z',
enactmentDatetime: '2022-11-22T13:27:33Z',
change: {
networkParameter: {
key: 'governance.proposal.asset.requiredParticipation',
value: '0.000001',
__typename: 'NetworkParameter',
},
__typename: 'UpdateNetworkParameter',
},
__typename: 'ProposalTerms',
},
votes: {
yes: {
totalTokens: '0',
totalNumber: '0',
totalEquityLikeShareWeight: '0',
__typename: 'ProposalVoteSide',
},
no: {
totalTokens: '0',
totalNumber: '0',
totalEquityLikeShareWeight: '0',
__typename: 'ProposalVoteSide',
},
__typename: 'ProposalVotes',
},
__typename: 'Proposal',
},
__typename: 'ProposalEdge',
},
],
__typename: 'ProposalsConnection',
},
};
@@ -12,7 +12,6 @@ import {
generateFreeFormProposalTitle,
getProposalIdFromList,
getProposalInformationFromTable,
getSortOrderOfSuppliedArray,
getSubmittedProposalFromProposalList,
goToMakeNewProposal,
governanceProposalType,
@@ -24,9 +23,9 @@ import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/stakin
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
const proposalDetailsTitle = '[data-testid="proposal-title"]';
const openProposals = '[data-testid="open-proposals"]';
const voteStatus = '[data-testid="vote-status"]';
const proposalClosingDate = '[data-testid="vote-details"]';
const viewProposalButton = '[data-testid="view-proposal-btn"]';
describe('Governance flow for proposal list', { tags: '@slow' }, function () {
@@ -45,16 +44,8 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
});
it('Newly created proposals list - proposals closest to closing date appear higher in list', function () {
const minCloseDays = 2;
const maxCloseDays = 3;
// 3001-VOTE-005
const proposalDays = [
minCloseDays + 1,
maxCloseDays,
minCloseDays + 3,
minCloseDays + 2,
];
const proposalDays = [364, 50, 2];
for (let index = 0; index < proposalDays.length; index++) {
goToMakeNewProposal(governanceProposalType.RAW);
enterRawProposalBody(
@@ -64,19 +55,12 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
waitForProposalSync();
}
const arrayOfProposals: string[] = [];
navigateTo(navigation.proposals);
cy.get(proposalDetailsTitle)
.each((proposalTitleElement) => {
arrayOfProposals.push(proposalTitleElement.text());
})
.then(() => {
cy.wrap(getSortOrderOfSuppliedArray(arrayOfProposals)).should(
'equal',
'descending'
);
});
cy.get(openProposals).within(() => {
cy.get(proposalClosingDate).first().should('contain.text', 'year');
cy.get(proposalClosingDate).should('contain.text', 'months');
cy.get(proposalClosingDate).last().should('contain.text', 'days');
});
});
it('Newly created proposals list - able to filter by proposerID to show it in list', function () {
@@ -40,18 +40,22 @@ const stakeAddStakeRadioButton = 'add-stake-radio';
const stakeMaximumTokens = 'token-amount-use-maximum';
const vegaWalletAssociatedBalance = 'currency-value';
const vegaWalletStakedBalances = 'vega-wallet-balance-staked-validators';
const ethWalletContainer = 'ethereum-wallet';
const ethWallet = 'ethereum-wallet';
const vegaWallet = 'vega-wallet';
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
const txTimeout = Cypress.env('txTimeout');
const epochTimeout = Cypress.env('epochTimeout');
const getEthereumWallet = () => cy.get(`[data-testid="${ethWallet}"]:visible`);
const getVegaWallet = () => cy.get(`[data-testid="${vegaWallet}"]:visible`);
context(
'Staking Tab - with eth and vega wallets connected',
{ tags: '@slow' },
function () {
// 2001-STKE-002, 2001-STKE-032
before('visit staking tab and connect vega wallet', function () {
cy.clearAllLocalStorage();
cy.visit('/');
ethereumWalletConnect();
// this is a workaround for #2422 which can be removed once issue is resolved
@@ -187,31 +191,35 @@ context(
.should('contain', 1.0, txTimeout);
closeStakingDialog();
navigateTo(navigation.validators);
cy.get(`[row-id="${0}"]`).within(() => {
cy.getByTestId(stakeValidatorListTotalStake)
.should('have.text', '2.00')
.and('be.visible');
cy.getByTestId(stakeValidatorListTotalShare)
.should('have.text', '66.67%')
.and('be.visible');
cy.getByTestId(stakeValidatorListTotalStake)
.scrollIntoView()
.should('have.text', '2.00')
.and('be.visible');
});
cy.get(`[row-id="${1}"]`).within(() => {
cy.getByTestId(stakeValidatorListTotalStake)
.scrollIntoView()
.should('have.text', '1.00')
.and('be.visible');
cy.getByTestId(stakeValidatorListTotalShare)
.should('have.text', '33.33%')
.and('be.visible');
cy.getByTestId(stakeValidatorListTotalStake)
.scrollIntoView()
.should('have.text', '1.00')
.and('be.visible');
});
cy.get(`[row-id="${0}"]`)
.eq(1)
.within(() => {
cy.getByTestId(stakeValidatorListTotalStake)
.should('have.text', '2.00')
.and('be.visible');
cy.getByTestId(stakeValidatorListTotalShare)
.should('have.text', '66.67%')
.and('be.visible');
cy.getByTestId(stakeValidatorListTotalStake)
.scrollIntoView()
.should('have.text', '2.00')
.and('be.visible');
});
cy.get(`[row-id="${1}"]`)
.eq(1)
.within(() => {
cy.getByTestId(stakeValidatorListTotalStake)
.scrollIntoView()
.should('have.text', '1.00')
.and('be.visible');
cy.getByTestId(stakeValidatorListTotalShare)
.should('have.text', '33.33%')
.and('be.visible');
cy.getByTestId(stakeValidatorListTotalStake)
.scrollIntoView()
.should('have.text', '1.00')
.and('be.visible');
});
});
// 2001-STKE-041
@@ -329,11 +337,11 @@ context(
verifyStakedBalance(2.0);
closeStakingDialog();
stakingPageDisassociateAllTokens();
cy.getByTestId(ethWalletContainer).within(() => {
getEthereumWallet().within(() => {
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
});
verifyEthWalletTotalAssociatedBalance('0.0');
cy.getByTestId(vegaWallet).within(() => {
getVegaWallet().within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'0.00'
@@ -357,11 +365,11 @@ context(
verifyStakedBalance(2.0);
closeStakingDialog();
stakingPageDisassociateAllTokens('contract');
cy.getByTestId(ethWalletContainer).within(() => {
getEthereumWallet().within(() => {
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
});
verifyEthWalletTotalAssociatedBalance('0.0');
cy.getByTestId(vegaWallet).within(() => {
getVegaWallet().within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'0.00'
@@ -386,7 +394,7 @@ context(
closeStakingDialog();
stakingPageDisassociateTokens('1');
verifyEthWalletTotalAssociatedBalance('2.0');
cy.getByTestId(vegaWallet).within(() => {
getVegaWallet().within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'2.00'
@@ -453,7 +461,7 @@ context(
verifyUnstakedBalance(0.0);
closeStakingDialog();
stakingPageAssociateTokens('6');
cy.getByTestId(vegaWallet).within(() => {
getVegaWallet().within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'12.00'
@@ -17,9 +17,11 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
it('should display announcement banner', function () {
cy.getByTestId('app-announcement')
.should('be.visible')
.should('contain.text', 'TEST ANNOUNCEMENT!')
.within(() => {
cy.getByTestId('external-link').should('exist');
cy.getByTestId('external-link')
.should('have.attr', 'href', 'https://fairground.wtf')
.and('have.text', 'CLICK LINK');
});
cy.getByTestId('app-announcement-close').should('be.visible').click();
cy.getByTestId('app-announcement').should('not.exist');
@@ -3,11 +3,14 @@ import {
navigation,
verifyPageHeader,
verifyTabHighlighted,
waitForSpinner,
} from '../../support/common.functions';
import {
goToMakeNewProposal,
governanceProposalType,
} from '../../support/governance.functions';
import { mockNetworkUpgradeProposal } from '../../support/proposal.functions';
const proposalDocumentationLink = '[data-testid="proposal-documentation-link"]';
const newProposalButton = '[data-testid="new-proposal-link"]';
const newProposalLink = '[data-testid="new-proposal-link"]';
const governanceDocsUrl = 'https://vega.xyz/governance';
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
@@ -21,56 +24,140 @@ context(
navigateTo(navigation.proposals);
});
describe('with no network change proposals', function () {
it('should have governance tab highlighted', function () {
verifyTabHighlighted(navigation.proposals);
it('should have governance tab highlighted', function () {
verifyTabHighlighted(navigation.proposals);
});
it('should have GOVERNANCE header visible', function () {
verifyPageHeader('Proposals');
});
it('should be able to see a working link for - find out more about Vega governance', function () {
// 3001-VOTE-001
cy.get(proposalDocumentationLink)
.should('be.visible')
.and('have.text', 'Find out more about Vega governance')
.and('have.attr', 'href')
.and('equal', governanceDocsUrl);
// 3002-PROP-001
cy.request(governanceDocsUrl)
.its('body')
.then((body) => {
if (!body.includes('Govern the network')) {
assert.include(
body,
'Govern the network',
`Checking that governance link destination includes 'Govern the network' text`
);
}
});
});
it('should be able to see button for - new proposal', function () {
// 3001-VOTE-002
cy.get(newProposalLink)
.should('be.visible')
.and('have.text', 'New proposal')
.and('have.attr', 'href')
.and('equal', '/proposals/propose');
});
it('should be able to see a connect wallet button - if vega wallet disconnected and user is submitting new proposal', function () {
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
cy.get(connectToVegaWalletButton)
.should('be.visible')
.and('have.text', 'Connect Vega wallet');
});
it('should see open network upgrade proposal on homepage', function () {
mockNetworkUpgradeProposal();
cy.visit('/');
cy.getByTestId('home-proposal-list').within(() => {
cy.getByTestId('protocol-upgrade-proposals-list-item').should('exist');
cy.getByTestId('protocol-upgrade-proposal-title').should(
'have.text',
'Vega release v1'
);
});
});
it('should have GOVERNANCE header visible', function () {
verifyPageHeader('Proposals');
});
it('should be able to see a working link for - find out more about Vega governance', function () {
// 3001-VOTE-001
cy.get(proposalDocumentationLink)
.should('be.visible')
.and('have.text', 'Find out more about Vega governance')
.and('have.attr', 'href')
.and('equal', governanceDocsUrl);
// 3002-PROP-001
cy.request(governanceDocsUrl)
.its('body')
.then((body) => {
if (!body.includes('Govern the network')) {
assert.include(
body,
'Govern the network',
`Checking that governance link destination includes 'Govern the network' text`
);
}
it('should see network upgrade proposals in proposals list', function () {
mockNetworkUpgradeProposal();
navigateTo(navigation.proposals);
cy.getByTestId('open-proposals').within(() => {
cy.get('li')
.eq(0)
.should(
'have.attr',
'data-testid',
'protocol-upgrade-proposals-list-item'
)
.within(() => {
cy.get('h2').should('have.text', 'Vega release v1');
cy.getByTestId('protocol-upgrade-proposal-type').should(
'have.text',
'Network Upgrade'
);
cy.getByTestId('protocol-upgrade-proposal-release-tag').should(
'have.text',
'Vega release tagv1'
);
cy.getByTestId('protocol-upgrade-proposal-block-height').should(
'have.text',
'Upgrade block height2015942'
);
cy.getByTestId('protocol-upgrade-proposal-status').should(
'have.text',
'Approved'
);
});
});
it('should be able to see button for - new proposal', function () {
// 3001-VOTE-002
cy.get(newProposalLink)
.should('be.visible')
.and('have.text', 'New proposal')
.and('have.attr', 'href')
.and('equal', '/proposals/propose');
cy.getByTestId('closed-proposals').within(() => {
cy.getByTestId('protocol-upgrade-proposals-list-item').should(
'have.length',
1
);
});
});
// Skipping this test for now, the new proposal button no longer takes a user directly
// to a proposal form, instead it takes them to a page where they can select a proposal type.
// Keeping this test here for now as it can be repurposed to test the new proposal forms.
it.skip('should be able to see a connect wallet button - if vega wallet disconnected and new proposal button selected', function () {
cy.get(newProposalButton).should('be.visible').click();
cy.get(connectToVegaWalletButton)
.should('be.visible')
.and('have.text', 'Connect Vega wallet');
navigateTo(navigation.proposals);
waitForSpinner();
it('should see details of network upgrade proposal', function () {
mockNetworkUpgradeProposal();
navigateTo(navigation.proposals);
cy.getByTestId('protocol-upgrade-proposals-list-item')
.first()
.find('[data-testid="view-proposal-btn"]')
.click();
cy.getByTestId('protocol-upgrade-proposal').within(() => {
cy.get('h1').should('have.text', 'Vega Release v1');
cy.getByTestId('protocol-upgrade-block-height').should(
'have.text',
'2015942 (currently 2014133)'
);
cy.getByTestId('protocol-upgrade-state').should(
'have.text',
'Approved'
);
cy.getByTestId('protocol-upgrade-release-tag').should(
'have.text',
'v1'
);
cy.getByTestId('protocol-upgrade-approval-status')
.should('contain.text', '99.98% approval (% validator voting power)')
.and('contain.text', '(67% voting power required)');
cy.get('h2').should('contain.text', 'Approvers (4/4 validators)');
cy.getByTestId('validator-name')
.should('have.length', 4)
.each(($validator) => {
cy.wrap($validator).find('a').should('have.attr', 'href');
});
cy.getByTestId('validator-voting-power').each(
($validatorVotingPower) => {
cy.wrap($validatorVotingPower)
.invoke('text')
.should('contain', '%');
}
);
});
});
}
@@ -45,10 +45,12 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
navigateTo(navigation.proposals);
goToMakeNewProposal('Freeform');
enterUniqueFreeFormProposalBody('50', 'pub key proposal test');
cy.getByTestId('dialog-content').within(() => {
cy.get('h1').should('have.text', 'Transaction failed');
cy.getByTestId('Error').should('have.text', expectedErrorTxt);
});
cy.getByTestId('dialog-content')
.first()
.within(() => {
cy.get('h1').should('have.text', 'Transaction failed');
cy.getByTestId('Error').should('have.text', expectedErrorTxt);
});
});
it('Able to disconnect via banner', function () {
@@ -3,6 +3,7 @@ import {
navigation,
verifyPageHeader,
} from '../../support/common.functions';
import { waitForBeginningOfEpoch } from '../../support/staking.functions';
const viewToggle = '[data-testid="epoch-reward-view-toggle-total"]';
const warning = '[data-testid="callout"]';
@@ -37,6 +38,41 @@ context(
it('should have toggle for seeing total vs individual rewards', function () {
cy.get(viewToggle).should('be.visible');
});
// Skipping due to bug #3471 causing flaky failuress
it.skip('should have option to view go to next and previous page', function () {
waitForBeginningOfEpoch();
cy.getByTestId('page-info')
.should('contain.text', 'Page ')
.invoke('text')
.then(($currentPage) => {
const currentPageNumber = Number($currentPage.slice(5));
cy.getByTestId('goto-next-page').click();
cy.getByTestId('page-info')
.invoke('text')
.then(($newPageNumber) => {
const newPageNumber = Number($newPageNumber.slice(5));
expect(newPageNumber).to.be.greaterThan(currentPageNumber);
cy.getByTestId('goto-previous-page').click();
cy.getByTestId('page-info').should(
'contain.text',
$currentPage
);
});
});
});
it('should have option to go to last and newest page', function () {
waitForBeginningOfEpoch();
cy.getByTestId('goto-last-page').click();
cy.getByTestId('epoch-total-rewards-table')
.last()
.find('h2')
.first()
.should('have.text', 'EPOCH 1');
cy.getByTestId('goto-first-page').click();
cy.get('h2').should('not.contain.text', 'EPOCH 1');
});
});
}
);
@@ -1,7 +1,6 @@
/// <reference types="cypress" />
import {
navigateTo,
navigation,
verifyPageHeader,
verifyTabHighlighted,
@@ -34,8 +33,8 @@ const stakeNumberRegex = /^\d*\.?\d*$/;
context('Validators Page - verify elements on page', function () {
before('navigate to validators page', function () {
cy.visit('/');
navigateTo(navigation.validators);
cy.clearAllLocalStorage();
cy.visit('/validators');
});
describe('with wallets disconnected', { tags: '@smoke' }, function () {
@@ -43,23 +43,25 @@ context(
// 1005-VEST-020 1005-VEST-021
it('Tokens in vesting contract for eth wallet is displayed on wallet window', function () {
cy.getByTestId('vega-in-vesting-contract').within(() => {
cy.getByTestId('currency-title')
.should('contain.text', 'VEGA')
.and('contain.text', 'In vesting contract');
cy.get('[data-testid="currency-value"]:visible').should(
'have.text',
lockedTokensInVestingContract
);
cy.get('[data-testid="currency-locked"]:visible').should(
'have.text',
lockedTokensInVestingContract
);
cy.get('[data-testid="currency-unlocked"]:visible').should(
'have.text',
'0.00'
);
});
cy.get('[data-testid="vega-in-vesting-contract"]:visible').within(
() => {
cy.getByTestId('currency-title')
.should('contain.text', 'VEGA')
.and('contain.text', 'In vesting contract');
cy.get('[data-testid="currency-value"]:visible').should(
'have.text',
lockedTokensInVestingContract
);
cy.get('[data-testid="currency-locked"]:visible').should(
'have.text',
lockedTokensInVestingContract
);
cy.get('[data-testid="currency-unlocked"]:visible').should(
'have.text',
'0.00'
);
}
);
});
// 1005-VEST-022 1005-VEST-023
it('Tokens amount displayed in vesting page', function () {
@@ -17,7 +17,7 @@ const vegaInWallet = '[data-testid="vega-in-wallet"]:visible';
const progressBar = '[data-testid="progress-bar"]:visible';
const currencyLocked = '[data-testid="currency-locked"]:visible';
const currencyUnlocked = '[data-testid="currency-unlocked"]:visible';
const dialog = '[role="dialog"]';
const dialog = '[role="dialog"]:visible';
const dialogHeader = '[data-testid="dialog-title"]';
const dialogCloseBtn = '[data-testid="dialog-close"]';
@@ -68,8 +68,10 @@ context(
it('should have connector list visible', function () {
const connectList = [
'Unknown',
'MetaMask, Brave or other injected web wallet',
'MetaMask',
'Coinbase',
'WalletConnect',
'WalletConnect Legacy',
];
cy.get(connectorList).within(() => {
cy.get('button').each(($btn, i) => {
@@ -7,7 +7,7 @@ const walletContainer = 'aside [data-testid="vega-wallet"]';
const walletHeader = '[data-testid="wallet-header"] h1';
const connectButton = '[data-testid="connect-vega-wallet"]';
const getVegaLink = '[data-testid="link"]';
const dialog = '[role="dialog"]';
const dialog = '[role="dialog"]:visible';
const dialogHeader = '[data-testid="dialog-title"]';
const walletDialogHeader = '[data-testid="wallet-dialog-title"]';
const connectorsList = '[data-testid="connectors-list"]';
@@ -35,6 +35,7 @@ context(
{ tags: '@regression' },
() => {
before('visit token home page', () => {
cy.clearAllLocalStorage();
cy.visit('/');
cy.get(walletContainer, { timeout: 60000 }).should('be.visible');
});
@@ -333,10 +334,8 @@ context(
.parent()
.siblings()
.invoke('text')
.then((el) => {
const value = parseFloat(el);
cy.wrap(value).should('be.gte', parseFloat(expectedAmount));
});
.then(parseFloat)
.should('be.gte', parseFloat(expectedAmount));
cy.get(vegaWalletCurrencyTitle)
.contains(id)
@@ -12,6 +12,7 @@ context(
{ tags: '@smoke' },
function () {
before('navigate to withdrawals page', function () {
cy.clearAllLocalStorage();
cy.visit('/');
navigateTo(navigation.withdraw);
});
@@ -26,9 +26,11 @@ const topLevelRoutes = [
export function navigateTo(page: navigation) {
if (!topLevelRoutes.includes(page)) {
cy.getByTestId(tokenDropDown, { timeout: 10000 }).eq(0).click();
cy.getByTestId('token-dropdown').within(() => {
cy.get(page).eq(0).click();
});
cy.getByTestId('token-dropdown')
.first()
.within(() => {
cy.get(page).eq(0).click();
});
} else {
return cy.get(navigation.section, { timeout: 10000 }).within(() => {
cy.get(page).eq(0).click();
@@ -150,18 +150,6 @@ export function waitForProposalSync() {
});
}
export function getSortOrderOfSuppliedArray(suppliedArray: string[]) {
const tempArray = [];
for (let index = 1; index < suppliedArray.length; index++) {
tempArray.push(
suppliedArray[index - 1].localeCompare(suppliedArray[index])
);
}
if (tempArray.every((n) => n <= 0)) return 'ascending';
else if (tempArray.every((n) => n >= 0)) return 'descending';
else return 'unsorted';
}
export function goToMakeNewProposal(proposalType: string) {
navigateTo(navigation.proposals);
cy.get(newProposalButton).should('be.visible').click();
@@ -1,5 +1,9 @@
import { addSeconds, millisecondsToSeconds } from 'date-fns';
import type { ProposalSubmissionBody } from '@vegaprotocol/wallet';
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { upgradeProposalsData } from '../fixtures/mocks/network-upgrade';
import { proposalsData } from '../fixtures/mocks/proposals';
import { nodeData } from '../fixtures/mocks/nodes';
export function createUpdateNetworkProposalTxBody(): ProposalSubmissionBody {
const MIN_CLOSE_SEC = 5;
@@ -80,3 +84,11 @@ export function createFreeFormProposalTxBody(): ProposalSubmissionBody {
},
};
}
export function mockNetworkUpgradeProposal() {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Nodes', nodeData);
aliasGQLQuery(req, 'Proposals', proposalsData);
aliasGQLQuery(req, 'ProtocolUpgrades', upgradeProposalsData);
});
}
@@ -184,16 +184,18 @@ export function validateValidatorListTotalStakeAndShare(
) {
cy.contains('Loading...', epochTimeout).should('not.exist');
waitForBeginningOfEpoch();
cy.get(`[row-id="${positionOnList}"]`).within(() => {
cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should(
'have.text',
expectedTotalStake
);
cy.getByTestId(stakeValidatorListTotalShare, epochTimeout).should(
'have.text',
expectedTotalShare
);
});
cy.get(`[row-id="${positionOnList}"]:visible`)
.eq(1)
.within(() => {
cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should(
'have.text',
expectedTotalStake
);
cy.getByTestId(stakeValidatorListTotalShare, epochTimeout).should(
'have.text',
expectedTotalShare
);
});
}
export function ensureSpecifiedUnstakedTokensAreAssociated(
@@ -218,13 +220,15 @@ export function ensureSpecifiedUnstakedTokensAreAssociated(
}
export function closeStakingDialog() {
cy.getByTestId('dialog-title').should(
cy.get('[data-testid="dialog-title"]:visible').should(
'contain.text',
'At the beginning of the next epoch'
);
cy.getByTestId('dialog-content').within(() => {
cy.get('a').should('have.text', 'Back to Staking').click();
});
cy.get('[data-testid="dialog-content"]:visible')
.first()
.within(() => {
cy.get('a').should('have.text', 'Back to Staking').click();
});
}
export function validateWalletCurrency(
@@ -9,7 +9,7 @@ import {
import { ethers, Wallet } from 'ethers';
const associatedAmountInWallet = '[data-testid="associated-amount"]:visible';
const vegaWalletContainer = 'aside [data-testid="vega-wallet"]';
const vegaWalletContainer = 'aside [data-testid="vega-wallet"]:visible';
const vegaWalletMnemonic = Cypress.env('vegaWalletMnemonic');
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey');
const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress');
@@ -105,24 +105,25 @@ async function vegaWalletTeardownStaking(stakingBridgeContract: StakingBridge) {
{ timeout: transactionTimeout, log: false }
).then((stakeBalance) => {
if (Number(stakeBalance) != 0) {
cy.get('[data-testid="vega-wallet-balance-unstaked"]:visible').within(
() => {
cy.get(associatedAmountInWallet)
.invoke('text')
.then(($walletAmount) => {
cy.wrap(
stakingBridgeContract.remove_stake(
String(stakeBalance),
vegaWalletPubKey
),
{ timeout: transactionTimeout, log: false }
);
cy.get(associatedAmountInWallet, {
cy.get(vegaWalletContainer).within(() => {
cy.getByTestId('currency-value')
.invoke('text')
.then(($associatedAmount) => {
cy.wrap(
stakingBridgeContract.remove_stake(
String(stakeBalance),
vegaWalletPubKey
),
{ timeout: transactionTimeout, log: false }
);
cy.get("[data-testid='currency-value']")
.first()
.invoke('text', {
timeout: transactionTimeout,
}).should('not.have.text', $walletAmount);
});
}
);
})
.should('not.eq', $associatedAmount);
});
});
}
});
}
@@ -134,8 +135,6 @@ async function vegaWalletTeardownVesting(vestingContract: TokenVesting) {
log: false,
}).then((vestingAmount) => {
if (Number(vestingAmount) != 0) {
// Wait needed to allow time for ganache to process tx for stakingBridgeContract.remove_stake
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wrap(
vestingContract.remove_stake(String(vestingAmount), vegaWalletPubKey),
{ timeout: transactionTimeout, log: false }
+1
View File
@@ -14,6 +14,7 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
#Test configuration variables
CYPRESS_FAIRGROUND=false
+2 -1
View File
@@ -5,7 +5,7 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_FAIRGROUND=false
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
NX_VEGA_CONFIG_URL=''
NX_VEGA_URL=http://localhost:3028/query
@@ -20,3 +20,4 @@ NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
#Test configuration variables
CYPRESS_FAIRGROUND=false
+47 -8
View File
@@ -17,6 +17,12 @@ import { AppStateProvider } from './contexts/app-state/app-state-provider';
import { ContractsProvider } from './contexts/contracts/contracts-provider';
import { AppRouter } from './routes';
import type { EthereumConfig } from '@vegaprotocol/web3';
import {
createConnectors,
useEthTransactionManager,
useEthWithdrawApprovalsManager,
useWeb3ConnectStore,
} from '@vegaprotocol/web3';
import { Web3Provider } from '@vegaprotocol/web3';
import { VegaWalletDialogs } from './components/vega-wallet-dialogs';
import { VegaWalletProvider } from '@vegaprotocol/wallet';
@@ -27,10 +33,10 @@ import {
NetworkLoader,
useInitializeEnv,
} from '@vegaprotocol/environment';
import { createConnectors } from './lib/web3-connectors';
import { ENV } from './config/env';
import { ENV } from './config';
import type { InMemoryCacheConfig } from '@apollo/client';
import { WithdrawalDialog } from '@vegaprotocol/withdraws';
import { SplashLoader } from './components/splash-loader';
const cache: InMemoryCacheConfig = {
typePolicies: {
@@ -70,20 +76,52 @@ const cache: InMemoryCacheConfig = {
const Web3Container = ({
chainId,
providerUrl,
}: {
chainId: number;
providerUrl: string;
}) => {
const InitializeHandlers = () => {
useEthTransactionManager();
useEthWithdrawApprovalsManager();
return null;
};
const [connectors, initializeConnectors] = useWeb3ConnectStore((store) => [
store.connectors,
store.initialize,
]);
const { ETHEREUM_PROVIDER_URL, ETH_LOCAL_PROVIDER_URL, ETH_WALLET_MNEMONIC } =
useEnvironment();
useEffect(() => {
if (chainId) {
return initializeConnectors(
createConnectors(
ETHEREUM_PROVIDER_URL,
Number(chainId),
ETH_LOCAL_PROVIDER_URL,
ETH_WALLET_MNEMONIC
),
Number(chainId)
);
}
}, [
chainId,
ETHEREUM_PROVIDER_URL,
initializeConnectors,
ETH_LOCAL_PROVIDER_URL,
ETH_WALLET_MNEMONIC,
]);
const sideBar = React.useMemo(() => {
return [<EthWallet />, <VegaWallet />];
}, []);
const Connectors = React.useMemo(() => {
return createConnectors(providerUrl, Number(chainId));
}, [chainId, providerUrl]);
if (connectors.length === 0) {
// Prevent loading when the connectors are not initialized
return <SplashLoader />;
}
return (
<Web3Provider connectors={Connectors}>
<Web3Connector connectors={Connectors} chainId={Number(chainId)}>
<Web3Provider connectors={connectors}>
<Web3Connector connectors={connectors} chainId={Number(chainId)}>
<VegaWalletProvider>
<ContractsProvider>
<AppLoader>
@@ -97,6 +135,7 @@ const Web3Container = ({
<NetworkInfo />
</footer>
</AppLayout>
<InitializeHandlers />
<VegaWalletDialogs />
<TransactionModal />
<WithdrawalDialog />
@@ -26,6 +26,7 @@ import {
import { Loader } from '@vegaprotocol/ui-toolkit';
import colors from 'tailwindcss/colors';
import { useBalances } from '../../lib/balances/balances-store';
import { useWeb3Disconnect } from '@vegaprotocol/web3';
const removeLeadingAddressSymbol = (key: string) => {
if (key && key.length > 2 && key.slice(0, 2) === '0x') {
@@ -184,6 +185,7 @@ export const EthWallet = () => {
const { appDispatch } = useAppState();
const { account, connector } = useWeb3React();
const pendingTxs = usePendingTransactions();
const disconnect = useWeb3Disconnect(connector);
return (
<WalletCard>
@@ -239,7 +241,7 @@ export const EthWallet = () => {
<div className="flex justify-end">
<button
className="underline"
onClick={() => connector.deactivate()}
onClick={() => disconnect()}
data-testid="disconnect-from-eth-wallet-button"
>
{t('disconnect')}
@@ -1,5 +1,10 @@
import { Button, Splash } from '@vegaprotocol/ui-toolkit';
import { getChainName, Web3ConnectDialog } from '@vegaprotocol/web3';
import {
getChainName,
useWeb3ConnectStore,
useWeb3Disconnect,
Web3ConnectDialog,
} from '@vegaprotocol/web3';
import { useWeb3React } from '@web3-react/core';
import type { ReactElement } from 'react';
import { useCallback, useEffect } from 'react';
@@ -51,7 +56,9 @@ interface Web3ContentProps {
}
export const Web3Content = ({ children, appChainId }: Web3ContentProps) => {
const { error, connector, chainId } = useWeb3React();
const { connector, chainId } = useWeb3React();
const error = useWeb3ConnectStore((store) => store.error);
const disconnect = useWeb3Disconnect(connector);
useEffect(() => {
if (connector?.connectEagerly) {
@@ -67,7 +74,7 @@ export const Web3Content = ({ children, appChainId }: Web3ContentProps) => {
<Splash>
<div className="flex flex-col items-center gap-12">
<p className="text-white">Something went wrong: {error.message}</p>
<Button onClick={() => connector.deactivate()}>Disconnect</Button>
<Button onClick={() => disconnect()}>Disconnect</Button>
</div>
</Splash>
);
@@ -80,7 +87,7 @@ export const Web3Content = ({ children, appChainId }: Web3ContentProps) => {
<p className="text-white">
This app only works on {getChainName(appChainId)}
</p>
<Button onClick={() => connector.deactivate()}>Disconnect</Button>
<Button onClick={() => disconnect()}>Disconnect</Button>
</div>
</Splash>
);
+17 -2
View File
@@ -595,6 +595,7 @@
"noPercentage": "No percentage",
"proposalTerms": "Proposal terms",
"currentlySetTo": "Currently expected to ",
"currently": "currently",
"finalOutcomeMayDiffer": "Final outcome may differ",
"votingPower": "Voting power",
"normalisedVotingPower": "Normalised voting power",
@@ -767,7 +768,7 @@
"performancePenalty": "Performance penalty",
"overstaked": "Overstaked",
"overstakedPenalty": "Overstaked penalty",
"homeProposalsIntro": "Decisions on the Vega network are on-chain, with tokenholders creating proposals that other tokenholders vote to approve or reject.",
"homeProposalsIntro": "Decisions on the Vega network are on-chain, with tokenholders creating proposals that other tokenholders vote to approve or reject. Network upgrades are proposed and approved by validators.",
"homeProposalsButtonText": "Browse, vote, and propose",
"homeValidatorsIntro": "Vega runs on a delegated proof of stake blockchain, where validators earn fees for validating block transactions. Tokenholders can nominate validators by staking tokens to them.",
"homeValidatorsButtonText": "Browse, and stake",
@@ -775,5 +776,19 @@
"homeRewardsButtonText": "See rewards",
"homeVegaTokenIntro": "VEGA Token is a governance asset used to make and vote on proposals, and nominate validators.",
"homeVegaTokenButtonText": "Manage tokens",
"downloadProposalJson": "Download proposal as JSON"
"downloadProposalJson": "Download proposal as JSON",
"networkUpgrade": "Network Upgrade",
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED": "Approved",
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING": "Pending",
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED": "Rejected",
"PROTOCOL_UPGRADE_PROPOSAL_STATUS_UNSPECIFIED": "Unspecified",
"vegaRelease{release}": "Vega Release {{release}}",
"upgradeBlockHeight": "Upgrade block height",
"vegaReleaseTag": "Vega release tag",
"approvalStatus": "Approval status",
"approvers": "Approvers",
"approval (% validator voting power)": "approval (% validator voting power)",
"67% voting power required": "67% voting power required",
"Token": "Token",
"associateVegaNow": "Associate $VEGA now"
}
+18 -26
View File
@@ -1,20 +1,17 @@
import { ethers } from 'ethers';
import type { Web3ReactHooks } from '@web3-react/core';
import { initializeConnector } from '@web3-react/core';
import { MetaMask } from '@web3-react/metamask';
import { WalletConnect } from '@web3-react/walletconnect';
import type { Connector } from '@web3-react/types';
import { ENV } from '../config/env';
import { UrlConnector } from '@vegaprotocol/web3';
import {
initializeMetaMaskConnector,
initializeWalletConnector,
initializeWalletConnectLegacyConnector,
initializeCoinbaseConnector,
WALLETCONNECT_PROJECT_ID,
initializeUrlConnector,
} from '@vegaprotocol/web3';
const [metamask, metamaskHooks] = initializeConnector<MetaMask>(
(actions) => new MetaMask(actions)
);
const [urlConnector, urlHooks] = initializeConnector<UrlConnector>(
(actions) =>
new UrlConnector(actions, ENV.localProviderUrl, ENV.ethWalletMnemonic)
);
initializeUrlConnector(ENV.localProviderUrl, ENV.ethWalletMnemonic);
export const createDefaultProvider = (providerUrl: string, chainId: number) => {
return new ethers.providers.JsonRpcProvider(providerUrl, chainId);
@@ -24,19 +21,14 @@ export const createConnectors = (providerUrl: string, chainId: number) => {
if (isNaN(chainId)) {
throw new Error('Invalid Ethereum chain ID for environment');
}
const [walletconnect, walletconnectHooks] =
initializeConnector<WalletConnect>(
(actions) =>
new WalletConnect(actions, {
rpc: {
[chainId]: providerUrl,
},
}),
[chainId]
);
return [
ENV.urlConnect ? [urlConnector, urlHooks] : null,
[metamask, metamaskHooks],
[walletconnect, walletconnectHooks],
].filter(Boolean) as [Connector, Web3ReactHooks][];
ENV.urlConnect
? initializeUrlConnector(ENV.localProviderUrl, ENV.ethWalletMnemonic)
: null,
initializeMetaMaskConnector(),
initializeCoinbaseConnector(providerUrl),
initializeWalletConnector(WALLETCONNECT_PROJECT_ID, chainId, providerUrl),
initializeWalletConnectLegacyConnector(chainId, providerUrl),
].filter(Boolean) as unknown as [Connector, Web3ReactHooks][];
};
+88 -20
View File
@@ -10,23 +10,31 @@ import {
import { useDocumentTitle } from '../../hooks/use-document-title';
import { useRefreshAfterEpoch } from '../../hooks/use-refresh-after-epoch';
import { ProposalsListItem } from '../proposals/components/proposals-list-item';
import { ProtocolUpgradeProposalsListItem } from '../proposals/components/protocol-upgrade-proposals-list-item/protocol-upgrade-proposals-list-item';
import Routes from '../routes';
import { ExternalLinks, removePaginationWrapper } from '@vegaprotocol/utils';
import { useNodesQuery } from '../staking/home/__generated__/Nodes';
import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals';
import { getNotRejectedProposals } from '../proposals/proposals/proposals-container';
import { useProtocolUpgradesQuery } from '../proposals/protocol-upgrade/__generated__/ProtocolUpgradeProposals';
import {
getNotRejectedProposals,
getNotRejectedProtocolUpgradeProposals,
} from '../proposals/proposals/proposals-container';
import { Heading } from '../../components/heading';
import * as Schema from '@vegaprotocol/types';
import type { RouteChildProps } from '..';
import type { ProposalFieldsFragment } from '../proposals/proposals/__generated__/Proposals';
import type { NodesFragmentFragment } from '../staking/home/__generated__/Nodes';
import type { ProtocolUpgradeProposalFieldsFragment } from '../proposals/protocol-upgrade/__generated__/ProtocolUpgradeProposals';
const nodesToShow = 6;
const HomeProposals = ({
proposals,
protocolUpgradeProposals,
}: {
proposals: ProposalFieldsFragment[];
protocolUpgradeProposals: ProtocolUpgradeProposalFieldsFragment[];
}) => {
const { t } = useTranslation();
@@ -47,6 +55,10 @@ const HomeProposals = ({
data-testid="home-proposal-list"
className="grid md:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2 gap-6"
>
{protocolUpgradeProposals.map((proposal, index) => (
<ProtocolUpgradeProposalsListItem key={index} proposal={proposal} />
))}
{proposals.map((proposal) => (
<ProposalsListItem key={proposal.id} proposal={proposal} />
))}
@@ -107,20 +119,7 @@ const HomeNodes = ({
{trimmedActiveNodes.map(({ id, avatarUrl, name }) => (
<div key={id} data-testid="validators" className="col-span-2">
<Link to={`${Routes.VALIDATORS}/${id}`}>
<RoundedWrapper paddingBottom={true} border={false}>
<div className="flex items-center justify-center m-[-1rem] p-4 bg-neutral-900 hover:bg-neutral-800">
{avatarUrl && (
<img
className="h-6 w-6 rounded-full mr-2"
src={avatarUrl}
alt={`Avatar icon for ${name}`}
/>
)}
<span className="text-sm">{name}</span>
</div>
</RoundedWrapper>
</Link>
<ValidatorDetailsLink id={id} avatarUrl={avatarUrl} name={name} />
</div>
))}
</div>
@@ -136,6 +135,35 @@ const HomeNodes = ({
);
};
interface ValidatorDetailsLinkProps {
id: string;
avatarUrl: string | null | undefined;
name: string;
}
export const ValidatorDetailsLink = ({
id,
avatarUrl,
name,
}: ValidatorDetailsLinkProps) => {
return (
<Link to={`${Routes.VALIDATORS}/${id}`}>
<RoundedWrapper paddingBottom={true} border={false}>
<div className="flex items-center justify-center m-[-1rem] p-3 bg-neutral-900 hover:bg-neutral-800">
{avatarUrl && (
<img
className="h-6 w-6 rounded-full mr-2"
src={avatarUrl}
alt={`Avatar icon for ${name}`}
/>
)}
<span className="text-sm">{name}</span>
</div>
</RoundedWrapper>
</Link>
);
};
const GovernanceHome = ({ name }: RouteChildProps) => {
useDocumentTitle(name);
const { t } = useTranslation();
@@ -149,6 +177,16 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
errorPolicy: 'ignore',
});
const {
data: protocolUpgradesData,
loading: protocolUpgradesLoading,
error: protocolUpgradesError,
} = useProtocolUpgradesQuery({
pollInterval: 5000,
fetchPolicy: 'network-only',
errorPolicy: 'ignore',
});
const {
data: validatorsData,
error: validatorsError,
@@ -163,11 +201,38 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
proposalsData
? getNotRejectedProposals<ProposalFieldsFragment>(
proposalsData.proposalsConnection
).slice(0, 3)
)
: [],
[proposalsData]
);
const protocolUpgradeProposals = useMemo(
() =>
protocolUpgradesData
? getNotRejectedProtocolUpgradeProposals<ProtocolUpgradeProposalFieldsFragment>(
protocolUpgradesData.protocolUpgradeProposals
).filter(
(p) =>
Number(p.upgradeBlockHeight) >
Number(protocolUpgradesData.lastBlockHeight)
)
: [],
[protocolUpgradesData]
);
const totalProposalsDesired = 4;
const protocolUpgradeProposalsToShow = protocolUpgradeProposals.slice(
0,
totalProposalsDesired
);
const proposalsToShow =
protocolUpgradeProposalsToShow.length === totalProposalsDesired
? []
: proposals.slice(
0,
totalProposalsDesired - protocolUpgradeProposalsToShow.length
);
const activeNodes = removePaginationWrapper(
validatorsData?.nodesConnection.edges
);
@@ -182,11 +247,14 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
return (
<AsyncRenderer
loading={proposalsLoading || validatorsLoading}
error={proposalsError || validatorsError}
data={proposalsData && validatorsData}
loading={proposalsLoading || protocolUpgradesLoading || validatorsLoading}
error={proposalsError || protocolUpgradesError || validatorsError}
data={proposalsData && protocolUpgradesData && validatorsData}
>
<HomeProposals proposals={proposals} />
<HomeProposals
proposals={proposalsToShow}
protocolUpgradeProposals={protocolUpgradeProposalsToShow}
/>
<HomeNodes
activeNodes={activeNodes}
@@ -63,7 +63,7 @@ const renderComponent = (proposals: ProposalQuery['proposal'][]) => (
<MockedProvider mocks={[networkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposalsList proposals={proposals} />
<ProposalsList proposals={proposals} protocolUpgradeProposals={[]} />
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
@@ -3,17 +3,21 @@ import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Heading, SubHeading } from '../../../../components/heading';
import { ProposalsListItem } from '../proposals-list-item';
import { ProtocolUpgradeProposalsListItem } from '../protocol-upgrade-proposals-list-item/protocol-upgrade-proposals-list-item';
import { ProposalsListFilter } from '../proposals-list-filter';
import Routes from '../../../routes';
import { Button } from '@vegaprotocol/ui-toolkit';
import { Link } from 'react-router-dom';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import { ExternalLinks } from '@vegaprotocol/utils';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProtocolUpgradeProposalFieldsFragment } from '../../protocol-upgrade/__generated__/ProtocolUpgradeProposals';
interface ProposalsListProps {
proposals: Array<ProposalFieldsFragment | ProposalQuery['proposal']>;
protocolUpgradeProposals: ProtocolUpgradeProposalFieldsFragment[];
lastBlockHeight?: string;
}
interface SortedProposalsProps {
@@ -21,7 +25,16 @@ interface SortedProposalsProps {
closed: Array<ProposalFieldsFragment | ProposalQuery['proposal']>;
}
export const ProposalsList = ({ proposals }: ProposalsListProps) => {
interface SortedProtocolUpgradeProposalsProps {
open: ProtocolUpgradeProposalFieldsFragment[];
closed: ProtocolUpgradeProposalFieldsFragment[];
}
export const ProposalsList = ({
proposals,
protocolUpgradeProposals,
lastBlockHeight,
}: ProposalsListProps) => {
const { t } = useTranslation();
const [filterString, setFilterString] = useState('');
const sortedProposals = proposals.reduce(
@@ -39,6 +52,21 @@ export const ProposalsList = ({ proposals }: ProposalsListProps) => {
}
);
const sortedProtocolUpgradeProposals = protocolUpgradeProposals.reduce(
(acc: SortedProtocolUpgradeProposalsProps, proposal) => {
if (Number(proposal?.upgradeBlockHeight) > Number(lastBlockHeight)) {
acc.open.push(proposal);
} else {
acc.closed.push(proposal);
}
return acc;
},
{
open: [],
closed: [],
}
);
const filterPredicate = (
p: ProposalFieldsFragment | ProposalQuery['proposal']
) =>
@@ -65,7 +93,7 @@ export const ProposalsList = ({ proposals }: ProposalsListProps) => {
</div>
<p className="mb-8">
{t(
`The Vega network is governed by the community. View active proposals, vote on them or propose changes to the network.`
`The Vega network is governed by the community. View active proposals, vote on them or propose changes to the network. Network upgrades are proposed and approved by validators.`
)}{' '}
<ExternalLink
data-testid="proposal-documentation-link"
@@ -80,8 +108,15 @@ export const ProposalsList = ({ proposals }: ProposalsListProps) => {
)}
<section className="-mx-4 p-4 mb-8 bg-neutral-800">
<SubHeading title={t('openProposals')} />
{sortedProposals.open.length > 0 ? (
{sortedProposals.open.length > 0 ||
sortedProtocolUpgradeProposals.open.length > 0 ? (
<ul data-testid="open-proposals">
{sortedProtocolUpgradeProposals.open.map((proposal) => (
<ProtocolUpgradeProposalsListItem
key={proposal.upgradeBlockHeight}
proposal={proposal}
/>
))}
{sortedProposals.open.filter(filterPredicate).map((proposal) => (
<ProposalsListItem key={proposal?.id} proposal={proposal} />
))}
@@ -94,8 +129,16 @@ export const ProposalsList = ({ proposals }: ProposalsListProps) => {
</section>
<section>
<SubHeading title={t('closedProposals')} />
{sortedProposals.closed.length > 0 ? (
{sortedProposals.closed.length > 0 ||
sortedProtocolUpgradeProposals.closed.length > 0 ? (
<ul data-testid="closed-proposals">
{sortedProtocolUpgradeProposals.closed.map((proposal) => (
<ProtocolUpgradeProposalsListItem
key={proposal.upgradeBlockHeight}
proposal={proposal}
/>
))}
{sortedProposals.closed.filter(filterPredicate).map((proposal) => (
<ProposalsListItem key={proposal?.id} proposal={proposal} />
))}
@@ -0,0 +1 @@
export * from './protocol-update-proposal-detail-approvals';
@@ -0,0 +1,81 @@
import { useTranslation } from 'react-i18next';
import {
RoundedWrapper,
KeyValueTable,
KeyValueTableRow,
} from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
import { ValidatorDetailsLink } from '../../../home';
import { getNormalisedVotingPower } from '../../../staking/shared';
import type { NodesFragmentFragment } from '../../../staking/home/__generated__/Nodes';
export interface ProtocolUpdateProposalDetailApprovalsProps {
totalConsensusValidators: number;
// Consensus validators that have approved the proposal
consensusApprovals: NodesFragmentFragment[];
consensusApprovalsVotingPowerPercentage: string;
}
export const ProtocolUpdateProposalDetailApprovals = ({
totalConsensusValidators,
consensusApprovals,
consensusApprovalsVotingPowerPercentage,
}: ProtocolUpdateProposalDetailApprovalsProps) => {
const { t } = useTranslation();
return (
<>
<div className="mb-10">
<SubHeading title={t('approvalStatus')} />
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
<KeyValueTable data-testid="protocol-upgrade-approval-status">
<KeyValueTableRow noBorder={true}>
<span>{`${consensusApprovalsVotingPowerPercentage} ${t(
'approval (% validator voting power)'
)}`}</span>
<span>({t('67% voting power required')})</span>
</KeyValueTableRow>
</KeyValueTable>
</RoundedWrapper>
</div>
<div className="mb-10">
<SubHeading
title={`${t('approvers')} (${
consensusApprovals.length
}/${totalConsensusValidators} validators)`}
/>
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
<KeyValueTable data-testid="protocol-upgrade-approvers">
<KeyValueTableRow>
<div className="mb-2">{t('validator')}</div>
<div className="text-white mb-2">{t('votingPower')}</div>
</KeyValueTableRow>
{consensusApprovals.map((validator, index) => (
<KeyValueTableRow
noBorder={index === consensusApprovals?.length - 1}
key={validator.pubkey}
>
<div className="-mb-3 mt-1" data-testid={'validator-name'}>
<ValidatorDetailsLink
id={validator.id}
avatarUrl={validator.avatarUrl}
name={validator.name}
/>
</div>
<span data-testid="validator-voting-power">
{getNormalisedVotingPower(
validator.rankingScore.votingPower,
2
)}
</span>
</KeyValueTableRow>
))}
</KeyValueTable>
</RoundedWrapper>
</div>
</>
);
};
@@ -0,0 +1,86 @@
import { render, screen } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import * as Schema from '@vegaprotocol/types';
import { ProtocolUpdateProposalDetailApprovals } from './protocol-update-proposal-detail-approvals';
import { getNormalisedVotingPower } from '../../../staking/shared';
import type { ProtocolUpdateProposalDetailApprovalsProps } from './protocol-update-proposal-detail-approvals';
import type { NodesFragmentFragment } from '../../../staking/home/__generated__/Nodes';
describe('ProtocolUpdateProposalDetailApprovals', () => {
const mockValidators: NodesFragmentFragment[] = [
{
id: 'ccc022b7e63a4d0a6d3a193c3940c88574060e58a184964c994998d86835a1b4',
name: 'Marvin',
avatarUrl:
'https://upload.wikimedia.org/wikipedia/en/2/25/Marvin-TV-3.jpg',
pubkey:
'6abc23391a9f888ab240415bf63d6844b03fc360be822f4a1d2cd832d87b2917',
stakedTotal: '14182454495731682635157',
stakedByOperator: '1000000000000000000000',
stakedByDelegates: '13182454495731682635157',
pendingStake: '0',
rankingScore: {
rankingScore: '0.67845061012234727427532760837568',
stakeScore: '0.3392701644525644',
performanceScore: '0.9998677767864936',
votingPower: '3500',
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
__typename: 'RankingScore',
},
__typename: 'Node',
},
];
const defaultProps = {
totalConsensusValidators: 3,
consensusApprovals: mockValidators,
consensusApprovalsVotingPowerPercentage: '75%',
};
const renderComponent = (
props: Partial<ProtocolUpdateProposalDetailApprovalsProps> = {}
) => {
const mergedProps = {
...defaultProps,
...props,
};
return render(
<BrowserRouter>
<ProtocolUpdateProposalDetailApprovals {...mergedProps} />
</BrowserRouter>
);
};
it('renders without crashing', () => {
renderComponent();
expect(
screen.getByTestId('protocol-upgrade-approval-status')
).toBeInTheDocument();
expect(
screen.getByTestId('protocol-upgrade-approvers')
).toBeInTheDocument();
});
it('renders the correct number of consensus approvers', () => {
renderComponent();
const validators = screen.getAllByTestId(/validator-name/);
expect(validators.length).toBe(mockValidators.length);
});
it('renders the correct approval status with the required percentage', () => {
renderComponent();
expect(screen.getByText(/75% approval/i)).toBeInTheDocument();
expect(screen.getByText(/67% voting power required/i)).toBeInTheDocument();
});
it('renders the correct voting power for each validator', () => {
renderComponent();
mockValidators.forEach((validator) => {
const normalisedVotingPower = getNormalisedVotingPower(
validator.rankingScore.votingPower,
2
);
expect(screen.getByText(normalisedVotingPower)).toBeInTheDocument();
});
});
});
@@ -0,0 +1 @@
export * from './protocol-upgrade-proposal-detail-header';
@@ -0,0 +1,18 @@
import { render } from '@testing-library/react';
import { ProtocolUpgradeProposalDetailHeader } from './protocol-upgrade-proposal-detail-header';
describe('ProtocolUpgradeProposalDetailHeader', () => {
it('should render successfully', () => {
const { baseElement } = render(
<ProtocolUpgradeProposalDetailHeader releaseTag="v1.0.0" />
);
expect(baseElement).toBeTruthy();
});
it('should render the release tag', () => {
const { getByText } = render(
<ProtocolUpgradeProposalDetailHeader releaseTag="v1.0.0" />
);
expect(getByText('Vega Release v1.0.0')).toBeTruthy();
});
});
@@ -0,0 +1,21 @@
import { useTranslation } from 'react-i18next';
import { Intent, Lozenge } from '@vegaprotocol/ui-toolkit';
import { Heading } from '../../../../components/heading';
export interface ProtocolUpgradeProposalDetailHeaderProps {
releaseTag: string;
}
export const ProtocolUpgradeProposalDetailHeader = ({
releaseTag,
}: ProtocolUpgradeProposalDetailHeaderProps) => {
const { t } = useTranslation();
return (
<>
<Heading title={t('vegaRelease{release}', { release: releaseTag })} />
<div className="mb-10">
<Lozenge variant={Intent.Success}>{t('networkUpgrade')}</Lozenge>
</div>
</>
);
};
@@ -0,0 +1 @@
export * from './protocol-upgrade-proposal-detail-info';
@@ -0,0 +1,44 @@
// jest tests for the protocol upgrade proposal detail info component
import { render } from '@testing-library/react';
import { ProtocolUpgradeProposalStatus } from '@vegaprotocol/types';
import { ProtocolUpgradeProposalDetailInfo } from './protocol-upgrade-proposal-detail-info';
const renderComponent = () =>
render(
<ProtocolUpgradeProposalDetailInfo
proposal={{
vegaReleaseTag: 'v0.1.234',
status:
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING,
upgradeBlockHeight: '12345',
approvers: [],
}}
/>
);
describe('ProtocolUpgradeProposalDetailInfo', () => {
it('should render successfully', () => {
const { baseElement } = renderComponent();
expect(baseElement).toBeTruthy();
});
it('should render the upgrade block height', () => {
const { getByTestId } = renderComponent();
expect(getByTestId('protocol-upgrade-block-height')).toHaveTextContent(
'12345'
);
});
it('should render the state', () => {
const { getByTestId } = renderComponent();
expect(getByTestId('protocol-upgrade-state')).toHaveTextContent('Pending');
});
it('should render the vega release tag', () => {
const { getByTestId } = renderComponent();
expect(getByTestId('protocol-upgrade-release-tag')).toHaveTextContent(
'v0.1.234'
);
});
});
@@ -0,0 +1,58 @@
import { useTranslation } from 'react-i18next';
import {
KeyValueTable,
KeyValueTableRow,
RoundedWrapper,
} from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
import type { ProtocolUpgradeProposalFieldsFragment } from '../../protocol-upgrade/__generated__/ProtocolUpgradeProposals';
export interface ProtocolUpgradeProposalDetailInfoProps {
proposal: ProtocolUpgradeProposalFieldsFragment;
lastBlockHeight?: string;
}
export const ProtocolUpgradeProposalDetailInfo = ({
proposal,
lastBlockHeight,
}: ProtocolUpgradeProposalDetailInfoProps) => {
const { t } = useTranslation();
return (
<div className="mb-10">
<SubHeading title={t('proposal')} />
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
<KeyValueTable data-testid="protocol-upgrade-proposal-details">
<KeyValueTableRow>
<span className="uppercase">{t('upgradeBlockHeight')}</span>
<span data-testid="protocol-upgrade-block-height">
{proposal.upgradeBlockHeight}{' '}
{lastBlockHeight && (
<>
({t('currently')} {lastBlockHeight})
</>
)}
</span>
</KeyValueTableRow>
<KeyValueTableRow>
<span className="uppercase">{t('state')}</span>
<span data-testid="protocol-upgrade-state">
{t(`${proposal.status}`)}
</span>
</KeyValueTableRow>
<KeyValueTableRow noBorder={true}>
<span className="uppercase">{t('vegaReleaseTag')}</span>
<span data-testid="protocol-upgrade-release-tag">
{proposal.vegaReleaseTag}
</span>
</KeyValueTableRow>
</KeyValueTable>
</RoundedWrapper>
</div>
);
};
@@ -0,0 +1,69 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import { ProtocolUpgradeProposalsListItem } from './protocol-upgrade-proposals-list-item';
import { ProtocolUpgradeProposalStatus } from '@vegaprotocol/types';
import type { ProtocolUpgradeProposalFieldsFragment } from '../../protocol-upgrade/__generated__/ProtocolUpgradeProposals';
const proposal = {
status:
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING,
vegaReleaseTag: 'v1.0.0',
upgradeBlockHeight: '12345',
} as ProtocolUpgradeProposalFieldsFragment;
const renderComponent = (proposal: ProtocolUpgradeProposalFieldsFragment) =>
render(
<BrowserRouter>
<ProtocolUpgradeProposalsListItem proposal={proposal} />
</BrowserRouter>
);
describe('ProtocolUpgradeProposalsListItem', () => {
it('renders the correct status icon for each proposal status', () => {
const statuses = [
{
status:
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED,
icon: 'protocol-upgrade-proposal-status-icon-rejected',
},
{
status:
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING,
icon: 'protocol-upgrade-proposal-status-icon-pending',
},
{
status:
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED,
icon: 'protocol-upgrade-proposal-status-icon-approved',
},
{
status:
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_UNSPECIFIED,
icon: 'protocol-upgrade-proposal-status-icon-unspecified',
},
];
statuses.forEach(({ status, icon }) => {
renderComponent({ ...proposal, status });
const statusIcon = screen.getByTestId(icon);
expect(statusIcon).toBeInTheDocument();
});
});
it('renders the correct Vega release tag', () => {
renderComponent(proposal);
const releaseTag = screen.getByTestId(
'protocol-upgrade-proposal-release-tag'
);
expect(releaseTag).toHaveTextContent(proposal.vegaReleaseTag);
});
it('renders the correct upgrade block height', () => {
renderComponent(proposal);
const blockHeight = screen.getByTestId(
'protocol-upgrade-proposal-block-height'
);
expect(blockHeight).toHaveTextContent(proposal.upgradeBlockHeight);
});
});
@@ -0,0 +1,124 @@
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import {
Button,
Icon,
Intent,
Lozenge,
RoundedWrapper,
} from '@vegaprotocol/ui-toolkit';
import { stripFullStops } from '@vegaprotocol/utils';
import { ProtocolUpgradeProposalStatus } from '@vegaprotocol/types';
import { SubHeading } from '../../../../components/heading';
import type { ReactNode } from 'react';
import type { ProtocolUpgradeProposalFieldsFragment } from '../../protocol-upgrade/__generated__/ProtocolUpgradeProposals';
import Routes from '../../../routes';
interface ProtocolProposalsListItemProps {
proposal: ProtocolUpgradeProposalFieldsFragment;
}
export const ProtocolUpgradeProposalsListItem = ({
proposal,
}: ProtocolProposalsListItemProps) => {
const { t } = useTranslation();
if (!proposal || !proposal.upgradeBlockHeight) return null;
let proposalStatusIcon: ReactNode;
switch (proposal.status) {
case ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED:
proposalStatusIcon = (
<div data-testid="protocol-upgrade-proposal-status-icon-rejected">
<Icon name={'cross'} />
</div>
);
break;
case ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING:
proposalStatusIcon = (
<div data-testid="protocol-upgrade-proposal-status-icon-pending">
<Icon name={'time'} />
</div>
);
break;
case ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED:
proposalStatusIcon = (
<div data-testid="protocol-upgrade-proposal-status-icon-approved">
<Icon name={'tick'} />
</div>
);
break;
case ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_UNSPECIFIED:
proposalStatusIcon = (
<div data-testid="protocol-upgrade-proposal-status-icon-unspecified">
<Icon name={'disable'} />
</div>
);
break;
}
return (
<li
id={proposal.upgradeBlockHeight}
data-testid="protocol-upgrade-proposals-list-item"
>
<RoundedWrapper paddingBottom={true} heightFull={true}>
<div
data-testid="protocol-upgrade-proposal-title"
className="text-sm mb-2"
>
<SubHeading title={`Vega release ${proposal.vegaReleaseTag}`} />
</div>
<div className="text-sm">
<div
data-testid="protocol-upgrade-proposal-type"
className="flex items-center gap-2 mb-4"
>
<Lozenge variant={Intent.Success}>{t('networkUpgrade')}</Lozenge>
</div>
<div
data-testid="protocol-upgrade-proposal-release-tag"
className="mb-2"
>
<span className="pr-2">{t('vegaReleaseTag')}</span>
<Lozenge>{proposal.vegaReleaseTag}</Lozenge>
</div>
<div
data-testid="protocol-upgrade-proposal-block-height"
className="mb-2"
>
<span className="pr-2">{t('upgradeBlockHeight')}</span>
<Lozenge>{proposal.upgradeBlockHeight}</Lozenge>
</div>
<div className="grid grid-cols-[1fr_auto] mt-3 items-start gap-2">
<div className="col-start-1 row-start-1 text-white">
<div
data-testid="protocol-upgrade-proposal-status"
className="flex items-center gap-2"
>
<span>{t(`${proposal.status}`)}</span>
<span>{proposalStatusIcon}</span>
</div>
</div>
<div className="col-start-2 row-start-2 justify-self-end">
<Link
to={`${Routes.PROPOSALS}/protocol-upgrade/${stripFullStops(
proposal.vegaReleaseTag
)}`}
>
<Button data-testid="view-proposal-btn" size="sm">
{t('View')}
</Button>
</Link>
</div>
</div>
</div>
</RoundedWrapper>
</li>
);
};
@@ -5,13 +5,18 @@ import { useTranslation } from 'react-i18next';
import { SplashLoader } from '../../../components/splash-loader';
import { ProposalsList } from '../components/proposals-list';
import { useProposalsQuery } from './__generated__/Proposals';
import type { ProposalFieldsFragment } from './__generated__/Proposals';
import type { NodeConnection, NodeEdge } from '@vegaprotocol/utils';
import { getNodes } from '@vegaprotocol/utils';
import flow from 'lodash/flow';
import { ProposalState } from '@vegaprotocol/types';
import {
ProposalState,
ProtocolUpgradeProposalStatus,
} from '@vegaprotocol/types';
import type { NodeConnection, NodeEdge } from '@vegaprotocol/utils';
import type { ProposalFieldsFragment } from './__generated__/Proposals';
import type { ProtocolUpgradeProposalFieldsFragment } from '../protocol-upgrade/__generated__/ProtocolUpgradeProposals';
import orderBy from 'lodash/orderBy';
import { useProtocolUpgradesQuery } from '../protocol-upgrade/__generated__/ProtocolUpgradeProposals';
const orderByDate = (arr: ProposalFieldsFragment[]) =>
orderBy(
@@ -20,6 +25,15 @@ const orderByDate = (arr: ProposalFieldsFragment[]) =>
['desc', 'desc']
);
const orderByUpgradeBlockHeight = (
arr: ProtocolUpgradeProposalFieldsFragment[]
) =>
orderBy(
arr,
[(p) => p?.upgradeBlockHeight, (p) => p.vegaReleaseTag],
['desc', 'desc']
);
export function getNotRejectedProposals<T extends ProposalFieldsFragment>(
data?: NodeConnection<NodeEdge<T>> | null
): T[] {
@@ -32,6 +46,21 @@ export function getNotRejectedProposals<T extends ProposalFieldsFragment>(
])(data);
}
export function getNotRejectedProtocolUpgradeProposals<
T extends ProtocolUpgradeProposalFieldsFragment
>(data?: NodeConnection<NodeEdge<T>> | null): T[] {
return flow([
(data) =>
getNodes<ProtocolUpgradeProposalFieldsFragment>(data, (p) =>
p
? p.status !==
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED
: false
),
orderByUpgradeBlockHeight,
])(data);
}
export const ProposalsContainer = () => {
const { t } = useTranslation();
const { data, loading, error } = useProposalsQuery({
@@ -40,6 +69,16 @@ export const ProposalsContainer = () => {
errorPolicy: 'ignore',
});
const {
data: protocolUpgradesData,
loading: protocolUpgradesLoading,
error: protocolUpgradesError,
} = useProtocolUpgradesQuery({
pollInterval: 5000,
fetchPolicy: 'network-only',
errorPolicy: 'ignore',
});
const proposals = useMemo(
() =>
getNotRejectedProposals<ProposalFieldsFragment>(
@@ -48,15 +87,25 @@ export const ProposalsContainer = () => {
[data]
);
if (error) {
const protocolUpgradeProposals = useMemo(
() =>
protocolUpgradesData
? getNotRejectedProtocolUpgradeProposals<ProtocolUpgradeProposalFieldsFragment>(
protocolUpgradesData.protocolUpgradeProposals
)
: [],
[protocolUpgradesData]
);
if (error || protocolUpgradesError) {
return (
<Callout intent={Intent.Danger} title={t('Something went wrong')}>
<pre>{error.message}</pre>
<pre>{error?.message || protocolUpgradesError?.message}</pre>
</Callout>
);
}
if (loading) {
if (loading || protocolUpgradesLoading) {
return (
<Splash>
<SplashLoader />
@@ -64,5 +113,11 @@ export const ProposalsContainer = () => {
);
}
return <ProposalsList proposals={proposals} />;
return (
<ProposalsList
proposals={proposals}
protocolUpgradeProposals={protocolUpgradeProposals}
lastBlockHeight={protocolUpgradesData?.lastBlockHeight}
/>
);
};
@@ -0,0 +1,17 @@
fragment ProtocolUpgradeProposalFields on ProtocolUpgradeProposal {
upgradeBlockHeight
vegaReleaseTag
approvers
status
}
query ProtocolUpgrades {
lastBlockHeight
protocolUpgradeProposals {
edges {
node {
...ProtocolUpgradeProposalFields
}
}
}
}
@@ -0,0 +1,59 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type ProtocolUpgradeProposalFieldsFragment = { __typename?: 'ProtocolUpgradeProposal', upgradeBlockHeight: string, vegaReleaseTag: string, approvers: Array<string>, status: Types.ProtocolUpgradeProposalStatus };
export type ProtocolUpgradesQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type ProtocolUpgradesQuery = { __typename?: 'Query', lastBlockHeight: string, protocolUpgradeProposals?: { __typename?: 'ProtocolUpgradeProposalConnection', edges?: Array<{ __typename?: 'ProtocolUpgradeProposalEdge', node: { __typename?: 'ProtocolUpgradeProposal', upgradeBlockHeight: string, vegaReleaseTag: string, approvers: Array<string>, status: Types.ProtocolUpgradeProposalStatus } }> | null } | null };
export const ProtocolUpgradeProposalFieldsFragmentDoc = gql`
fragment ProtocolUpgradeProposalFields on ProtocolUpgradeProposal {
upgradeBlockHeight
vegaReleaseTag
approvers
status
}
`;
export const ProtocolUpgradesDocument = gql`
query ProtocolUpgrades {
lastBlockHeight
protocolUpgradeProposals {
edges {
node {
...ProtocolUpgradeProposalFields
}
}
}
}
${ProtocolUpgradeProposalFieldsFragmentDoc}`;
/**
* __useProtocolUpgradesQuery__
*
* To run a query within a React component, call `useProtocolUpgradesQuery` and pass it any options that fit your needs.
* When your component renders, `useProtocolUpgradesQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useProtocolUpgradesQuery({
* variables: {
* },
* });
*/
export function useProtocolUpgradesQuery(baseOptions?: Apollo.QueryHookOptions<ProtocolUpgradesQuery, ProtocolUpgradesQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<ProtocolUpgradesQuery, ProtocolUpgradesQueryVariables>(ProtocolUpgradesDocument, options);
}
export function useProtocolUpgradesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ProtocolUpgradesQuery, ProtocolUpgradesQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<ProtocolUpgradesQuery, ProtocolUpgradesQueryVariables>(ProtocolUpgradesDocument, options);
}
export type ProtocolUpgradesQueryHookResult = ReturnType<typeof useProtocolUpgradesQuery>;
export type ProtocolUpgradesLazyQueryHookResult = ReturnType<typeof useProtocolUpgradesLazyQuery>;
export type ProtocolUpgradesQueryResult = Apollo.QueryResult<ProtocolUpgradesQuery, ProtocolUpgradesQueryVariables>;
@@ -0,0 +1 @@
export { ProtocolUpgradeProposalContainer as default } from './protocol-upgrade-proposal-container';
@@ -0,0 +1,78 @@
import { useEffect, useMemo } from 'react';
import { useParams } from 'react-router-dom';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { removePaginationWrapper, stripFullStops } from '@vegaprotocol/utils';
import * as Schema from '@vegaprotocol/types';
import { ProtocolUpgradeProposal } from './protocol-upgrade-proposal';
import { ProposalNotFound } from '../components/proposal-not-found';
import { useProtocolUpgradesQuery } from './__generated__/ProtocolUpgradeProposals';
import { useNodesQuery } from '../../staking/home/__generated__/Nodes';
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
export const ProtocolUpgradeProposalContainer = () => {
const params = useParams<{ proposalReleaseTag: string }>();
const { data, loading, error, refetch } = useProtocolUpgradesQuery({
fetchPolicy: 'network-only',
errorPolicy: 'ignore',
skip: !params.proposalReleaseTag,
});
useEffect(() => {
const interval = setInterval(refetch, 1000);
return () => clearInterval(interval);
}, [refetch]);
const {
data: nodesData,
error: nodesError,
loading: nodesLoading,
refetch: nodesRefetch,
} = useNodesQuery();
useRefreshAfterEpoch(nodesData?.epoch.timestamps.expiry, nodesRefetch);
const protocolUpgradeProposal = useMemo(() => {
if (!data?.protocolUpgradeProposals) return null;
const proposals = removePaginationWrapper(
data.protocolUpgradeProposals.edges
);
return proposals.find(
({ vegaReleaseTag }) =>
params.proposalReleaseTag &&
params.proposalReleaseTag === stripFullStops(vegaReleaseTag)
);
}, [data, params.proposalReleaseTag]);
const consensusValidators = useMemo(() => {
if (!nodesData?.nodesConnection.edges) return null;
const nodes = removePaginationWrapper(nodesData.nodesConnection.edges);
return nodes.filter(
({ rankingScore: { status } }) =>
status === Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT
);
}, [nodesData]);
return (
<AsyncRenderer
loading={loading || nodesLoading}
error={error || nodesError}
data={{ ...data, ...nodesData }}
>
{protocolUpgradeProposal ? (
<ProtocolUpgradeProposal
proposal={protocolUpgradeProposal}
lastBlockHeight={data?.lastBlockHeight}
consensusValidators={consensusValidators}
/>
) : (
<ProposalNotFound />
)}
</AsyncRenderer>
);
};
@@ -0,0 +1,134 @@
import { render } from '@testing-library/react';
import * as Schema from '@vegaprotocol/types';
import {
ProtocolUpgradeProposal,
getConsensusApprovals,
getConsensusApprovalsVotingPower,
getConsensusApprovalsVotingPowerPercentage,
} from './protocol-upgrade-proposal';
import { ProtocolUpgradeProposalStatus } from '@vegaprotocol/types';
import { getNormalisedVotingPower } from '../../staking/shared';
import type { NodesFragmentFragment } from '../../staking/home/__generated__/Nodes';
import type { ProtocolUpgradeProposalFieldsFragment } from './__generated__/ProtocolUpgradeProposals';
const mockProposal: ProtocolUpgradeProposalFieldsFragment = {
vegaReleaseTag: 'v0.1.234',
status:
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_PENDING,
upgradeBlockHeight: '12345',
approvers: [],
};
const mockConsensusValidators: NodesFragmentFragment[] = [
{
id: 'ccc022b7e63a4d0a6d3a193c3940c88574060e58a184964c994998d86835a1b4',
name: 'Marvin',
avatarUrl: 'https://upload.wikimedia.org/wikipedia/en/2/25/Marvin-TV-3.jpg',
pubkey: '6abc23391a9f888ab240415bf63d6844b03fc360be822f4a1d2cd832d87b2917',
stakedTotal: '14182454495731682635157',
stakedByOperator: '1000000000000000000000',
stakedByDelegates: '13182454495731682635157',
pendingStake: '0',
rankingScore: {
rankingScore: '0.67845061012234727427532760837568',
stakeScore: '0.3392701644525644',
performanceScore: '0.9998677767864936',
votingPower: '3500',
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
__typename: 'RankingScore',
},
__typename: 'Node',
},
{
id: 'ccc022b7e63a4d0a6d3a193c3940c88574060e58a184964c994998d86835a1b5',
name: 'Barvin',
avatarUrl: 'https://upload.wikimedia.org/wikipedia/en/2/25/Barvin-TV-3.jpg',
pubkey: '6abc23391a9f888ab240415bf63d6844b03fc360be822f4a1d2cd832d87b291b',
stakedTotal: '1418245449573168263',
stakedByOperator: '100000000000000000',
stakedByDelegates: '1318245449573168263',
pendingStake: '0',
rankingScore: {
rankingScore: '0.5',
stakeScore: '0.3',
performanceScore: '0.98',
votingPower: '2500',
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
__typename: 'RankingScore',
},
__typename: 'Node',
},
];
const renderComponent = () =>
render(
<ProtocolUpgradeProposal proposal={mockProposal} consensusValidators={[]} />
);
describe('ProtocolUpgradeProposal', () => {
it('should render successfully', () => {
const { baseElement } = renderComponent();
expect(baseElement).toBeTruthy();
});
});
describe('getConsensusApprovals', () => {
it('returns an empty array when there are no matching approvers', () => {
const result = getConsensusApprovals(mockConsensusValidators, {
...mockProposal,
approvers: [],
});
expect(result).toEqual([]);
});
it('returns the correct consensus approvals when there are matching approvers', () => {
const expectedApprovals = mockConsensusValidators[1];
const result = getConsensusApprovals(mockConsensusValidators, {
...mockProposal,
approvers: [
'6abc23391a9f888ab240415bf63d6844b03fc360be822f4a1d2cd832d87b291b',
],
});
expect(result.length).toEqual(1);
expect(result[0].id).toEqual(expectedApprovals.id);
});
});
describe('getConsensusApprovalsVotingPower', () => {
it('returns 0 when the input array is empty', () => {
const result = getConsensusApprovalsVotingPower([]);
expect(result).toBe(0);
});
it('returns the correct sum of voting power for a given array of consensus validators', () => {
const expectedSum = mockConsensusValidators.reduce(
(acc, curr) => acc + Number(curr.rankingScore.votingPower),
0
);
const result = getConsensusApprovalsVotingPower(mockConsensusValidators);
expect(result).toBe(expectedSum);
});
});
describe('getConsensusApprovalsVotingPowerPercentage', () => {
it('returns "0%" when the input value is 0 or less', () => {
const resultZero = getConsensusApprovalsVotingPowerPercentage(0);
const resultNegative = getConsensusApprovalsVotingPowerPercentage(-10);
expect(resultZero).toBe('0%');
expect(resultNegative).toBe('0%');
});
it('returns the correct percentage string when the input value is greater than 0', () => {
const inputValue = 12345;
const expectedPercentage = getNormalisedVotingPower(
inputValue.toString(),
2
);
const result = getConsensusApprovalsVotingPowerPercentage(inputValue);
expect(result).toBe(expectedPercentage);
});
});
@@ -0,0 +1,83 @@
import { useMemo } from 'react';
import { ProtocolUpgradeProposalDetailHeader } from '../components/protocol-upgrade-proposal-detail-header';
import { ProtocolUpdateProposalDetailApprovals } from '../components/protocol-upgrade-proposal-detail-approvals';
import { ProtocolUpgradeProposalDetailInfo } from '../components/protocol-upgrade-proposal-detail-info';
import { getNormalisedVotingPower } from '../../staking/shared';
import type { ProtocolUpgradeProposalFieldsFragment } from './__generated__/ProtocolUpgradeProposals';
import type { NodesFragmentFragment } from '../../staking/home/__generated__/Nodes';
export interface ProtocolUpgradeProposalProps {
proposal: ProtocolUpgradeProposalFieldsFragment;
consensusValidators: NodesFragmentFragment[] | null;
lastBlockHeight?: string;
}
export const getConsensusApprovals = (
consensusValidators: NodesFragmentFragment[],
proposal: ProtocolUpgradeProposalFieldsFragment
) =>
consensusValidators?.filter(({ pubkey }) =>
proposal.approvers?.includes(pubkey)
);
export const getConsensusApprovalsVotingPower = (
consensusValidators: NodesFragmentFragment[]
) =>
consensusValidators?.reduce<number>(
(acc: number, curr: NodesFragmentFragment) => {
return acc + Number(curr.rankingScore.votingPower);
},
0
);
export const getConsensusApprovalsVotingPowerPercentage = (
consensusApprovalsVotingPower: number
) =>
consensusApprovalsVotingPower > 0
? getNormalisedVotingPower(consensusApprovalsVotingPower.toString(), 2)
: '0%';
export const ProtocolUpgradeProposal = ({
proposal,
lastBlockHeight,
consensusValidators,
}: ProtocolUpgradeProposalProps) => {
const consensusApprovals = useMemo(
() => getConsensusApprovals(consensusValidators || [], proposal),
[consensusValidators, proposal]
);
const consensusApprovalsVotingPower = useMemo(
() => getConsensusApprovalsVotingPower(consensusApprovals || []),
[consensusApprovals]
);
const consensusApprovalsVotingPowerPercentage = useMemo(
() =>
getConsensusApprovalsVotingPowerPercentage(consensusApprovalsVotingPower),
[consensusApprovalsVotingPower]
);
return (
<section data-testid="protocol-upgrade-proposal">
<ProtocolUpgradeProposalDetailHeader
releaseTag={proposal.vegaReleaseTag}
/>
<ProtocolUpgradeProposalDetailInfo
proposal={proposal}
lastBlockHeight={lastBlockHeight}
/>
{consensusValidators && consensusApprovals && (
<ProtocolUpdateProposalDetailApprovals
consensusApprovals={consensusApprovals}
consensusApprovalsVotingPowerPercentage={
consensusApprovalsVotingPowerPercentage
}
totalConsensusValidators={consensusValidators.length}
/>
)}
</section>
);
};
@@ -109,6 +109,13 @@ const LazyProposal = React.lazy(
)
);
const LazyProtocolUpgradeProposal = React.lazy(
() =>
import(
/* webpackChunkName: "route-governance-protocol-upgrade-proposal", webpackPrefetch: true */ './proposals/protocol-upgrade'
)
);
const LazyProposalsList = React.lazy(
() =>
import(
@@ -257,6 +264,10 @@ const routerConfig = [
},
{ path: 'proposals', element: <LazyProposalsList /> },
{ path: ':proposalId', element: <LazyProposal /> },
{
path: 'protocol-upgrade/:proposalReleaseTag',
element: <LazyProtocolUpgradeProposal />,
},
{ path: 'rejected', element: <LazyRejectedProposalsList /> },
],
},
@@ -13,6 +13,8 @@ import { StakingFormTxStatuses } from './staking-form-tx-statuses';
import {
ButtonLink,
FormGroup,
Intent,
Notification,
Radio,
RadioGroup,
} from '@vegaprotocol/ui-toolkit';
@@ -29,6 +31,7 @@ import type {
DelegateSubmissionBody,
UndelegateSubmissionBody,
} from '@vegaprotocol/wallet';
import Routes from '../../routes';
export enum FormState {
Default,
@@ -191,51 +194,65 @@ export const StakingForm = ({
}, [isDialogVisible]);
return (
<>
<div className="my-8">
<SubHeading title={t('Manage your stake')} />
{formState === FormState.Default &&
availableStakeToAdd.isEqualTo(0) &&
availableStakeToRemove.isEqualTo(0) && (
<div className="mb-4">
{lien.isGreaterThan(0) ? (
<span className="text-vega-pink">
{t('stakeNodeWrongVegaKey')}
</span>
<Notification
intent={Intent.Warning}
message={t('stakeNodeWrongVegaKey')}
/>
) : (
<span className="text-vega-orange">{t('stakeNodeNone')}</span>
<Notification
message={t('stakeNodeNone')}
intent={Intent.Warning}
buttonProps={{
text: t('associateVegaNow'),
action: () => navigate(Routes.ASSOCIATE),
className: 'py-1',
size: 'sm',
}}
/>
)}
</div>
)}
<FormGroup
label={t('Select if you want to add or remove stake')}
labelFor="radio-stake-options"
hideLabel={true}
>
<RadioGroup
name="radio-stake-options"
onChange={(value) => {
// @ts-ignore value does exist on target
setAction(value);
navigate(`?action=${value}`, {
replace: true,
});
}}
value={action}
<div className="mb-8">
<FormGroup
label={t('Select if you want to add or remove stake')}
labelFor="radio-stake-options"
hideLabel={true}
>
<Radio
disabled={availableStakeToAdd.isEqualTo(0)}
value={Actions.Add}
label="Add"
id="add-stake-radio"
/>
<Radio
disabled={availableStakeToRemove.isEqualTo(0)}
value={Actions.Remove}
label="Remove"
id="remove-stake-radio"
/>
</RadioGroup>
</FormGroup>
<RadioGroup
name="radio-stake-options"
onChange={(value) => {
// @ts-ignore value does exist on target
setAction(value);
navigate(`?action=${value}`, {
replace: true,
});
}}
value={action}
>
<Radio
disabled={availableStakeToAdd.isEqualTo(0)}
value={Actions.Add}
label="Add"
id="add-stake-radio"
/>
<Radio
disabled={availableStakeToRemove.isEqualTo(0)}
value={Actions.Remove}
label="Remove"
id="remove-stake-radio"
/>
</RadioGroup>
</FormGroup>
</div>
{action !== undefined && (
// eslint-disable-next-line
<>
@@ -314,6 +331,6 @@ export const StakingForm = ({
toggleDialog={toggleDialog}
error={error}
/>
</>
</div>
);
};
+2 -2
View File
@@ -20,8 +20,8 @@ export const getLastEpochScoreAndPerformance = (
};
};
export const getNormalisedVotingPower = (votingPower: string) =>
formatNumberPercentage(new BigNumber(votingPower).dividedBy(100), 2);
export const getNormalisedVotingPower = (votingPower: string, decimals = 2) =>
formatNumberPercentage(new BigNumber(votingPower).dividedBy(100), decimals);
export const getUnnormalisedVotingPower = (
validatorScore: string | null | undefined
+1 -1
View File
@@ -2,4 +2,4 @@ NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
NX_VEGA_NETWORKS='{"TESTNET":"https://multisig-signer.fairground.wtf","MAINNET":"https://multisig-signer.vega.xyz"}'
NX_VEGA_ENV=STAGNET3
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
+3 -1
View File
@@ -9,6 +9,7 @@ import {
} from '@vegaprotocol/environment';
import { AsyncRenderer, Button, Lozenge } from '@vegaprotocol/ui-toolkit';
import type { EthereumConfig } from '@vegaprotocol/web3';
import { useWeb3Disconnect } from '@vegaprotocol/web3';
import { useEthereumConfig, Web3Provider } from '@vegaprotocol/web3';
import { t } from '@vegaprotocol/i18n';
import { ENV } from './config/env';
@@ -34,6 +35,7 @@ const pageWrapperClasses = classnames(
const ConnectedApp = ({ config }: { config: EthereumConfig | null }) => {
const { account, connector } = useWeb3React();
const disconnect = useWeb3Disconnect(connector);
return (
<main className="w-full max-w-3xl px-5 justify-self-center">
<h1>{t('Multisig signer')}</h1>
@@ -41,7 +43,7 @@ const ConnectedApp = ({ config }: { config: EthereumConfig | null }) => {
<p>
Connected to Eth wallet: <Lozenge>{account}</Lozenge>
</p>
<Button onClick={() => connector.deactivate()}>Disconnect</Button>
<Button onClick={() => disconnect()}>Disconnect</Button>
</div>
<ContractDetails config={config} />
<h2>{t('Add or remove signer')}</h2>
@@ -1,5 +1,10 @@
import { useEnvironment } from '@vegaprotocol/environment';
import { getChainName, useEthereumConfig } from '@vegaprotocol/web3';
import {
getChainName,
useEthereumConfig,
useWeb3ConnectStore,
useWeb3Disconnect,
} from '@vegaprotocol/web3';
import { Button, Splash, AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { Web3ConnectDialog } from '@vegaprotocol/web3';
import { useWeb3React } from '@web3-react/core';
@@ -55,7 +60,9 @@ export const Web3Content = ({
appChainId,
setDialogOpen,
}: Web3ContentProps) => {
const { error, connector, chainId } = useWeb3React();
const { connector, chainId } = useWeb3React();
const error = useWeb3ConnectStore((store) => store.error);
const disconnect = useWeb3Disconnect(connector);
useEffect(() => {
if (connector?.connectEagerly) {
@@ -71,7 +78,7 @@ export const Web3Content = ({
<Splash>
<div className="flex flex-col items-center gap-12">
<p className="text-white">Something went wrong: {error.message}</p>
<Button onClick={() => connector.deactivate()}>Disconnect</Button>
<Button onClick={() => disconnect()}>Disconnect</Button>
</div>
</Splash>
);
@@ -84,7 +91,7 @@ export const Web3Content = ({
<p className="text-white">
This app only works on {getChainName(appChainId)}
</p>
<Button onClick={() => connector.deactivate()}>Disconnect</Button>
<Button onClick={() => disconnect()}>Disconnect</Button>
</div>
</Splash>
);
@@ -1,13 +1,13 @@
import { ethers } from 'ethers';
import type { Web3ReactHooks } from '@web3-react/core';
import { initializeConnector } from '@web3-react/core';
import { MetaMask } from '@web3-react/metamask';
import { WalletConnect } from '@web3-react/walletconnect';
import type { Connector } from '@web3-react/types';
const [metamask, metamaskHooks] = initializeConnector<MetaMask>(
(actions) => new MetaMask(actions)
);
import {
WALLETCONNECT_PROJECT_ID,
initializeCoinbaseConnector,
initializeMetaMaskConnector,
initializeWalletConnectLegacyConnector,
initializeWalletConnector,
} from '@vegaprotocol/web3';
export const createDefaultProvider = (providerUrl: string, chainId: number) => {
return new ethers.providers.JsonRpcProvider(providerUrl, chainId);
@@ -17,18 +17,11 @@ export const createConnectors = (providerUrl: string, chainId: number) => {
if (isNaN(chainId)) {
throw new Error('Invalid Ethereum chain ID for environment');
}
const [walletconnect, walletconnectHooks] =
initializeConnector<WalletConnect>(
(actions) =>
new WalletConnect(actions, {
rpc: {
[chainId]: providerUrl,
},
}),
[chainId]
);
return [
[metamask, metamaskHooks],
[walletconnect, walletconnectHooks],
] as [Connector, Web3ReactHooks][];
initializeMetaMaskConnector(),
initializeCoinbaseConnector(providerUrl),
initializeWalletConnector(WALLETCONNECT_PROJECT_ID, chainId, providerUrl),
initializeWalletConnectLegacyConnector(chainId, providerUrl),
].filter(Boolean) as unknown as [Connector, Web3ReactHooks][];
};
+358 -54
View File
@@ -36,10 +36,25 @@
"tranche_id": 56,
"tranche_start": "2023-04-20T00:00:00.000Z",
"tranche_end": "2023-05-20T00:00:00.000Z",
"total_added": "15761.125",
"total_removed": "0",
"locked_amount": "15761.125",
"total_added": "17206.625",
"total_removed": "202.093666077975",
"locked_amount": "14192.3522349054765257",
"deposits": [
{
"amount": "188",
"user": "0x90Cf7B9958C3BbBCddAb52Ecc408535D4f3C4241",
"tx": "0xefa5cb034a994bd2cf2b100b1ecca1877038e7b1188fab4ebf2065cb165027e4"
},
{
"amount": "50",
"user": "0xAc1c2783d64c29CDB79608f5B66a37Fd1ea35dD6",
"tx": "0xc1ede6de1653f205e0a743f609835648a67287a271a994cd141911ce13d5cac7"
},
{
"amount": "1207.5",
"user": "0x1447Efc62d5077d7AbB20492dF831Dd6c9Eb1756",
"tx": "0x9092eaf46d5cdba3b2219aa7187da4e1623004434c33a915956aa45d04d561f2"
},
{
"amount": "241.5",
"user": "0xBf1AaB792D729fA125e6D7122D4b916a1E1C44B1",
@@ -181,8 +196,66 @@
"tx": "0x679fcc1c3a29bdc259b6a4c044579a89c5357f42ed1963221669ebf43cc545b0"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "202.093666077975",
"user": "0x1447Efc62d5077d7AbB20492dF831Dd6c9Eb1756",
"tx": "0x300c18b4220d3bc357f054792cb65f05d4005912bf8e5d9580b5b830cc3c0845"
}
],
"users": [
{
"address": "0x90Cf7B9958C3BbBCddAb52Ecc408535D4f3C4241",
"deposits": [
{
"amount": "188",
"user": "0x90Cf7B9958C3BbBCddAb52Ecc408535D4f3C4241",
"tranche_id": 56,
"tx": "0xefa5cb034a994bd2cf2b100b1ecca1877038e7b1188fab4ebf2065cb165027e4"
}
],
"withdrawals": [],
"total_tokens": "188",
"withdrawn_tokens": "0",
"remaining_tokens": "188"
},
{
"address": "0xAc1c2783d64c29CDB79608f5B66a37Fd1ea35dD6",
"deposits": [
{
"amount": "50",
"user": "0xAc1c2783d64c29CDB79608f5B66a37Fd1ea35dD6",
"tranche_id": 56,
"tx": "0xc1ede6de1653f205e0a743f609835648a67287a271a994cd141911ce13d5cac7"
}
],
"withdrawals": [],
"total_tokens": "50",
"withdrawn_tokens": "0",
"remaining_tokens": "50"
},
{
"address": "0x1447Efc62d5077d7AbB20492dF831Dd6c9Eb1756",
"deposits": [
{
"amount": "1207.5",
"user": "0x1447Efc62d5077d7AbB20492dF831Dd6c9Eb1756",
"tranche_id": 56,
"tx": "0x9092eaf46d5cdba3b2219aa7187da4e1623004434c33a915956aa45d04d561f2"
}
],
"withdrawals": [
{
"amount": "202.093666077975",
"user": "0x1447Efc62d5077d7AbB20492dF831Dd6c9Eb1756",
"tranche_id": 56,
"tx": "0x300c18b4220d3bc357f054792cb65f05d4005912bf8e5d9580b5b830cc3c0845"
}
],
"total_tokens": "1207.5",
"withdrawn_tokens": "202.093666077975",
"remaining_tokens": "1005.406333922025"
},
{
"address": "0xBf1AaB792D729fA125e6D7122D4b916a1E1C44B1",
"deposits": [
@@ -664,10 +737,15 @@
"tranche_id": 54,
"tranche_start": "2023-04-06T00:00:00.000Z",
"tranche_end": "2023-05-06T00:00:00.000Z",
"total_added": "8865",
"total_removed": "362.31015740205",
"locked_amount": "4947.631059027778128",
"total_added": "8976",
"total_removed": "596.64743517951",
"locked_amount": "3214.7758703703708912",
"deposits": [
{
"amount": "111",
"user": "0x90Cf7B9958C3BbBCddAb52Ecc408535D4f3C4241",
"tx": "0x1229e077f48b796678436bfa8143cea3ae71df58b589ac922be205c4482be235"
},
{
"amount": "33",
"user": "0xBf1AaB792D729fA125e6D7122D4b916a1E1C44B1",
@@ -805,6 +883,11 @@
}
],
"withdrawals": [
{
"amount": "106.53500000286",
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
"tx": "0x4027743264e01043ddb16676c6f7914c110df9e7212bd3f21cb6842614ce238f"
},
{
"amount": "5.46866782407",
"user": "0x92A1e98C6f09970e45645Cbe57c6DcaF4547c8FE",
@@ -825,6 +908,11 @@
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
"tx": "0x05d086879e23724f1397d41adcbe2f3316dd4039c240edbc3cbbcacf1ca1d00e"
},
{
"amount": "127.8022777746",
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
"tx": "0xb67468e99866887e95c5a211fe8611d107b02ef094d9b90343820366a5e8c7a0"
},
{
"amount": "52.2185023074",
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
@@ -832,6 +920,21 @@
}
],
"users": [
{
"address": "0x90Cf7B9958C3BbBCddAb52Ecc408535D4f3C4241",
"deposits": [
{
"amount": "111",
"user": "0x90Cf7B9958C3BbBCddAb52Ecc408535D4f3C4241",
"tranche_id": 54,
"tx": "0x1229e077f48b796678436bfa8143cea3ae71df58b589ac922be205c4482be235"
}
],
"withdrawals": [],
"total_tokens": "111",
"withdrawn_tokens": "0",
"remaining_tokens": "111"
},
{
"address": "0xBf1AaB792D729fA125e6D7122D4b916a1E1C44B1",
"deposits": [
@@ -1038,6 +1141,12 @@
}
],
"withdrawals": [
{
"amount": "106.53500000286",
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
"tranche_id": 54,
"tx": "0x4027743264e01043ddb16676c6f7914c110df9e7212bd3f21cb6842614ce238f"
},
{
"amount": "155.03186111556",
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
@@ -1050,6 +1159,12 @@
"tranche_id": 54,
"tx": "0x05d086879e23724f1397d41adcbe2f3316dd4039c240edbc3cbbcacf1ca1d00e"
},
{
"amount": "127.8022777746",
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
"tranche_id": 54,
"tx": "0xb67468e99866887e95c5a211fe8611d107b02ef094d9b90343820366a5e8c7a0"
},
{
"amount": "52.2185023074",
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
@@ -1058,8 +1173,8 @@
}
],
"total_tokens": "858",
"withdrawn_tokens": "296.67303008772",
"remaining_tokens": "561.32696991228"
"withdrawn_tokens": "531.01030786518",
"remaining_tokens": "326.98969213482"
},
{
"address": "0x0bBf7580e036eA5D69ABe679CC90117EeC2e3dc1",
@@ -4407,7 +4522,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "86666.297",
"total_removed": "0",
"locked_amount": "54550.6765448265232514477",
"locked_amount": "53126.3383787007632981199",
"deposits": [
{
"amount": "86666.297",
@@ -4473,7 +4588,7 @@
"tranche_end": "2023-06-01T00:00:00.000Z",
"total_added": "2500",
"total_removed": "0",
"locked_amount": "587.132586741961625",
"locked_amount": "504.733128561253575",
"deposits": [
{
"amount": "2500",
@@ -4594,7 +4709,7 @@
"tranche_end": "2023-09-01T00:00:00.000Z",
"total_added": "17500",
"total_removed": "0",
"locked_amount": "12815.2549755938015",
"locked_amount": "12244.72829232085475",
"deposits": [
{
"amount": "12500",
@@ -4860,8 +4975,8 @@
"tranche_start": "2023-02-01T00:00:00.000Z",
"tranche_end": "2023-08-01T00:00:00.000Z",
"total_added": "37500",
"total_removed": "12294.731717775",
"locked_amount": "21493.76774478207375",
"total_removed": "12539.2989369",
"locked_amount": "20250.94718769183375",
"deposits": [
{
"amount": "7500",
@@ -4890,6 +5005,11 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x2c8a0681fe27258861489cd7a891cf213c7ab930d86b1bf08cd54f2f3739a8b5"
},
{
"amount": "244.567219125",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x4bc7559edf36b6ecda7656f8066479395ea441daf0ad37ad4324814348e41643"
},
{
"amount": "158.943370125",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -5046,6 +5166,12 @@
"tranche_id": 34,
"tx": "0x2c8a0681fe27258861489cd7a891cf213c7ab930d86b1bf08cd54f2f3739a8b5"
},
{
"amount": "244.567219125",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 34,
"tx": "0x4bc7559edf36b6ecda7656f8066479395ea441daf0ad37ad4324814348e41643"
},
{
"amount": "158.943370125",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -5186,8 +5312,8 @@
}
],
"total_tokens": "7500",
"withdrawn_tokens": "3059.282439375",
"remaining_tokens": "4440.717560625"
"withdrawn_tokens": "3303.8496585",
"remaining_tokens": "4196.1503415"
},
{
"address": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
@@ -5225,7 +5351,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "129999.45",
"total_removed": "0",
"locked_amount": "54500.905916308673138415",
"locked_amount": "53077.8672795424049222625",
"deposits": [
{
"amount": "129999.45",
@@ -5258,7 +5384,7 @@
"tranche_end": "2024-04-01T00:00:00.000Z",
"total_added": "54144.7663",
"total_removed": "0",
"locked_amount": "51443.92658193328217573951",
"locked_amount": "50556.50265628052469670738",
"deposits": [
{
"amount": "54144.7663",
@@ -5291,7 +5417,7 @@
"tranche_end": "2023-09-03T00:00:00.000Z",
"total_added": "62600",
"total_removed": "0",
"locked_amount": "23452.40436960933488",
"locked_amount": "22423.58956747843764",
"deposits": [
{
"amount": "10000",
@@ -5484,7 +5610,7 @@
"tranche_end": "2023-09-17T00:00:00.000Z",
"total_added": "5000",
"total_removed": "0",
"locked_amount": "2064.976059107052",
"locked_amount": "1982.802352866565",
"deposits": [
{
"amount": "5000",
@@ -6024,8 +6150,8 @@
"tranche_start": "2022-11-01T00:00:00.000Z",
"tranche_end": "2023-05-01T00:00:00.000Z",
"total_added": "22500",
"total_removed": "6871.43713545",
"locked_amount": "1459.796558471453925",
"total_removed": "7115.9985996",
"locked_amount": "714.104224217310375",
"deposits": [
{
"amount": "7500",
@@ -6054,6 +6180,11 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x15840e283faffb39a5d0e3389137ec92cec3deee7df535a534908ccd7d6b0873"
},
{
"amount": "244.56146415",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x00275dfbd06b609e69b430eef7fe04c7bb64314904a0478a0e55b643f7f0bc09"
},
{
"amount": "158.9433702",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -6265,6 +6396,12 @@
"tranche_id": 33,
"tx": "0x15840e283faffb39a5d0e3389137ec92cec3deee7df535a534908ccd7d6b0873"
},
{
"amount": "244.56146415",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 33,
"tx": "0x00275dfbd06b609e69b430eef7fe04c7bb64314904a0478a0e55b643f7f0bc09"
},
{
"amount": "158.9433702",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -6483,8 +6620,8 @@
}
],
"total_tokens": "7500",
"withdrawn_tokens": "6871.43713545",
"remaining_tokens": "628.56286455"
"withdrawn_tokens": "7115.9985996",
"remaining_tokens": "384.0014004"
},
{
"address": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1",
@@ -6509,7 +6646,7 @@
"tranche_end": "2023-06-02T00:00:00.000Z",
"total_added": "1939928.38",
"total_removed": "928642.9598472029154",
"locked_amount": "232489.7989013972454998708",
"locked_amount": "200607.5779362562454442532",
"deposits": [
{
"amount": "1852091.69",
@@ -40325,7 +40462,7 @@
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "3732368.4671",
"total_removed": "715655.108029600523393",
"locked_amount": "381757.201289964680148718477",
"locked_amount": "332765.327876919897996287797",
"deposits": [
{
"amount": "1998.95815",
@@ -41717,8 +41854,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "15870102.715470999700000001",
"total_removed": "835090.78677275839915352",
"locked_amount": "6653374.1102600029976151216559241015233847",
"total_removed": "860379.54790441442685852",
"locked_amount": "6479652.07271627106022165330027333915923225",
"deposits": [
{
"amount": "16249.93",
@@ -42222,6 +42359,16 @@
}
],
"withdrawals": [
{
"amount": "10150.87581603206683",
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
"tx": "0x2ee57ee8a712525955ad807f4d45eeaa5f6388bf0b4fceabc7de6871899f736e"
},
{
"amount": "913.910324501590625",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x455d2e8214a5071fd4de1642939780068d4694cc2a774e7a3ab9283c4d52e847"
},
{
"amount": "981.387731774910625",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -42277,6 +42424,21 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xa56a064890829624fb37f887adb87987dfafd709ebea2cdf423c91a38e91b82f"
},
{
"amount": "984.287150968688875",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xbf3e00aef8ae756fb2f5de5d3eec6f925e9005c7acca1a6c2f88a84ad1e44fba"
},
{
"amount": "12786.192214",
"user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37",
"tx": "0x57c9c9396f67fb377f2d7cca30a1a6e6b73267408efde1239cbfdfd99c333345"
},
{
"amount": "453.495626153681375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xdad160466fa0b4805f3a12ff558d429bf48f81f9b99653dbce172d261861f1d0"
},
{
"amount": "998.454771147362375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -44315,6 +44477,12 @@
}
],
"withdrawals": [
{
"amount": "913.910324501590625",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0x455d2e8214a5071fd4de1642939780068d4694cc2a774e7a3ab9283c4d52e847"
},
{
"amount": "981.387731774910625",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -44375,6 +44543,18 @@
"tranche_id": 2,
"tx": "0xa56a064890829624fb37f887adb87987dfafd709ebea2cdf423c91a38e91b82f"
},
{
"amount": "984.287150968688875",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0xbf3e00aef8ae756fb2f5de5d3eec6f925e9005c7acca1a6c2f88a84ad1e44fba"
},
{
"amount": "453.495626153681375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0xdad160466fa0b4805f3a12ff558d429bf48f81f9b99653dbce172d261861f1d0"
},
{
"amount": "998.454771147362375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -45811,8 +45991,8 @@
}
],
"total_tokens": "259998.8875",
"withdrawn_tokens": "150733.980517927478375",
"remaining_tokens": "109264.906982072521625"
"withdrawn_tokens": "153085.67361955143925",
"remaining_tokens": "106913.21388044856075"
},
{
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
@@ -46039,6 +46219,12 @@
}
],
"withdrawals": [
{
"amount": "10150.87581603206683",
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
"tranche_id": 2,
"tx": "0x2ee57ee8a712525955ad807f4d45eeaa5f6388bf0b4fceabc7de6871899f736e"
},
{
"amount": "2873.74755113623213",
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
@@ -46311,8 +46497,8 @@
}
],
"total_tokens": "150551.801",
"withdrawn_tokens": "78415.36940998198906",
"remaining_tokens": "72136.43159001801094"
"withdrawn_tokens": "88566.24522601405589",
"remaining_tokens": "61985.55577398594411"
},
{
"address": "0x4d982Ab0823fD2f48e934a7be2bb0a5374a26148",
@@ -46532,6 +46718,12 @@
}
],
"withdrawals": [
{
"amount": "12786.192214",
"user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37",
"tranche_id": 2,
"tx": "0x57c9c9396f67fb377f2d7cca30a1a6e6b73267408efde1239cbfdfd99c333345"
},
{
"amount": "934.96553",
"user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37",
@@ -46780,8 +46972,8 @@
}
],
"total_tokens": "200000",
"withdrawn_tokens": "104171.325864",
"remaining_tokens": "95828.674136"
"withdrawn_tokens": "116957.518078",
"remaining_tokens": "83042.481922"
},
{
"address": "0x1b956E6c00E238194B331eddEFF72Cb5f28A8d01",
@@ -48163,8 +48355,8 @@
"tranche_start": "2021-11-05T00:00:00.000Z",
"tranche_end": "2023-05-05T00:00:00.000Z",
"total_added": "14597706.0446472999",
"total_removed": "5844740.479416869886902626",
"locked_amount": "420907.270106923449603004591821117",
"total_removed": "5847991.884210280507681376",
"locked_amount": "260528.1942722316783230342092766613",
"deposits": [
{
"amount": "129284.449",
@@ -48373,6 +48565,11 @@
}
],
"withdrawals": [
{
"amount": "1257.7360413991436375",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x42fa522871101c2d402faba52603df54599654f29ef5fe1211a9ea058b7eaad9"
},
{
"amount": "1360.32447632896938825",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -48443,6 +48640,21 @@
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x5cee329248d32efdbd9e7f2b223f1714843a154b530cafd9f5df43a1d45c625b"
},
{
"amount": "371.1636800374613695",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0xc4a521e74b6b9c9c01e7fbd950f4096d3e6473a773818b4fdf0c9d974ee5fc7e"
},
{
"amount": "993.45434720929767175",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x6b1bd1880e5539566cb7110e80ef3e877e3c46a2fcd88798e82211a962dd2b7b"
},
{
"amount": "629.0507247647181",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x537a8c34bee648cc1e658c0e55d30202694887899bfcbe529f9cf8284a4e90eb"
},
{
"amount": "37462.74710421168752574",
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
@@ -51658,6 +51870,12 @@
}
],
"withdrawals": [
{
"amount": "1257.7360413991436375",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0x42fa522871101c2d402faba52603df54599654f29ef5fe1211a9ea058b7eaad9"
},
{
"amount": "1360.32447632896938825",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -51724,6 +51942,24 @@
"tranche_id": 3,
"tx": "0x5cee329248d32efdbd9e7f2b223f1714843a154b530cafd9f5df43a1d45c625b"
},
{
"amount": "371.1636800374613695",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0xc4a521e74b6b9c9c01e7fbd950f4096d3e6473a773818b4fdf0c9d974ee5fc7e"
},
{
"amount": "993.45434720929767175",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0x6b1bd1880e5539566cb7110e80ef3e877e3c46a2fcd88798e82211a962dd2b7b"
},
{
"amount": "629.0507247647181",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0x537a8c34bee648cc1e658c0e55d30202694887899bfcbe529f9cf8284a4e90eb"
},
{
"amount": "1383.345213676043696",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -54462,8 +54698,8 @@
}
],
"total_tokens": "359123.469575",
"withdrawn_tokens": "348403.655627419118415",
"remaining_tokens": "10719.813947580881585"
"withdrawn_tokens": "351655.06042082973919375",
"remaining_tokens": "7468.40915417026080625"
},
{
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
@@ -55914,7 +56150,7 @@
"tranche_start": "2021-10-05T00:00:00.000Z",
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "5778205.3912159303",
"total_removed": "3421810.610823310514313769",
"total_removed": "3480709.486904665102263769",
"locked_amount": "0",
"deposits": [
{
@@ -56059,6 +56295,11 @@
}
],
"withdrawals": [
{
"amount": "58898.87608135458795",
"user": "0x83b1a48376E045D26420200345414e6b93066396",
"tx": "0xeb193da202cd833a574a524eff7f1dd13a0ee8669e51a7db36984ef4d6735fd6"
},
{
"amount": "219.945520329711288",
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
@@ -57576,6 +57817,12 @@
}
],
"withdrawals": [
{
"amount": "58898.87608135458795",
"user": "0x83b1a48376E045D26420200345414e6b93066396",
"tranche_id": 4,
"tx": "0xeb193da202cd833a574a524eff7f1dd13a0ee8669e51a7db36984ef4d6735fd6"
},
{
"amount": "66753.39849271259062",
"user": "0x83b1a48376E045D26420200345414e6b93066396",
@@ -57644,8 +57891,8 @@
}
],
"total_tokens": "1104995.291",
"withdrawn_tokens": "1046096.41491864541205",
"remaining_tokens": "58898.87608135458795"
"withdrawn_tokens": "1104995.291",
"remaining_tokens": "0"
},
{
"address": "0x5565d64f29Ea17355106DF3bA5903Eb793B3e139",
@@ -58097,8 +58344,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "472355.6199999996",
"total_removed": "43120.0853616251849",
"locked_amount": "60491.61076159115414066601116184",
"total_removed": "43365.4083448891849",
"locked_amount": "52728.553391508069839034794317608",
"deposits": [
{
"amount": "3000",
@@ -64717,6 +64964,16 @@
}
],
"withdrawals": [
{
"amount": "182.662252664",
"user": "0xb1169C6daAc76bAcaf0D8f87641Fc38fbabe569F",
"tx": "0xc182a183d124ab4faa413e71faa8c764fc265b4c568a5025ead367fbb86da331"
},
{
"amount": "62.6607306",
"user": "0x7345AaA0D0e4C4A46d921fA9323973956F2b7392",
"tx": "0xb13444d5ef684a442be6c285a6c38dcbc9959ff2eacc31474531826efe28c20a"
},
{
"amount": "168.502276762",
"user": "0x38A292CB98Dc602ECAFF94E8E5fADD9800e4bA13",
@@ -83267,6 +83524,12 @@
}
],
"withdrawals": [
{
"amount": "62.6607306",
"user": "0x7345AaA0D0e4C4A46d921fA9323973956F2b7392",
"tranche_id": 5,
"tx": "0xb13444d5ef684a442be6c285a6c38dcbc9959ff2eacc31474531826efe28c20a"
},
{
"amount": "152.077625568",
"user": "0x7345AaA0D0e4C4A46d921fA9323973956F2b7392",
@@ -83323,8 +83586,8 @@
}
],
"total_tokens": "1200",
"withdrawn_tokens": "1002.094025868",
"remaining_tokens": "197.905974132"
"withdrawn_tokens": "1064.754756468",
"remaining_tokens": "135.245243532"
},
{
"address": "0x47181cf36aDFb0b5dB7EfDB123f403D890607841",
@@ -86292,6 +86555,12 @@
}
],
"withdrawals": [
{
"amount": "182.662252664",
"user": "0xb1169C6daAc76bAcaf0D8f87641Fc38fbabe569F",
"tranche_id": 5,
"tx": "0xc182a183d124ab4faa413e71faa8c764fc265b4c568a5025ead367fbb86da331"
},
{
"amount": "78.04403856",
"user": "0xb1169C6daAc76bAcaf0D8f87641Fc38fbabe569F",
@@ -86306,8 +86575,8 @@
}
],
"total_tokens": "400",
"withdrawn_tokens": "171.538952308",
"remaining_tokens": "228.461047692"
"withdrawn_tokens": "354.201204972",
"remaining_tokens": "45.798795028"
},
{
"address": "0xF53D81D9f3A1465df9AD1b12ddDB5cC585D96877",
@@ -87784,7 +88053,7 @@
"tranche_start": "2021-12-05T00:00:00.000Z",
"tranche_end": "2022-06-05T00:00:00.000Z",
"total_added": "171288.42",
"total_removed": "69390.5995794947989",
"total_removed": "69890.5995794947989",
"locked_amount": "0",
"deposits": [
{
@@ -92024,6 +92293,16 @@
"user": "0x0715B8bA27dB75F7601A9D8E22c15dcA1487FB70",
"tx": "0x11c685c41ff0c2d5f1d7fe3b08dc84a7ddb9160764a45bc61b8f39df94729634"
},
{
"amount": "250",
"user": "0xf8Ec254406f878dA2BEd160730d238524Af3D5F6",
"tx": "0xb79fdf2dddc0ac091d7cdc737800683482d24367f18daaf5ab98c703b30bfee5"
},
{
"amount": "250",
"user": "0xBD1da3A721510B6d76f5b2C553d31753cc148bEC",
"tx": "0x17504994220684f4ba61ec374fdd5b0e4c0e0a9cfb15aa6794338b5a4de9eb68"
},
{
"amount": "1250",
"user": "0x9405F540EcC1204801De5C4444D06386BD6693F0",
@@ -99174,10 +99453,17 @@
"tx": "0x75de6ca47e0da361181d14aceb5d08e572754861465caa67a12b528886d55307"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "250",
"user": "0xBD1da3A721510B6d76f5b2C553d31753cc148bEC",
"tranche_id": 6,
"tx": "0x17504994220684f4ba61ec374fdd5b0e4c0e0a9cfb15aa6794338b5a4de9eb68"
}
],
"total_tokens": "250",
"withdrawn_tokens": "0",
"remaining_tokens": "250"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0x4e8bA6747F20009163e51Ff1b5D3edd3Ef7c6C90",
@@ -99211,10 +99497,17 @@
"tx": "0x75de6ca47e0da361181d14aceb5d08e572754861465caa67a12b528886d55307"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "250",
"user": "0xf8Ec254406f878dA2BEd160730d238524Af3D5F6",
"tranche_id": 6,
"tx": "0xb79fdf2dddc0ac091d7cdc737800683482d24367f18daaf5ab98c703b30bfee5"
}
],
"total_tokens": "250",
"withdrawn_tokens": "0",
"remaining_tokens": "250"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0xd995e89D6cCB2252388b9BaE0173981b5EfA0817",
@@ -143305,6 +143598,11 @@
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
"tx": "0x11aafa8a2fb510a50d52e5d1e149c5c2027ad2c3dc2d9ef67c18d391c0331c49"
},
{
"amount": "0",
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
"tx": "0x2e48ba2e6ca4994286e85e57d26b578fb0fd625f44a6fd27202476bb18575a40"
},
{
"amount": "0",
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
@@ -143593,6 +143891,12 @@
"tranche_id": 9,
"tx": "0x11aafa8a2fb510a50d52e5d1e149c5c2027ad2c3dc2d9ef67c18d391c0331c49"
},
{
"amount": "0",
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
"tranche_id": 9,
"tx": "0x2e48ba2e6ca4994286e85e57d26b578fb0fd625f44a6fd27202476bb18575a40"
},
{
"amount": "0",
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
+1
View File
@@ -12,6 +12,7 @@ NX_VEGA_URL=http://localhost:3028/query
NX_VEGA_WALLET_URL=http://localhost:1789
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
# Expose some env vars to cypress environment for market setup
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
+3
View File
@@ -1,8 +1,10 @@
const { defineConfig } = require('cypress');
module.exports = defineConfig({
reporter: '../../node_modules/cypress-mochawesome-reporter',
e2e: {
setupNodeEvents(on, config) {
require('cypress-mochawesome-reporter/plugin')(on);
require('@cypress/grep/src/plugin')(config);
return config;
},
@@ -23,6 +25,7 @@ module.exports = defineConfig({
responseTimeout: 50000,
requestTimeout: 20000,
retries: 2,
testIsolation: false,
},
env: {
ETHERSCAN_URL: 'https://sepolia.etherscan.io',
@@ -108,18 +108,14 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
it('risk model displayed', () => {
cy.getByTestId(marketTitle).contains('Risk model').click();
validateMarketDataRow(0, 'Typename', 'LogNormalRiskModel');
validateMarketDataRow(1, 'Tau', '0.0001140771161');
validateMarketDataRow(2, 'Risk Aversion Parameter', '0.01');
validateMarketDataRow(0, 'Tau', '0.0001140771161');
validateMarketDataRow(1, 'Risk Aversion Parameter', '0.01');
});
it('risk parameters displayed', () => {
cy.getByTestId(marketTitle).contains('Risk parameters').click();
validateMarketDataRow(0, 'Typename', 'LogNormalModelParams');
validateMarketDataRow(1, 'R', '0.016');
validateMarketDataRow(2, 'Sigma', '0.3');
validateMarketDataRow(0, 'R', '0.016');
validateMarketDataRow(1, 'Sigma', '0.3');
});
it('risk factors displayed', () => {
@@ -0,0 +1,47 @@
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { proposalListQuery, marketUpdateProposal } from '@vegaprotocol/mock';
import * as Schema from '@vegaprotocol/types';
const marketSummaryBlock = 'header-summary';
describe('Market proposal notification', { tags: '@smoke' }, () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_ACTIVE,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockGQL((req) => {
aliasGQLQuery(
req,
'ProposalsList',
proposalListQuery({
proposalsConnection: {
edges: [{ node: marketUpdateProposal }],
},
})
);
});
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@MarketData');
cy.getByTestId(marketSummaryBlock).should('be.visible');
});
it('should display market proposal notification if proposal found', () => {
cy.getByTestId(marketSummaryBlock).within(() => {
cy.getByTestId('market-proposal-notification').should(
'contain.text',
'Changes have been proposed for this market'
);
cy.getByTestId('market-proposal-notification').within(() => {
cy.getByTestId('external-link').should(
'have.attr',
'href',
`${Cypress.env('VEGA_TOKEN_URL')}/proposals/123`
);
});
});
});
});
@@ -0,0 +1,41 @@
describe('market bottom panel', { tags: '@smoke' }, () => {
before(() => {
cy.clearAllLocalStorage();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@MarketData');
});
it('on xxl screen should be splitted out into two tables', () => {
cy.getByTestId('tab-positions').should('have.attr', 'data-state', 'active');
cy.getByTestId('tab-orders').should('have.attr', 'data-state', 'inactive');
cy.getByTestId('tab-fills').should('have.attr', 'data-state', 'inactive');
cy.getByTestId('tab-accounts').should(
'have.attr',
'data-state',
'inactive'
);
cy.viewport(1801, 1000);
cy.getByTestId('tab-positions').should('have.attr', 'data-state', 'active');
cy.getByTestId('tab-orders').should('have.attr', 'data-state', 'active');
cy.getByTestId('tab-fills').should('have.attr', 'data-state', 'inactive');
cy.getByTestId('tab-accounts').should(
'have.attr',
'data-state',
'inactive'
);
cy.getByTestId('Fills').click();
cy.getByTestId('Collateral').click();
cy.getByTestId('tab-positions').should(
'have.attr',
'data-state',
'inactive'
);
cy.getByTestId('tab-orders').should('have.attr', 'data-state', 'inactive');
cy.getByTestId('tab-fills').should('have.attr', 'data-state', 'active');
cy.getByTestId('tab-accounts').should('have.attr', 'data-state', 'active');
});
});
@@ -1,5 +1,3 @@
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { proposalListQuery, marketUpdateProposal } from '@vegaprotocol/mock';
import * as Schema from '@vegaprotocol/types';
const marketSummaryBlock = 'header-summary';
@@ -15,50 +13,9 @@ const priceChangeValue = 'price-change';
const itemHeader = 'item-header';
const itemValue = 'item-value';
describe('Market proposal notification', { tags: '@smoke' }, () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_ACTIVE,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockGQL((req) => {
aliasGQLQuery(
req,
'ProposalsList',
proposalListQuery({
proposalsConnection: {
edges: [{ node: marketUpdateProposal }],
},
})
);
});
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@MarketData');
cy.getByTestId(marketSummaryBlock).should('be.visible');
});
it('should display market proposal notification if proposal found', () => {
cy.getByTestId(marketSummaryBlock).within(() => {
cy.getByTestId('market-proposal-notification').should(
'contain.text',
'Changes have been proposed for this market'
);
cy.getByTestId('market-proposal-notification').within(() => {
cy.getByTestId('external-link').should(
'have.attr',
'href',
`${Cypress.env('VEGA_TOKEN_URL')}/proposals/123`
);
});
});
});
});
describe('Market trading page', () => {
before(() => {
cy.clearAllLocalStorage();
cy.mockTradingPage(
Schema.MarketState.STATE_ACTIVE,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
@@ -165,6 +122,7 @@ describe('Market trading page', () => {
});
});
cy.getByTestId('expiry-tooltip')
.eq(0)
.should(
'contain.text',
'This market expires when triggered by its oracle, not on a set date.'
@@ -202,6 +160,7 @@ describe('Market trading page', () => {
'contain.text',
'This market is in auction until it reaches sufficient liquidity.'
)
.eq(0)
.within(() => {
cy.getByTestId('external-link')
.should('have.attr', 'href')
@@ -216,93 +175,4 @@ describe('Market trading page', () => {
});
});
});
describe('market bottom panel', { tags: '@smoke' }, () => {
it('on xxl screen should be splitted out into two tables', () => {
cy.getByTestId('tab-positions').should(
'have.attr',
'data-state',
'active'
);
cy.getByTestId('tab-orders').should(
'have.attr',
'data-state',
'inactive'
);
cy.getByTestId('tab-fills').should('have.attr', 'data-state', 'inactive');
cy.getByTestId('tab-accounts').should(
'have.attr',
'data-state',
'inactive'
);
cy.viewport(1801, 1000);
cy.getByTestId('tab-positions').should(
'have.attr',
'data-state',
'active'
);
cy.getByTestId('tab-orders').should('have.attr', 'data-state', 'active');
cy.getByTestId('tab-fills').should('have.attr', 'data-state', 'inactive');
cy.getByTestId('tab-accounts').should(
'have.attr',
'data-state',
'inactive'
);
cy.getByTestId('Fills').click();
cy.getByTestId('Collateral').click();
cy.getByTestId('tab-positions').should(
'have.attr',
'data-state',
'inactive'
);
cy.getByTestId('tab-orders').should(
'have.attr',
'data-state',
'inactive'
);
cy.getByTestId('tab-fills').should('have.attr', 'data-state', 'active');
cy.getByTestId('tab-accounts').should(
'have.attr',
'data-state',
'active'
);
});
});
});
describe('market states not accepting orders', { tags: '@smoke' }, function () {
//7002-SORD-062
//7002-SORD-063
//7002-SORD-066
const states = [
Schema.MarketState.STATE_REJECTED,
Schema.MarketState.STATE_CANCELLED,
Schema.MarketState.STATE_CLOSED,
Schema.MarketState.STATE_SETTLED,
Schema.MarketState.STATE_TRADING_TERMINATED,
];
states.forEach((marketState) => {
describe(marketState, function () {
beforeEach(function () {
cy.mockTradingPage(marketState);
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
});
it('must display that market is not accepting orders', function () {
cy.getByTestId('dealticket-error-message-summary').should(
'have.text',
`This market is ${marketState
.split('_')
.pop()
?.toLowerCase()} and not accepting orders`
);
cy.getByTestId('place-order').should('be.disabled');
});
});
});
});
+70 -77
View File
@@ -1,27 +1,32 @@
import { mockConnectWallet } from '@vegaprotocol/cypress';
beforeEach(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/');
cy.wait('@Markets');
cy.wait('@MarketsData');
cy.wait('@MarketsCandles');
cy.getByTestId('dialog-close').click();
});
describe('Navbar', { tags: '@smoke' }, () => {
before(() => {
cy.clearAllLocalStorage();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/');
cy.wait('@Markets');
cy.wait('@MarketsData');
cy.wait('@MarketsCandles');
// close welcome dialog
cy.getByTestId('dialog-close').click();
});
describe('Desktop view', { tags: '@smoke' }, () => {
describe('Navbar', () => {
const links = ['Markets', 'Trading', 'Portfolio'];
const hashes = ['#/markets/all', '#/markets/market-1', '#/portfolio'];
const pages = [
{ name: 'Markets', link: '#/markets/all' },
{ name: 'Trading', link: '#/markets' },
{ name: 'Portfolio', link: '#/portfolio' },
];
links.forEach((link, index) => {
it(`${link} should be correctly rendered`, () => {
describe('desktop view', () => {
pages.forEach(({ name, link }) => {
it(`${name} should be correctly rendered`, () => {
cy.get('nav')
.find(`a[data-testid=${link}]:visible`)
.find(`a[data-testid=${name}]:visible`)
.then((element) => {
cy.wrap(element).click();
cy.location('hash').should('equal', hashes[index]);
cy.location('hash').should('contain', link);
});
});
});
@@ -43,73 +48,61 @@ describe('Desktop view', { tags: '@smoke' }, () => {
});
});
});
});
describe('Mobile view', { tags: '@smoke' }, () => {
const viewportHeight = Cypress.config('viewportHeight');
const viewportWidth = Cypress.config('viewportWidth');
before(() => {
// a little hack to keep the viewport size between tests (cypress bug)
Cypress.config({
viewportWidth: 560,
viewportHeight: 890,
describe('mobile view', () => {
const viewportHeight = Cypress.config('viewportHeight');
const viewportWidth = Cypress.config('viewportWidth');
before(() => {
// a little hack to keep the viewport size between tests (cypress bug)
Cypress.config({
viewportWidth: 560,
viewportHeight: 890,
});
cy.viewport(560, 890);
});
cy.viewport(560, 890);
});
describe('wallet drawer', () => {
it('wallet drawer should be correctly rendered', () => {
mockConnectWallet();
cy.connectVegaWallet(true);
cy.getByTestId('connect-vega-wallet-mobile').click();
cy.getByTestId('wallets-drawer').should('be.visible');
cy.getByTestId('wallets-drawer').within((el) => {
cy.wrap(el).get('button').contains('Disconnect').click();
});
cy.getByTestId('wallets-drawer').should('not.be.visible');
});
});
describe('menu drawer', () => {
it('Markets should be correctly rendered', () => {
cy.getByTestId('button-menu-drawer').click();
cy.getByTestId('menu-drawer').should('be.visible');
cy.getByTestId('menu-drawer').within((el) => {
cy.wrap(el).getByTestId('Markets').click();
cy.location('hash').should('equal', '#/markets/all');
});
});
it('Trading should be correctly rendered', () => {
cy.getByTestId('button-menu-drawer').click();
cy.getByTestId('menu-drawer').within((el) => {
cy.wrap(el).getByTestId('Trading').click();
cy.location('hash').should('equal', '#/markets/market-1');
});
});
it('Portfolio should be correctly rendered', () => {
cy.getByTestId('button-menu-drawer').click();
cy.getByTestId('menu-drawer').within((el) => {
cy.wrap(el).getByTestId('Portfolio').click();
cy.location('hash').should('equal', '#/portfolio');
describe('wallet drawer', () => {
it('wallet drawer should be correctly rendered', () => {
mockConnectWallet();
cy.connectVegaWallet(true);
cy.getByTestId('connect-vega-wallet-mobile').click();
cy.getByTestId('wallets-drawer').should('be.visible');
cy.getByTestId('wallets-drawer').within((el) => {
cy.wrap(el).get('button').contains('Disconnect').click();
});
cy.getByTestId('wallets-drawer').should('not.be.visible');
});
});
it('Menu drawer should not be visible until opened', () => {
cy.getByTestId('menu-drawer').should('not.be.visible');
cy.getByTestId('button-menu-drawer').click();
cy.getByTestId('menu-drawer').should('be.visible');
cy.getByTestId('menu-drawer')
.find('[data-testid="theme-switcher"]')
.should('be.visible');
cy.getByTestId('button-menu-drawer').click();
cy.getByTestId('menu-drawer').should('not.be.visible');
describe('menu drawer', () => {
pages.forEach(({ name, link }) => {
it(`${name} should be correctly rendered`, () => {
cy.getByTestId('button-menu-drawer').click();
cy.getByTestId('menu-drawer').should('be.visible');
cy.getByTestId('menu-drawer').within((el) => {
cy.wrap(el).getByTestId(name).click();
cy.location('hash').should('contain', link);
});
});
});
it('Menu drawer should not be visible until opened', () => {
cy.getByTestId('menu-drawer').should('not.be.visible');
cy.getByTestId('button-menu-drawer').click();
cy.getByTestId('menu-drawer').should('be.visible');
cy.getByTestId('menu-drawer')
.find('[data-testid="theme-switcher"]')
.should('be.visible');
cy.getByTestId('button-menu-drawer').click();
cy.getByTestId('menu-drawer').should('not.be.visible');
});
});
});
after(() => {
// a little hack to keep the viewport size between tests (cypress bug)
Cypress.config({
viewportWidth,
viewportHeight,
after(() => {
// a little hack to keep the viewport size between tests (cypress bug)
Cypress.config({
viewportWidth,
viewportHeight,
});
});
});
});
@@ -1,14 +1,16 @@
import { checkSorting } from '@vegaprotocol/cypress';
beforeEach(() => {
cy.mockTradingPage();
cy.mockWeb3Provider();
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
});
describe('accounts', { tags: '@smoke' }, () => {
before(() => {
cy.clearAllLocalStorage();
cy.mockTradingPage();
cy.mockWeb3Provider();
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
cy.wait('@Assets');
});
it('renders accounts', () => {
const tradingAccountRowId = '[row-id="t-0"]';
cy.getByTestId('Collateral').click();
@@ -41,13 +43,21 @@ describe('accounts', { tags: '@smoke' }, () => {
.should('have.text', '100,001.01');
});
it('asset detail should be properly rendered', () => {
cy.getByTestId('Collateral').click();
it('should open asset details dialog when clicked on symbol', () => {
cy.getByTestId('asset').contains('tEURO').click();
cy.get('[data-testid$="_label"]').should('have.length', 16);
cy.get('[data-testid="dialog-content"]:visible').should('exist');
cy.get('[data-testid="dialog-close"]:visible').click();
});
describe('sorting by ag-grid columns should work well', () => {
before(() => {
const dialogs = Cypress.$('[data-testid="dialog-close"]:visible');
if (dialogs.length > 0) {
dialogs.each((btn) => {
cy.wrap(btn).click();
});
}
});
it('sorting by asset', () => {
cy.getByTestId('Collateral').click();
const marketsSortedDefault = ['tBTC', 'tEURO', 'tDAI', 'tBTC'];
@@ -0,0 +1,110 @@
import * as Schema from '@vegaprotocol/types';
import { testOrderSubmission } from '../support/order-validation';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
describe('must submit order', { tags: '@smoke' }, () => {
// 7002-SORD-039
before(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('successfully places market buy order', () => {
// 7002-SORD-010
// 0003-WTXN-012
// 0003-WTXN-003
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
postOnly: false,
reduceOnly: false,
size: '100',
};
createOrder(order);
testOrderSubmission(order);
});
it('successfully places market sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
size: '100',
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order);
});
it('successfully places limit buy order', () => {
// 7002-SORD-017
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '200',
};
createOrder(order);
testOrderSubmission(order, { price: '20000000' });
});
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GFN,
size: '100',
postOnly: false,
reduceOnly: false,
price: '50000',
};
createOrder(order);
testOrderSubmission(order, { price: '5000000000' });
});
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000);
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
price: '1.00',
expiresAt: expiresAt.toISOString().substring(0, 16),
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order, {
price: '100000',
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
postOnly: false,
reduceOnly: false,
});
});
});
@@ -0,0 +1,96 @@
import * as Schema from '@vegaprotocol/types';
import { mockConnectWallet } from '@vegaprotocol/cypress';
import {
orderPriceField,
placeOrderBtn,
toggleLimit,
toggleLong,
toggleMarket,
toggleShort,
} from '../support/deal-ticket';
describe('deal ticket basics', { tags: '@smoke' }, () => {
before(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.clearAllLocalStorage();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('must show place order button and connect wallet if wallet is not connected', () => {
// 0003-WTXN-001
cy.getByTestId('connect-vega-wallet'); // Not connected
cy.getByTestId('order-connect-wallet').should('exist');
cy.getByTestId(placeOrderBtn).should('exist');
cy.getByTestId('deal-ticket-connect-wallet').should('exist');
});
it('must be able to select order direction - long/short', function () {
// 7002-SORD-004
cy.getByTestId(toggleShort).click().children('input').should('be.checked');
cy.getByTestId(toggleLong).click().children('input').should('be.checked');
});
it('must be able to select order type - limit/market', function () {
// 7002-SORD-005
// 7002-SORD-006
// 7002-SORD-007
cy.getByTestId(toggleLimit).click().children('input').should('be.checked');
cy.getByTestId(toggleMarket).click().children('input').should('be.checked');
});
it('order connect vega wallet button should connect', () => {
mockConnectWallet();
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderPriceField).clear().type('101');
cy.getByTestId('order-connect-wallet').click();
cy.getByTestId('dialog-content').should('be.visible');
cy.getByTestId('connectors-list')
.find('[data-testid="connector-jsonRpc"]')
.click();
cy.wait('@walletReq');
cy.getByTestId(placeOrderBtn).should('be.visible');
cy.getByTestId(toggleLimit).children('input').should('be.checked');
cy.getByTestId(orderPriceField).should('have.value', '101');
});
});
describe(
'market states not accepting orders',
{ tags: '@smoke', testIsolation: true },
function () {
//7002-SORD-062
//7002-SORD-063
//7002-SORD-066
const states = [
Schema.MarketState.STATE_REJECTED,
Schema.MarketState.STATE_CANCELLED,
Schema.MarketState.STATE_CLOSED,
Schema.MarketState.STATE_SETTLED,
Schema.MarketState.STATE_TRADING_TERMINATED,
];
states.forEach((marketState) => {
describe(marketState, function () {
beforeEach(function () {
cy.mockTradingPage(marketState);
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
});
it('must display that market is not accepting orders', function () {
cy.getByTestId('dealticket-error-message-summary').should(
'have.text',
`This market is ${marketState
.split('_')
.pop()
?.toLowerCase()} and not accepting orders`
);
cy.getByTestId('place-order').should('be.disabled');
});
});
});
}
);
@@ -0,0 +1,92 @@
import {
orderPriceField,
orderSizeField,
orderTIFDropDown,
placeOrderBtn,
toggleLimit,
toggleMarket,
} from '../support/deal-ticket';
describe('deal ticker order validation', { tags: '@smoke' }, () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
describe('limit order', () => {
before(() => {
cy.getByTestId(toggleLimit).click();
});
it('must see the price unit', function () {
// 7002-SORD-018
cy.getByTestId(orderPriceField)
.siblings('label')
.should('have.text', 'Price (DAI)');
});
it('must see warning when placing an order with expiry date in past', () => {
const expiresAt = new Date(Date.now() - 24 * 60 * 60 * 1000);
const expiresAtInputValue = expiresAt.toISOString().substring(0, 16);
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderPriceField).clear().type('0.1');
cy.getByTestId(orderSizeField).clear().type('1');
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTT');
cy.log('choosing yesterday');
cy.getByTestId('date-picker-field').type(expiresAtInputValue);
cy.getByTestId(placeOrderBtn).click();
cy.getByTestId('dealticket-error-message-expiry').should(
'have.text',
'The expiry date that you have entered appears to be in the past'
);
});
it('must see warning if price has too many digits after decimal place', function () {
// 7002-SORD-059
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTC');
cy.getByTestId(orderSizeField).clear().type('1');
cy.getByTestId(orderPriceField).clear().type('1.123456');
cy.getByTestId('dealticket-error-message-price-limit').should(
'have.text',
'Price accepts up to 5 decimal places'
);
});
});
describe('market order', () => {
before(() => {
cy.getByTestId(toggleMarket).click();
});
it('must not see the price unit', function () {
// 7002-SORD-019
cy.getByTestId(orderPriceField).should('not.exist');
});
it('must warn if order size input has too many digits after the decimal place', function () {
// 7002-SORD-016
cy.getByTestId(orderSizeField).clear().type('1.234');
cy.getByTestId(placeOrderBtn).should('be.disabled');
cy.getByTestId('dealticket-error-message-size-market').should(
'have.text',
'Size must be whole numbers for this market'
);
});
it('must warn if order size is set to 0', function () {
cy.getByTestId(orderSizeField).clear().type('0');
cy.getByTestId(placeOrderBtn).should('be.disabled');
cy.getByTestId('dealticket-error-message-size-market').should(
'have.text',
'Size cannot be lower than 1'
);
});
});
});
@@ -0,0 +1,173 @@
import * as Schema from '@vegaprotocol/types';
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import {
accountsQuery,
amendGeneralAccountBalance,
estimateOrderQuery,
} from '@vegaprotocol/mock';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
describe(
'account validation',
{ tags: '@regression', testIsolation: true },
() => {
describe('zero balance error', () => {
beforeEach(() => {
cy.setVegaWallet();
cy.mockTradingPage();
const accounts = accountsQuery();
amendGeneralAccountBalance(accounts, 'market-0', '0');
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Accounts', accounts);
});
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('should show an error if your balance is zero', () => {
cy.getByTestId('place-order').should('be.disabled');
// 7002-SORD-003
cy.getByTestId('dealticket-error-message-zero-balance').should(
'have.text',
'You need ' +
'tDAI' +
' in your wallet to trade in this market.See all your collateral.Make a deposit'
);
cy.getByTestId('deal-ticket-deposit-dialog-button').should('exist');
});
});
describe('not enough balance warning', () => {
beforeEach(() => {
cy.setVegaWallet();
cy.mockTradingPage();
const accounts = accountsQuery();
amendGeneralAccountBalance(accounts, 'market-0', '100000000');
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Accounts', accounts);
});
cy.mockGQL((req) => {
aliasGQLQuery(req, 'EstimateOrder', estimateOrderQuery());
});
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('should display info and button for deposit', () => {
// 7002-SORD-003
// warning should show immediately
cy.getByTestId('dealticket-warning-margin').should(
'contain.text',
'You may not have enough margin available to open this position'
);
cy.getByTestId('dealticket-warning-margin').should(
'contain.text',
'You may not have enough margin available to open this position. 2,354.72283 tDAI is currently required. You have only 1,000.01 tDAI available.'
);
cy.getByTestId('deal-ticket-deposit-dialog-button').click();
cy.getByTestId('dialog-content')
.find('h1')
.eq(0)
.should('have.text', 'Deposit');
});
});
describe('must submit order', { tags: '@smoke' }, () => {
// 7002-SORD-039
beforeEach(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('must see a prompt to check connected vega wallet to approve transaction', () => {
// 0003-WTXN-002
cy.mockVegaWalletTransaction(1000);
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
size: '100',
};
createOrder(order);
cy.getByTestId('toast-content').should(
'contain.text',
'Please go to your Vega wallet application and approve or reject the transaction.'
);
});
it('must show error returned by wallet ', () => {
// 0003-WTXN-009
// 0003-WTXN-011
// 0002-WCON-016
// 0003-WTXN-008
//trigger error from the wallet
cy.intercept('POST', 'http://localhost:1789/api/v2/requests', (req) => {
req.on('response', (res) => {
res.send({
jsonrpc: '2.0',
id: '1',
});
});
});
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
size: '100',
};
createOrder(order);
cy.getByTestId('toast-content').should(
'contain.text',
'The connection to your Vega Wallet has been lost.'
);
cy.getByTestId('connect-vega-wallet').click();
cy.getByTestId('dialog-content').should('be.visible');
});
it('must see that the order was rejected by the connected wallet', () => {
// 0003-WTXN-007
//trigger rejection error from the wallet
cy.intercept('POST', 'http://localhost:1789/api/v2/requests', (req) => {
req.alias = 'client.send_transaction';
req.reply({
statusCode: 400,
body: {
jsonrpc: '2.0',
error: {
code: 3001,
data: 'the user rejected the wallet connection',
message: 'User error',
},
id: '0',
},
});
});
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
size: '100',
};
createOrder(order);
cy.getByTestId('toast-content').should(
'contain.text',
'Error occurredthe user rejected the wallet connection'
);
});
});
}
);
@@ -0,0 +1,87 @@
import * as Schema from '@vegaprotocol/types';
import { testOrderSubmission } from '../support/order-validation';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
const displayTomorrow = () => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
return tomorrow.toISOString().substring(0, 16);
};
describe(
'must submit order for market in batch auction',
{ tags: '@regression' },
() => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('successfully places limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '200',
};
createOrder(order);
testOrderSubmission(order, { price: '20000000' });
});
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '50000',
};
createOrder(order);
testOrderSubmission(order, { price: '5000000000' });
});
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
postOnly: false,
reduceOnly: false,
price: '1.00',
expiresAt: displayTomorrow(),
};
createOrder(order);
testOrderSubmission(order, {
price: '100000',
postOnly: false,
reduceOnly: false,
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
});
});
}
);
@@ -0,0 +1,85 @@
import * as Schema from '@vegaprotocol/types';
import { testOrderSubmission } from '../support/order-validation';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
const displayTomorrow = () => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
return tomorrow.toISOString().substring(0, 16);
};
describe(
'must submit order for market in monitoring auction',
{ tags: '@regression' },
() => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('successfully places limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '200',
};
createOrder(order);
testOrderSubmission(order, { price: '20000000' });
});
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
price: '50000',
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order, { price: '5000000000' });
});
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
price: '1.00',
expiresAt: displayTomorrow(),
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order, {
price: '100000',
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
});
});
}
);
@@ -0,0 +1,85 @@
import * as Schema from '@vegaprotocol/types';
import { testOrderSubmission } from '../support/order-validation';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
const displayTomorrow = () => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
return tomorrow.toISOString().substring(0, 16);
};
describe(
'must submit order for market in opening auction',
{ tags: '@regression' },
() => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('successfully places limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '200',
};
createOrder(order);
testOrderSubmission(order, { price: '20000000' });
});
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '50000',
};
createOrder(order);
testOrderSubmission(order, { price: '5000000000' });
});
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
price: '1.00',
expiresAt: displayTomorrow(),
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order, {
price: '100000',
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
});
});
}
);
@@ -0,0 +1,68 @@
import * as Schema from '@vegaprotocol/types';
import {
TIFlist,
orderPriceField,
orderSizeField,
orderTIFDropDown,
placeOrderBtn,
toggleLimit,
toggleMarket,
} from '../support/deal-ticket';
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { accountsQuery } from '@vegaprotocol/mock';
describe('suspended market validation', { tags: '@regression' }, () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
const accounts = accountsQuery();
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Accounts', accounts);
});
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('should show warning for market order', function () {
cy.getByTestId(toggleMarket).click();
cy.getByTestId(placeOrderBtn).should('not.be.disabled');
cy.getByTestId(placeOrderBtn).click();
cy.getByTestId(placeOrderBtn).should('be.disabled');
cy.getByTestId('dealticket-error-message-type').should(
'have.text',
'This market is in auction until it reaches sufficient liquidity. Only limit orders are permitted when market is in auction'
);
});
it('should show info for allowed TIF', function () {
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderPriceField).clear().type('0.1');
cy.getByTestId(orderSizeField).clear().type('1');
cy.getByTestId(placeOrderBtn).should('be.enabled');
cy.getByTestId('dealticket-warning-auction').should(
'have.text',
'Any orders placed now will not trade until the auction ends'
);
});
it('should show warning for not allowed TIF', function () {
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderTIFDropDown).select(
TIFlist.filter((item) => item.code === 'FOK')[0].value
);
cy.getByTestId(placeOrderBtn).should('be.disabled');
cy.getByTestId('dealticket-error-message-tif').should(
'have.text',
'This market is in auction until it reaches sufficient liquidity. Until the auction ends, you can only place GFA, GTT, or GTC limit orders'
);
});
});
@@ -1,580 +0,0 @@
import * as Schema from '@vegaprotocol/types';
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { testOrderSubmission } from '../support/order-validation';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import {
accountsQuery,
estimateOrderQuery,
amendGeneralAccountBalance,
} from '@vegaprotocol/mock';
import { createOrder } from '../support/create-order';
const orderSizeField = 'order-size';
const orderPriceField = 'order-price';
const orderTIFDropDown = 'order-tif';
const placeOrderBtn = 'place-order';
const toggleLimit = 'order-type-TYPE_LIMIT';
const toggleMarket = 'order-type-TYPE_MARKET';
const TIFlist = Object.values(Schema.OrderTimeInForce).map((value) => {
return {
code: Schema.OrderTimeInForceCode[value],
value,
text: Schema.OrderTimeInForceMapping[value],
};
});
const displayTomorrow = () => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
return tomorrow.toISOString().substring(0, 16);
};
describe('must submit order', { tags: '@smoke' }, () => {
// 7002-SORD-039
before(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('successfully places market buy order', () => {
// 7002-SORD-010
// 0003-WTXN-012
// 0003-WTXN-003
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
postOnly: false,
reduceOnly: false,
size: '100',
};
createOrder(order);
testOrderSubmission(order);
});
it('successfully places market sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
size: '100',
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order);
});
it('successfully places limit buy order', () => {
// 7002-SORD-017
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '200',
};
createOrder(order);
testOrderSubmission(order, { price: '20000000' });
});
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GFN,
size: '100',
postOnly: false,
reduceOnly: false,
price: '50000',
};
createOrder(order);
testOrderSubmission(order, { price: '5000000000' });
});
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000);
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
price: '1.00',
expiresAt: expiresAt.toISOString().substring(0, 16),
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order, {
price: '100000',
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
postOnly: false,
reduceOnly: false,
});
});
});
describe(
'must submit order for market in batch auction',
{ tags: '@regression' },
() => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('successfully places limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '200',
};
createOrder(order);
testOrderSubmission(order, { price: '20000000' });
});
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '50000',
};
createOrder(order);
testOrderSubmission(order, { price: '5000000000' });
});
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
postOnly: false,
reduceOnly: false,
price: '1.00',
expiresAt: displayTomorrow(),
};
createOrder(order);
testOrderSubmission(order, {
price: '100000',
postOnly: false,
reduceOnly: false,
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
});
});
}
);
describe(
'must submit order for market in opening auction',
{ tags: '@regression' },
() => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('successfully places limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '200',
};
createOrder(order);
testOrderSubmission(order, { price: '20000000' });
});
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '50000',
};
createOrder(order);
testOrderSubmission(order, { price: '5000000000' });
});
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
price: '1.00',
expiresAt: displayTomorrow(),
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order, {
price: '100000',
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
});
});
}
);
describe(
'must submit order for market in monitoring auction',
{ tags: '@regression' },
() => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('successfully places limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '200',
};
createOrder(order);
testOrderSubmission(order, { price: '20000000' });
});
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
price: '50000',
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order, { price: '5000000000' });
});
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
price: '1.00',
expiresAt: displayTomorrow(),
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order, {
price: '100000',
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
});
});
}
);
describe('suspended market validation', { tags: '@regression' }, () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
const accounts = accountsQuery();
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Accounts', accounts);
});
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('should show warning for market order', function () {
cy.getByTestId(toggleMarket).click();
cy.getByTestId(placeOrderBtn).should('not.be.disabled');
cy.getByTestId(placeOrderBtn).click();
cy.getByTestId(placeOrderBtn).should('be.disabled');
cy.getByTestId('dealticket-error-message-type').should(
'have.text',
'This market is in auction until it reaches sufficient liquidity. Only limit orders are permitted when market is in auction'
);
});
it('should show info for allowed TIF', function () {
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderPriceField).clear().type('0.1');
cy.getByTestId(orderSizeField).clear().type('1');
cy.getByTestId(placeOrderBtn).should('be.enabled');
cy.getByTestId('dealticket-warning-auction').should(
'have.text',
'Any orders placed now will not trade until the auction ends'
);
});
it('should show warning for not allowed TIF', function () {
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderTIFDropDown).select(
TIFlist.filter((item) => item.code === 'FOK')[0].value
);
cy.getByTestId(placeOrderBtn).should('be.disabled');
cy.getByTestId('dealticket-error-message-tif').should(
'have.text',
'This market is in auction until it reaches sufficient liquidity. Until the auction ends, you can only place GFA, GTT, or GTC limit orders'
);
});
});
describe('account validation', { tags: '@regression' }, () => {
describe('zero balance error', () => {
beforeEach(() => {
cy.setVegaWallet();
cy.mockTradingPage();
const accounts = accountsQuery();
amendGeneralAccountBalance(accounts, 'market-0', '0');
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Accounts', accounts);
});
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('should show an error if your balance is zero', () => {
cy.getByTestId('place-order').should('be.disabled');
// 7002-SORD-003
cy.getByTestId('dealticket-error-message-zero-balance').should(
'have.text',
'You need ' +
'tDAI' +
' in your wallet to trade in this market.See all your collateral.Make a deposit'
);
cy.getByTestId('deal-ticket-deposit-dialog-button').should('exist');
});
});
describe('not enough balance warning', () => {
beforeEach(() => {
cy.setVegaWallet();
cy.mockTradingPage();
const accounts = accountsQuery();
amendGeneralAccountBalance(accounts, 'market-0', '100000000');
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Accounts', accounts);
});
cy.mockGQL((req) => {
aliasGQLQuery(req, 'EstimateOrder', estimateOrderQuery());
});
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('should display info and button for deposit', () => {
// 7002-SORD-003
// warning should show immediately
cy.getByTestId('dealticket-warning-margin').should(
'contain.text',
'You may not have enough margin available to open this position'
);
cy.getByTestId('dealticket-warning-margin').should(
'contain.text',
'You may not have enough margin available to open this position. 2,354.72283 tDAI is currently required. You have only 1,000.01 tDAI available.'
);
cy.getByTestId('deal-ticket-deposit-dialog-button').click();
cy.getByTestId('dialog-content')
.find('h1')
.eq(0)
.should('have.text', 'Deposit');
});
});
describe('must submit order', { tags: '@smoke' }, () => {
// 7002-SORD-039
beforeEach(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('must see a prompt to check connected vega wallet to approve transaction', () => {
// 0003-WTXN-002
cy.mockVegaWalletTransaction(1000);
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
size: '100',
};
createOrder(order);
cy.getByTestId('toast-content').should(
'contain.text',
'Please go to your Vega wallet application and approve or reject the transaction.'
);
});
it('must show error returned by wallet ', () => {
// 0003-WTXN-009
// 0003-WTXN-011
// 0002-WCON-016
// 0003-WTXN-008
//trigger error from the wallet
cy.intercept('POST', 'http://localhost:1789/api/v2/requests', (req) => {
req.on('response', (res) => {
res.send({
jsonrpc: '2.0',
id: '1',
});
});
});
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
size: '100',
};
createOrder(order);
cy.getByTestId('toast-content').should(
'contain.text',
'The connection to your Vega Wallet has been lost.'
);
cy.getByTestId('connect-vega-wallet').click();
cy.getByTestId('dialog-content').should('be.visible');
});
it('must see that the order was rejected by the connected wallet', () => {
// 0003-WTXN-007
//trigger rejection error from the wallet
cy.intercept('POST', 'http://localhost:1789/api/v2/requests', (req) => {
req.alias = 'client.send_transaction';
req.reply({
statusCode: 400,
body: {
jsonrpc: '2.0',
error: {
code: 3001,
data: 'the user rejected the wallet connection',
message: 'User error',
},
id: '0',
},
});
});
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
size: '100',
};
createOrder(order);
cy.getByTestId('toast-content').should(
'contain.text',
'Error occurredthe user rejected the wallet connection'
);
});
});
});
@@ -0,0 +1,157 @@
import {
TIFlist,
orderTIFDropDown,
toggleLimit,
toggleMarket,
} from '../support/deal-ticket';
describe('time in force validation', { tags: '@smoke' }, () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockSubscription();
cy.clearAllLocalStorage();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('must have market order set up to IOC by default', function () {
// 7002-SORD-030
cy.getByTestId(toggleMarket).click();
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
TIFlist.filter((item) => item.code === 'IOC')[0].text
);
});
it('must have time in force set to GTC for limit order', function () {
// 7002-SORD-031
cy.getByTestId(toggleLimit).click();
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
TIFlist.filter((item) => item.code === 'GTC')[0].text
);
});
it('selections should be remembered', () => {
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTT');
cy.getByTestId(toggleMarket).click();
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
TIFlist.filter((item) => item.code === 'IOC')[0].text
);
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_FOK');
cy.getByTestId(toggleLimit).click();
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
TIFlist.filter((item) => item.code === 'GTT')[0].text
);
cy.getByTestId(toggleMarket).click();
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
TIFlist.filter((item) => item.code === 'FOK')[0].text
);
});
describe('limit order', () => {
before(() => {
cy.getByTestId(toggleLimit).click();
});
const validTIF = TIFlist;
validTIF.forEach((tif) => {
// 7002-SORD-023
// 7002-SORD-024
// 7002-SORD-025
// 7002-SORD-026
// 7002-SORD-027
// 7002-SORD-028
it(`must be able to select ${tif.code}`, function () {
cy.getByTestId(orderTIFDropDown).select(tif.value);
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
tif.text
);
});
});
});
describe('market order', () => {
before(() => {
cy.getByTestId(toggleMarket).click();
});
const validTIF = TIFlist.filter((tif) => ['FOK', 'IOC'].includes(tif.code));
const invalidTIF = TIFlist.filter(
(tif) => !['FOK', 'IOC'].includes(tif.code)
);
validTIF.forEach((tif) => {
// 7002-SORD-025
// 7002-SORD-026
it(`must be able to select ${tif.code}`, function () {
cy.getByTestId(orderTIFDropDown).select(tif.value);
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
tif.text
);
});
});
invalidTIF.forEach((tif) => {
// 7002-SORD-023
// 7002-SORD-024
// 7002-SORD-027
// 7002-SORD-028
it(`must not be able to select ${tif.code}`, function () {
cy.getByTestId(orderTIFDropDown).should('not.contain', tif.text);
});
});
});
describe('post and reduce - market order', () => {
before(() => {
cy.getByTestId(toggleMarket).click();
});
const validTIF = TIFlist.filter((tif) => ['FOK', 'IOC'].includes(tif.code));
validTIF.forEach((tif) => {
// 7002-SORD-025
// 7002-SORD-026
it(`post and reduce order market for ${tif.code}`, function () {
cy.getByTestId(orderTIFDropDown).select(tif.value);
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
tif.text
);
cy.getByTestId('post-only').should('be.disabled');
cy.getByTestId('reduce-only').should('be.enabled');
});
});
});
describe('post and reduce - limit order', () => {
before(() => {
cy.getByTestId(toggleLimit).click();
});
const validTIFLimit = TIFlist.filter((tif) =>
['GFA', 'GFN', 'GTC', 'GTT'].includes(tif.code)
);
validTIFLimit.forEach((tif) => {
it(`post and reduce order for limit ${tif.code}`, function () {
cy.getByTestId(orderTIFDropDown).select(tif.value);
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
tif.text
);
cy.getByTestId('post-only').should('be.enabled');
cy.getByTestId('reduce-only').should('be.disabled');
});
});
});
});
@@ -1,329 +0,0 @@
import * as Schema from '@vegaprotocol/types';
import { mockConnectWallet } from '@vegaprotocol/cypress';
const orderSizeField = 'order-size';
const orderPriceField = 'order-price';
const orderTIFDropDown = 'order-tif';
const placeOrderBtn = 'place-order';
const toggleShort = 'order-side-SIDE_SELL';
const toggleLong = 'order-side-SIDE_BUY';
const toggleLimit = 'order-type-TYPE_LIMIT';
const toggleMarket = 'order-type-TYPE_MARKET';
const TIFlist = Object.values(Schema.OrderTimeInForce).map((value) => {
return {
code: Schema.OrderTimeInForceCode[value],
value,
text: Schema.OrderTimeInForceMapping[value],
};
});
describe('time in force default values', () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('must have market order set up to IOC by default', function () {
// 7002-SORD-030
cy.getByTestId(toggleMarket).click();
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
TIFlist.filter((item) => item.code === 'IOC')[0].text
);
});
it('must have time in force set to GTC for limit order', function () {
// 7002-SORD-031
cy.getByTestId(toggleLimit).click();
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
TIFlist.filter((item) => item.code === 'GTC')[0].text
);
});
});
describe('deal ticket validation', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockTradingPage();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('must show place order button and connect wallet if wallet is not connected', () => {
// 0003-WTXN-001
cy.getByTestId('connect-vega-wallet'); // Not connected
cy.getByTestId('order-connect-wallet').should('exist');
cy.getByTestId(placeOrderBtn).should('exist');
cy.getByTestId('deal-ticket-connect-wallet').should('exist');
});
it('must be able to select order direction - long/short', function () {
// 7002-SORD-004
cy.getByTestId(toggleShort).click().children('input').should('be.checked');
cy.getByTestId(toggleLong).click().children('input').should('be.checked');
});
it('must be able to select order type - limit/market', function () {
// 7002-SORD-005
// 7002-SORD-006
// 7002-SORD-007
cy.getByTestId(toggleLimit).click().children('input').should('be.checked');
cy.getByTestId(toggleMarket).click().children('input').should('be.checked');
});
it('order connect vega wallet button should connect', () => {
mockConnectWallet();
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderPriceField).clear().type('101');
cy.getByTestId('order-connect-wallet').click();
cy.getByTestId('dialog-content').should('be.visible');
cy.getByTestId('connectors-list')
.find('[data-testid="connector-jsonRpc"]')
.click();
cy.wait('@walletReq');
cy.getByTestId(placeOrderBtn).should('be.visible');
cy.getByTestId(toggleLimit).children('input').should('be.checked');
cy.getByTestId(orderPriceField).should('have.value', '101');
});
});
describe('deal ticket size validation', { tags: '@smoke' }, function () {
beforeEach(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('must warn if order size input has too many digits after the decimal place', function () {
// 7002-SORD-016
cy.getByTestId('order-type-TYPE_MARKET').click();
cy.getByTestId(orderSizeField).clear().type('1.234');
cy.getByTestId(placeOrderBtn).should('not.be.disabled');
cy.getByTestId(placeOrderBtn).click();
cy.getByTestId(placeOrderBtn).should('be.disabled');
cy.getByTestId('dealticket-error-message-size-market').should(
'have.text',
'Size must be whole numbers for this market'
);
});
it('must warn if order size is set to 0', function () {
cy.getByTestId('order-type-TYPE_MARKET').click();
cy.getByTestId(orderSizeField).clear().type('0');
cy.getByTestId(placeOrderBtn).should('not.be.disabled');
cy.getByTestId(placeOrderBtn).click();
cy.getByTestId(placeOrderBtn).should('be.disabled');
cy.getByTestId('dealticket-error-message-size-market').should(
'have.text',
'Size cannot be lower than 1'
);
});
});
describe('limit order validations', { tags: '@smoke' }, () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
cy.getByTestId(toggleLimit).click();
});
beforeEach(() => {
cy.setVegaWallet();
});
it('must see the price unit', function () {
// 7002-SORD-018
cy.getByTestId(orderPriceField)
.siblings('label')
.should('have.text', 'Price (DAI)');
});
it('must see warning when placing an order with expiry date in past', () => {
const expiresAt = new Date(Date.now() - 24 * 60 * 60 * 1000);
const expiresAtInputValue = expiresAt.toISOString().substring(0, 16);
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderPriceField).clear().type('0.1');
cy.getByTestId(orderSizeField).clear().type('1');
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTT');
cy.log('choosing yesterday');
cy.getByTestId('date-picker-field').type(expiresAtInputValue);
cy.getByTestId(placeOrderBtn).click();
cy.getByTestId('dealticket-error-message-expiry').should(
'have.text',
'The expiry date that you have entered appears to be in the past'
);
});
it('must see warning if price has too many digits after decimal place', function () {
// 7002-SORD-059
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTC');
cy.getByTestId(orderSizeField).clear().type('1');
cy.getByTestId(orderPriceField).clear().type('1.123456');
cy.getByTestId('dealticket-error-message-price-limit').should(
'have.text',
'Price accepts up to 5 decimal places'
);
});
describe('time in force validations', function () {
const validTIF = TIFlist;
validTIF.forEach((tif) => {
// 7002-SORD-023
// 7002-SORD-024
// 7002-SORD-025
// 7002-SORD-026
// 7002-SORD-027
// 7002-SORD-028
it(`must be able to select ${tif.code}`, function () {
cy.getByTestId(orderTIFDropDown).select(tif.value);
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
tif.text
);
});
});
it('selections should be remembered', () => {
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTT');
cy.getByTestId(toggleMarket).click();
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
TIFlist.filter((item) => item.code === 'IOC')[0].text
);
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_FOK');
cy.getByTestId(toggleLimit).click();
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
TIFlist.filter((item) => item.code === 'GTT')[0].text
);
cy.getByTestId(toggleMarket).click();
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
TIFlist.filter((item) => item.code === 'FOK')[0].text
);
});
});
});
describe('market order validations', { tags: '@smoke' }, () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
cy.getByTestId(toggleMarket).click();
});
beforeEach(() => {
cy.setVegaWallet();
});
it('must not see the price unit', function () {
// 7002-SORD-019
cy.getByTestId(orderPriceField).should('not.exist');
});
describe('time in force validations', function () {
const validTIF = TIFlist.filter((tif) => ['FOK', 'IOC'].includes(tif.code));
const invalidTIF = TIFlist.filter(
(tif) => !['FOK', 'IOC'].includes(tif.code)
);
validTIF.forEach((tif) => {
// 7002-SORD-025
// 7002-SORD-026
it(`must be able to select ${tif.code}`, function () {
cy.getByTestId(orderTIFDropDown).select(tif.value);
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
tif.text
);
});
});
invalidTIF.forEach((tif) => {
// 7002-SORD-023
// 7002-SORD-024
// 7002-SORD-027
// 7002-SORD-028
it(`must not be able to select ${tif.code}`, function () {
cy.getByTestId(orderTIFDropDown).should('not.contain', tif.text);
});
});
});
});
describe('post and reduce order validations', { tags: '@smoke' }, () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
cy.getByTestId(toggleMarket).click();
});
beforeEach(() => {
cy.setVegaWallet();
});
const validTIF = TIFlist.filter((tif) => ['FOK', 'IOC'].includes(tif.code));
validTIF.forEach((tif) => {
// 7002-SORD-025
// 7002-SORD-026
it(`post and reduce order market for ${tif.code}`, function () {
cy.getByTestId(orderTIFDropDown).select(tif.value);
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
tif.text
);
cy.getByTestId('post-only').should('be.disabled');
cy.getByTestId('reduce-only').should('be.enabled');
});
});
validTIF.forEach((tif) => {
it(`post and reduce order limit for ${tif.code}`, function () {
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderTIFDropDown).select(tif.value);
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
tif.text
);
cy.getByTestId('post-only').should('be.disabled');
cy.getByTestId('reduce-only').should('be.enabled');
});
});
const validTIFLimit = TIFlist.filter((tif) =>
['GFA', 'GFN', 'GTC', 'GTT'].includes(tif.code)
);
validTIFLimit.forEach((tif) => {
it(`post and reduce order for limit ${tif.code}`, function () {
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderTIFDropDown).select(tif.value);
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
'have.text',
tif.text
);
cy.getByTestId('post-only').should('be.enabled');
cy.getByTestId('reduce-only').should('be.disabled');
});
});
});
@@ -1,7 +1,18 @@
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { fillsQuery } from '@vegaprotocol/mock';
const tabFills = 'tab-fills';
describe('fills', { tags: '@regression' }, () => {
// 7005-FILL-001
// 7005-FILL-002
// 7005-FILL-003
// 7005-FILL-004
// 7005-FILL-005
// 7005-FILL-006
// 7005-FILL-007
// 7005-FILL-008
beforeEach(() => {
// Ensure page loads with correct key
cy.window().then((window) => {
@@ -38,31 +49,37 @@ describe('fills', { tags: '@regression' }, () => {
});
function validateFillsDisplayed() {
cy.getByTestId('tab-fills').should('be.visible');
cy.getByTestId('tab-fills')
cy.getByTestId(tabFills).should('be.visible');
cy.getByTestId(tabFills).contains('Market');
cy.getByTestId(tabFills)
.get(
'[role="gridcell"][col-id="market.tradableInstrument.instrument.name"]'
)
.each(($marketSymbol) => {
cy.wrap($marketSymbol).invoke('text').should('not.be.empty');
});
cy.getByTestId('tab-fills')
cy.getByTestId(tabFills).contains('Size');
cy.get(`[col-id='size']`).eq(1).should('contain.text', '+');
cy.get(`[col-id='size']`).eq(2).should('contain.text', '-');
cy.getByTestId(tabFills)
.get('[role="gridcell"][col-id="size"]')
.each(($amount) => {
cy.wrap($amount).invoke('text').should('not.be.empty');
});
cy.getByTestId('tab-fills')
cy.getByTestId(tabFills).contains('Price');
cy.getByTestId(tabFills)
.get('[role="gridcell"][col-id="price"]')
.each(($prices) => {
cy.wrap($prices).invoke('text').should('not.be.empty');
});
cy.getByTestId('tab-fills')
cy.getByTestId(tabFills).contains('Notional');
cy.getByTestId(tabFills)
.get('[role="gridcell"][col-id="price_1"]')
.each(($total) => {
cy.wrap($total).invoke('text').should('not.be.empty');
});
cy.getByTestId('tab-fills')
cy.getByTestId(tabFills).contains('Role');
cy.getByTestId(tabFills)
.get('[role="gridcell"][col-id="aggressor"]')
.each(($role) => {
cy.wrap($role)
@@ -72,13 +89,15 @@ describe('fills', { tags: '@regression' }, () => {
expect(roles.indexOf(text.trim())).to.be.greaterThan(-1);
});
});
cy.getByTestId('tab-fills')
cy.getByTestId(tabFills).contains('Fee');
cy.getByTestId(tabFills)
.get(
'[role="gridcell"][col-id="market.tradableInstrument.instrument.product"]'
)
.each(($fees) => {
cy.wrap($fees).invoke('text').should('not.be.empty');
});
cy.getByTestId(tabFills).contains('Date');
const dateTimeRegex =
/(\d{1,2})\/(\d{1,2})\/(\d{4}), (\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
cy.get('[col-id="createdAt"]').each(($tradeDateTime, index) => {
@@ -21,7 +21,7 @@ const cancelOrderBtn = 'cancel';
const cancelAllOrdersBtn = 'cancelAll';
const editOrderBtn = 'edit';
describe('orders list', { tags: '@smoke' }, () => {
describe('orders list', { tags: '@smoke', testIsolation: true }, () => {
beforeEach(() => {
const subscriptionMocks = getSubscriptionMocks();
cy.spy(subscriptionMocks, 'OrdersUpdate');
@@ -89,15 +89,17 @@ describe('orders list', { tags: '@smoke' }, () => {
cy.contains('Partially Filled').click();
cy.getByTestId('Orders').click();
cy.get(`[row-id="${partiallyFilledId}"]`).within(() => {
cy.get(`[col-id='${orderStatus}']`).should(
'have.text',
'Partially Filled'
);
cy.get(`[col-id='${orderRemaining}']`).should('have.text', '7/10');
cy.getByTestId(cancelOrderBtn).should('not.exist');
cy.getByTestId(editOrderBtn).should('not.exist');
});
cy.get(`[row-id="${partiallyFilledId}"]`)
.eq(1)
.within(() => {
cy.get(`[col-id='${orderStatus}']`).should(
'have.text',
'Partially Filled'
);
cy.get(`[col-id='${orderRemaining}']`).should('have.text', '7/10');
cy.getByTestId(cancelOrderBtn).should('not.exist');
cy.getByTestId(editOrderBtn).should('not.exist');
});
});
it('orders are sorted by most recent order', () => {
@@ -424,7 +426,7 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
.find(`[data-testid="cancel"]`)
.should('have.text', 'Cancel')
.then(($btn) => {
cy.wrap($btn).click();
cy.wrap($btn).click({ force: true });
const order: OrderCancellation = {
orderId: orderId,
marketId: 'market-0',
@@ -445,7 +447,7 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
cy.get(`[data-testid="cancelAll"]`)
.should('have.text', 'Cancel all')
.then(($btn) => {
cy.wrap($btn).click();
cy.wrap($btn).click({ force: true });
const order: OrderCancellation = {
marketId: 'market-0',
};
@@ -464,7 +466,7 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
.find('[data-testid="edit"]')
.should('have.text', 'Edit')
.then(($btn) => {
cy.wrap($btn).click();
cy.wrap($btn).click({ force: true });
cy.getByTestId('dialog-title').should('have.text', 'Edit order');
cy.get('#limitPrice').focus().clear().type('0.111111');
cy.getByTestId('edit-order').find('[type="submit"]').click();
@@ -8,7 +8,7 @@ beforeEach(() => {
cy.setVegaWallet();
});
describe('positions', { tags: '@smoke' }, () => {
describe('positions', { tags: '@smoke', testIsolation: true }, () => {
it('renders positions on trading page', () => {
cy.visit('/#/markets/market-0');
cy.getByTestId('Positions').click();
@@ -53,13 +53,17 @@ describe('positions', { tags: '@smoke' }, () => {
'currentLeverage',
'averageEntryPrice',
];
cy.getByTestId('tab-positions').within(() => {
cy.get('[row-id="market-2"]').within(() => {
emptyCells.forEach((cell) => {
cy.get(`[col-id="${cell}"]`).should('contain.text', '-');
});
cy.getByTestId('tab-positions')
.first()
.within(() => {
cy.get('[row-id="market-2"]')
.eq(1)
.within(() => {
emptyCells.forEach((cell) => {
cy.get(`[col-id="${cell}"]`).should('contain.text', '-');
});
});
});
});
});
it('error message should be displayed', () => {
const errors = [
@@ -2,7 +2,7 @@ import { connectEthereumWallet } from '../support/ethereum-wallet';
const connectEthWalletBtn = 'connect-eth-wallet-btn';
describe('ethereum wallet', { tags: '@smoke' }, () => {
describe('ethereum wallet', { tags: '@smoke', testIsolation: true }, () => {
beforeEach(() => {
cy.mockWeb3Provider();
// Using portfolio withdrawals tab is it requires Ethereum wallet connection
@@ -27,7 +27,7 @@ describe('ethereum wallet', { tags: '@smoke' }, () => {
cy.getByTestId('tab-deposits').should('not.be.empty');
});
it('should see an option to cancel the attempted connection', () => {
it('should see QR code modal for WalletConnect', () => {
// 0004-EWAL-003
cy.wait('@NetworkParams');
@@ -36,8 +36,8 @@ describe('ethereum wallet', { tags: '@smoke' }, () => {
cy.getByTestId('connect-eth-wallet-btn').click();
cy.getByTestId('web3-connector-list').should('exist');
cy.getByTestId('web3-connector-WalletConnect').click();
cy.get('#walletconnect-qrcode-text').should('exist');
cy.get('#walletconnect-qrcode-close').click();
// testing if exists rather than visible because of the long loading time
cy.get('w3m-modal').should('exist');
});
it('able to disconnect eth wallet', () => {
@@ -8,103 +8,115 @@ const manageVegaBtn = 'manage-vega-wallet';
const form = 'rest-connector-form';
const dialogContent = 'dialog-content';
describe('connect hosted wallet', { tags: '@smoke' }, () => {
beforeEach(() => {
// Using portfolio page as it requires vega wallet connection
cy.visit('/#/portfolio');
cy.mockTradingPage();
cy.mockSubscription();
cy.get('main[data-testid="/portfolio"]').should('exist');
});
it('can connect', () => {
// 0002-WCON-002
// 0002-WCON-003
// 0002-WCON-039
// 0002-WCON-017
// 0002-WCON-018
// 0002-WCON-019
// Mock authentication
cy.intercept('POST', 'https://wallet.testnet.vega.xyz/api/v1/auth/token', {
body: {
token: 'test-token',
},
describe(
'connect hosted wallet',
{ tags: '@smoke', testIsolation: true },
() => {
beforeEach(() => {
// Using portfolio page as it requires vega wallet connection
cy.visit('/#/portfolio');
cy.mockTradingPage();
cy.mockSubscription();
cy.get('main[data-testid="/portfolio"]').should('exist');
});
// Mock getting keys from wallet
cy.intercept('GET', 'https://wallet.testnet.vega.xyz/api/v1/keys', {
body: {
keys: [
{
algorithm: {
name: 'algo',
version: 1,
},
index: 0,
meta: [],
pub: 'HOSTED_PUBKEY',
tainted: false,
it('can connect', () => {
// 0002-WCON-002
// 0002-WCON-003
// 0002-WCON-039
// 0002-WCON-017
// 0002-WCON-018
// 0002-WCON-019
// Mock authentication
cy.intercept(
'POST',
'https://wallet.testnet.vega.xyz/api/v1/auth/token',
{
body: {
token: 'test-token',
},
],
},
}
);
// Mock getting keys from wallet
cy.intercept('GET', 'https://wallet.testnet.vega.xyz/api/v1/keys', {
body: {
keys: [
{
algorithm: {
name: 'algo',
version: 1,
},
index: 0,
meta: [],
pub: 'HOSTED_PUBKEY',
tainted: false,
},
],
},
});
cy.getByTestId(connectVegaBtn).click();
cy.contains(
'Choose wallet app to connect, or to change port or server URL enter a custom wallet location first'
);
cy.contains('Connect Vega wallet');
cy.contains('Hosted Fairground wallet');
cy.getByTestId('connectors-list')
.find('[data-testid="connector-hosted"]')
.click();
cy.getByTestId(form).find('#wallet').click().type('user');
cy.getByTestId(form).find('#passphrase').click().type('pass');
cy.getByTestId('rest-connector-form').find('button[type=submit]').click();
cy.getByTestId(manageVegaBtn).should('exist');
cy.getByTestId('manage-vega-wallet').click();
cy.getByTestId('keypair-list').should('exist');
});
cy.getByTestId(connectVegaBtn).click();
cy.contains(
'Choose wallet app to connect, or to change port or server URL enter a custom wallet location first'
);
cy.contains('Connect Vega wallet');
cy.contains('Hosted Fairground wallet');
cy.getByTestId('connectors-list')
.find('[data-testid="connector-hosted"]')
.click();
cy.getByTestId(form).find('#wallet').click().type('user');
cy.getByTestId(form).find('#passphrase').click().type('pass');
cy.getByTestId('rest-connector-form').find('button[type=submit]').click();
cy.getByTestId(manageVegaBtn).should('exist');
cy.getByTestId('manage-vega-wallet').click();
cy.getByTestId('keypair-list').should('exist');
});
it('doesnt connect with invalid credentials', () => {
// 0002-WCON-020
it('doesnt connect with invalid credentials', () => {
// 0002-WCON-020
// Mock incorrect username/password
cy.intercept('POST', 'https://wallet.testnet.vega.xyz/api/v1/auth/token', {
body: {
error: 'No wallet',
},
statusCode: 403, // 403 forbidden invalid crednetials
// Mock incorrect username/password
cy.intercept(
'POST',
'https://wallet.testnet.vega.xyz/api/v1/auth/token',
{
body: {
error: 'No wallet',
},
statusCode: 403, // 403 forbidden invalid crednetials
}
);
cy.getByTestId(connectVegaBtn).click();
cy.getByTestId('connectors-list')
.find('[data-testid="connector-hosted"]')
.click();
cy.getByTestId(form).find('#wallet').click().type('invalid name');
cy.getByTestId(form).find('#passphrase').click().type('invalid password');
cy.getByTestId('rest-connector-form').find('button[type=submit]').click();
cy.getByTestId('form-error').should('have.text', 'Invalid credentials');
});
cy.getByTestId(connectVegaBtn).click();
cy.getByTestId('connectors-list')
.find('[data-testid="connector-hosted"]')
.click();
cy.getByTestId(form).find('#wallet').click().type('invalid name');
cy.getByTestId(form).find('#passphrase').click().type('invalid password');
cy.getByTestId('rest-connector-form').find('button[type=submit]').click();
cy.getByTestId('form-error').should('have.text', 'Invalid credentials');
});
it('doesnt connect with empty fields', () => {
cy.getByTestId(connectVegaBtn).click();
cy.getByTestId('connectors-list')
.find('[data-testid="connector-hosted"]')
.click();
it('doesnt connect with empty fields', () => {
cy.getByTestId(connectVegaBtn).click();
cy.getByTestId('connectors-list')
.find('[data-testid="connector-hosted"]')
.click();
cy.getByTestId('rest-connector-form').find('button[type=submit]').click();
cy.getByTestId(form)
.find('#wallet')
.next('[data-testid="input-error-text"]')
.should('have.text', 'Required');
cy.getByTestId(form)
.find('#passphrase')
.next('[data-testid="input-error-text"]')
.should('have.text', 'Required');
});
});
cy.getByTestId('rest-connector-form').find('button[type=submit]').click();
cy.getByTestId(form)
.find('#wallet')
.next('[data-testid="input-error-text"]')
.should('have.text', 'Required');
cy.getByTestId(form)
.find('#passphrase')
.next('[data-testid="input-error-text"]')
.should('have.text', 'Required');
});
}
);
describe('connect vega wallet', { tags: '@smoke' }, () => {
describe('connect vega wallet', { tags: '@smoke', testIsolation: true }, () => {
beforeEach(() => {
// Using portfolio page as it requires vega wallet connection
cy.visit('/#/portfolio');
@@ -88,48 +88,54 @@ describe(
}
);
describe('withdraw actions', { tags: '@regression' }, () => {
beforeEach(() => {
cy.mockWeb3Provider();
cy.mockTradingPage();
cy.mockSubscription();
cy.setVegaWallet();
describe(
'withdraw actions',
{ tags: '@regression', testIsolation: true },
() => {
beforeEach(() => {
cy.mockWeb3Provider();
cy.mockTradingPage();
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/portfolio');
cy.getByTestId(collateralTab).click();
cy.getByTestId(openTransferDialog).click();
cy.visit('/#/portfolio');
cy.getByTestId(collateralTab).click();
cy.getByTestId(openTransferDialog).click();
cy.wait('@Accounts');
cy.wait('@Assets');
cy.mockVegaWalletTransaction();
});
cy.wait('@Accounts');
cy.wait('@Assets');
cy.mockVegaWalletTransaction();
});
it('key to key transfers by select key', function () {
cy.getByTestId(transferForm).should('be.visible');
cy.getByTestId(transferForm).find(toAddressField).select(1);
selectAsset(ASSET_SEPOLIA_TBTC);
cy.getByTestId(transferForm).find(amountField).type('1', { delay: 100 });
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(toastContent).should(
'contain.text',
'Awaiting confirmation'
);
cy.getByTestId(toastCloseBtn).click();
});
it('key to key transfers by select key', function () {
cy.getByTestId(transferForm).should('be.visible');
cy.getByTestId(transferForm).find(toAddressField).select(1);
selectAsset(ASSET_SEPOLIA_TBTC);
cy.getByTestId(transferForm).find(amountField).type('1', { delay: 100 });
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(toastContent).should(
'contain.text',
'Awaiting confirmation'
);
cy.getByTestId(toastCloseBtn).click();
});
it('key to key transfers by enter manual key', function () {
cy.getByTestId(transferForm).should('be.visible');
cy.contains('Enter manually').click();
cy.getByTestId(transferForm)
.find(toAddressField)
.type('7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535');
selectAsset(ASSET_SEPOLIA_TBTC);
cy.getByTestId(transferForm).find(amountField).type('1', { delay: 100 });
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(toastContent).should(
'contain.text',
'Awaiting confirmation'
);
cy.getByTestId(toastCloseBtn).click();
});
});
it('key to key transfers by enter manual key', function () {
cy.getByTestId(transferForm).should('be.visible');
cy.contains('Enter manually').click();
cy.getByTestId(transferForm)
.find(toAddressField)
.type(
'7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535'
);
selectAsset(ASSET_SEPOLIA_TBTC);
cy.getByTestId(transferForm).find(amountField).type('1', { delay: 100 });
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(toastContent).should(
'contain.text',
'Awaiting confirmation'
);
cy.getByTestId(toastCloseBtn).click();
});
}
);
+51 -45
View File
@@ -70,54 +70,60 @@ describe('withdraw form validation', { tags: '@smoke' }, () => {
});
});
describe('withdraw actions', { tags: '@regression' }, () => {
// this is extremely ugly hack, but setting it properly in contract is too much effort for such simple validation
describe(
'withdraw actions',
{ tags: '@regression', testIsolation: true },
() => {
// this is extremely ugly hack, but setting it properly in contract is too much effort for such simple validation
// 1002-WITH-018
// 1002-WITH-018
const withdrawalThreshold =
Cypress.env('VEGA_ENV') === 'CUSTOM' ? '0.00' : '100.00';
before(() => {
cy.mockWeb3Provider();
cy.mockTradingPage();
cy.mockSubscription();
cy.setVegaWallet();
const withdrawalThreshold =
Cypress.env('VEGA_ENV') === 'CUSTOM' ? '0.00' : '100.00';
before(() => {
cy.mockWeb3Provider();
cy.mockTradingPage();
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/portfolio');
cy.getByTestId('Withdrawals').click();
cy.getByTestId('withdraw-dialog-button').click();
cy.visit('/#/portfolio');
cy.getByTestId('Withdrawals').click();
connectEthereumWallet('MetaMask');
cy.getByTestId('withdraw-dialog-button').click();
cy.wait('@Accounts');
cy.wait('@Assets');
cy.mockVegaWalletTransaction();
});
// It also requires connection Ethereum wallet
connectEthereumWallet('MetaMask');
it('triggers transaction when submitted', () => {
// 1002-WITH-002
// 1002-WITH-003
selectAsset(ASSET_SEPOLIA_TBTC);
cy.getByTestId('BALANCE_AVAILABLE_label').should(
'contain.text',
'Balance available'
);
cy.getByTestId('BALANCE_AVAILABLE_value').should(
'have.text',
'1,000.00001'
);
cy.getByTestId('WITHDRAWAL_THRESHOLD_label').should(
'contain.text',
'Delayed withdrawal threshold'
);
cy.getByTestId('WITHDRAWAL_THRESHOLD_value').should(
'contain.text',
withdrawalThreshold
);
cy.getByTestId('DELAY_TIME_label').should('contain.text', 'Delay time');
cy.getByTestId('DELAY_TIME_value').should('have.text', 'None');
cy.get(amountField).clear().type('10');
cy.getByTestId(submitWithdrawBtn).click();
cy.getByTestId('toast').should('contain.text', 'Awaiting confirmation');
});
});
cy.wait('@Accounts');
cy.wait('@Assets');
cy.mockVegaWalletTransaction();
});
it('triggers transaction when submitted', () => {
// 1002-WITH-002
// 1002-WITH-003
selectAsset(ASSET_SEPOLIA_TBTC);
cy.getByTestId('BALANCE_AVAILABLE_label').should(
'contain.text',
'Balance available'
);
cy.getByTestId('BALANCE_AVAILABLE_value').should(
'have.text',
'1,000.00001'
);
cy.getByTestId('WITHDRAWAL_THRESHOLD_label').should(
'contain.text',
'Delayed withdrawal threshold'
);
cy.getByTestId('WITHDRAWAL_THRESHOLD_value').should(
'contain.text',
withdrawalThreshold
);
cy.getByTestId('DELAY_TIME_label').should('contain.text', 'Delay time');
cy.getByTestId('DELAY_TIME_value').should('have.text', 'None');
cy.get(amountField).clear().type('10');
cy.getByTestId(submitWithdrawBtn).click();
cy.getByTestId('toast').should('contain.text', 'Awaiting confirmation');
});
}
);
@@ -0,0 +1,18 @@
import * as Schema from '@vegaprotocol/types';
export const orderSizeField = 'order-size';
export const orderPriceField = 'order-price';
export const orderTIFDropDown = 'order-tif';
export const placeOrderBtn = 'place-order';
export const toggleShort = 'order-side-SIDE_SELL';
export const toggleLong = 'order-side-SIDE_BUY';
export const toggleLimit = 'order-type-TYPE_LIMIT';
export const toggleMarket = 'order-type-TYPE_MARKET';
export const TIFlist = Object.values(Schema.OrderTimeInForce).map((value) => {
return {
code: Schema.OrderTimeInForceCode[value],
value,
text: Schema.OrderTimeInForceMapping[value],
};
});
+1
View File
@@ -2,6 +2,7 @@ import '@vegaprotocol/cypress';
import 'cypress-real-events/support';
import registerCypressGrep from '@cypress/grep';
import { addMockTradingPage } from './trading';
import 'cypress-mochawesome-reporter/register';
registerCypressGrep();
addMockTradingPage();
+2 -1
View File
@@ -11,4 +11,5 @@ NX_VEGA_TOKEN_URL=https://token.fairground.wtf
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
+2 -2
View File
@@ -11,7 +11,7 @@ NX_VEGA_URL=http://localhost:3028/query
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
@@ -7,7 +7,6 @@ import {
useThrottledDataProvider,
} from '@vegaprotocol/react-helpers';
import { AsyncRenderer, ExternalLink, Splash } from '@vegaprotocol/ui-toolkit';
import { marketProvider, marketDataProvider } from '@vegaprotocol/market-list';
import { useGlobalStore, usePageTitleStore } from '../../stores';
import { TradeGrid, TradePanels } from './trade-grid';
@@ -1,5 +1,5 @@
import { DealTicketContainer } from '@vegaprotocol/deal-ticket';
import { MarketInfoContainer } from '@vegaprotocol/market-info';
import { MarketInfoAccordionContainer } from '@vegaprotocol/market-info';
import { OrderbookContainer } from '@vegaprotocol/market-depth';
import { OrderListContainer } from '@vegaprotocol/orders';
import { FillsContainer } from '@vegaprotocol/fills';
@@ -12,11 +12,10 @@ import { memo, useState } from 'react';
import type { ReactNode, ComponentProps } from 'react';
import { DepthChartContainer } from '@vegaprotocol/market-depth';
import { CandlesChartContainer } from '@vegaprotocol/candles-chart';
import { OracleBanner } from '../../components/banner';
import {
Tab,
LocalStoragePersistTabs as Tabs,
ResizableGrid,
ResizableGridPanel,
Splash,
} from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
@@ -33,12 +32,16 @@ import {
useMarketClickHandler,
useMarketLiquidityClickHandler,
} from '../../lib/hooks/use-market-click-handler';
import {
ResizableGrid,
ResizableGridPanel,
} from '../../components/resizable-grid';
type MarketDependantView =
| typeof CandlesChartContainer
| typeof DepthChartContainer
| typeof DealTicketContainer
| typeof MarketInfoContainer
| typeof MarketInfoAccordionContainer
| typeof OrderbookContainer
| typeof TradesContainer;
@@ -56,7 +59,7 @@ const TradingViews = {
Depth: requiresMarket(DepthChartContainer),
Liquidity: requiresMarket(LiquidityContainer),
Ticket: requiresMarket(DealTicketContainer),
Info: requiresMarket(MarketInfoContainer),
Info: requiresMarket(MarketInfoAccordionContainer),
Orderbook: requiresMarket(OrderbookContainer),
Trades: requiresMarket(TradesContainer),
Positions: PositionsContainer,
@@ -271,7 +274,10 @@ export const TradeGrid = ({
}: TradeGridProps) => {
return (
<div className="h-full grid grid-rows-[min-content_1fr]">
<TradeMarketHeader market={market} onSelect={onSelect} />
<div>
<TradeMarketHeader market={market} onSelect={onSelect} />
<OracleBanner marketId={market?.id || ''} />
</div>
<MainGrid
marketId={market?.id || ''}
onSelect={onSelect}
@@ -13,8 +13,7 @@ import type { OnCellClickHandler } from '../../components/select-market';
import { Header, HeaderStat } from '../../components/header';
import { NO_MARKET } from './constants';
import { MarketMarkPrice } from '../../components/market-mark-price';
import { Last24hPriceChange } from '../../components/last-24h-price-change';
import { Last24hVolume } from '../../components/last-24h-volume';
import { Last24hPriceChange, Last24hVolume } from '@vegaprotocol/market-info';
import { MarketState } from '../../components/market-state';
import { HeaderStatMarketTradingMode } from '../../components/market-trading-mode';
import { MarketLiquiditySupplied } from '../../components/liquidity-supplied';
@@ -2,18 +2,13 @@ import { titlefy } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { PositionsContainer } from '@vegaprotocol/positions';
import { OrderListContainer } from '@vegaprotocol/orders';
import {
ResizableGridPanel,
Tab,
LocalStoragePersistTabs as Tabs,
} from '@vegaprotocol/ui-toolkit';
import { Tab, LocalStoragePersistTabs as Tabs } from '@vegaprotocol/ui-toolkit';
import { WithdrawalsContainer } from './withdrawals-container';
import { FillsContainer } from '@vegaprotocol/fills';
import type { ReactNode } from 'react';
import { useEffect } from 'react';
import { VegaWalletContainer } from '../../components/vega-wallet-container';
import { DepositsContainer } from './deposits-container';
import { ResizableGrid } from '@vegaprotocol/ui-toolkit';
import { LayoutPriority } from 'allotment';
import { usePageTitleStore } from '../../stores';
import { LedgerContainer } from '@vegaprotocol/ledger';
@@ -23,6 +18,10 @@ import {
useMarketClickHandler,
useMarketLiquidityClickHandler,
} from '../../lib/hooks/use-market-click-handler';
import {
ResizableGrid,
ResizableGridPanel,
} from '../../components/resizable-grid';
export const Portfolio = () => {
const { updateTitle } = usePageTitleStore((store) => ({
@@ -14,10 +14,9 @@ export const Web3Provider = ({ children }: { children: ReactNode }) => {
const { config, loading, error } = useEthereumConfig();
const { ETHEREUM_PROVIDER_URL, ETH_LOCAL_PROVIDER_URL, ETH_WALLET_MNEMONIC } =
useEnvironment();
const [connectors, initializeConnectors] = useWeb3ConnectStore((store) => [
store.connectors,
store.initialize,
]);
const connectors = useWeb3ConnectStore((store) => store.connectors);
const initializeConnectors = useWeb3ConnectStore((store) => store.initialize);
useEffect(() => {
if (config?.chain_id) {

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