Compare commits

...
Author SHA1 Message Date
Matthew Russell 6636509099 chore: move updateAsset.requiredParticipation to percentage formatting 2023-05-08 08:26:58 -07:00
Matthew Russell 40b3caa56b fix: network params fixture lookup for updateAsset proposals 2023-05-08 08:26:58 -07:00
daro-maj d1265a6af7 test(trading): update of capsule and live tests (#3635) 2023-05-08 16:52:33 +02:00
Sam Keen 313eff1c95 feat(governance): proposal details page improvements (#3611) 2023-05-08 12:41:55 +00:00
dexturr 7f949a276c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-08 12:10:52 +00:00
dexturr 76a53dc7e3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-08 06:08:30 +00:00
Matthew Russell 72821dd183 chore(utils,react-helpers,data-provider): remove apollo deps from ui-toolkit (#3626) 2023-05-07 18:01:07 -07:00
dexturr 40d2e033e0 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-08 00:15:27 +00:00
Edd e6d0b6ac1f fix(explorer): number formatting for updateasset proposals (#3630) 2023-05-07 18:17:57 +00:00
dexturr 99161497fe chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-07 18:08:18 +00:00
Edd bf6ab32230 feat(governance): render markdown in proposal view (#3632) 2023-05-07 17:45:19 +01:00
dexturr 28bcb4ada1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-07 12:10:24 +00:00
dexturr 5812c8858d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-07 06:07:03 +00:00
dexturr abf146895d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-07 00:16:07 +00:00
dexturr 4476e6c6d1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-06 18:09:41 +00:00
dexturr d967000e8f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-06 12:09:52 +00:00
dexturr 91d3d97399 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-06 06:07:05 +00:00
dexturr ca700aa103 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-06 00:14:21 +00:00
dexturr 265bf7fb35 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-05 18:08:29 +00:00
Sam Keen 7a5c6f3a25 fix(governance): added toasts for withdrawals (#3621) 2023-05-05 14:10:21 +00:00
dexturr 91e3460e9d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-05 12:10:43 +00:00
Art cf0c45aaa5 fix(trading): asset balance being rendered when disconnected from eth… (#3618) 2023-05-05 13:00:15 +02:00
m.rayandasiaznik bf63f9d46d feat(oracles): oracle full profile (#3545)
Co-authored-by: asiaznik <artur@vegaprotocol.io>
2023-05-05 09:52:03 +00:00
dexturr 023a83e0f7 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-05 06:08:12 +00:00
dexturr 4f6ed1eadf chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-05 00:14:53 +00:00
m.ray 85e293f3ec fix(liquidity): use LP order ID as ag-grid row ID (#3615) 2023-05-04 16:23:33 -07:00
dexturr 7b15d2db10 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-04 18:07:23 +00:00
m.ray b1b9695998 fix(liquidity): rows duplicated wrong ag-grid row ID (#3614) 2023-05-04 17:23:52 +00:00
Edd 6b8b33a78b chore(explorer,trading,governance): remove stagnet3 (#3608) 2023-05-04 16:50:39 +00:00
Mikołaj Młodzikowski 4fd0f6819a feat(ci): deploy develop to stagnet1 (#3609) 2023-05-04 14:29:31 +00:00
Mikołaj Młodzikowski 5032d87f98 feat(ci): define max lenght of a branch (#3607) 2023-05-04 16:06:46 +02:00
Matthew Russell b15d9cb7dc fix(governance,trading): validator testnet link for governance app (#3599) 2023-05-04 15:21:24 +02:00
dexturr 6aa7cc5bab chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-04 12:09:32 +00:00
Bartłomiej Głownia c37f9ebe66 feat(trading): divide order tab into open, closed, rejected and all (#3541) 2023-05-04 12:09:55 +02:00
Art 768b3b29f0 feat(trading): protocol upgrade notification (#3517) 2023-05-04 09:51:24 +02:00
dexturr 378946f22b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-04 06:07:49 +00:00
dexturr 523598645a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-04 00:13:39 +00:00
Art a9267de653 feat(trading): asset balances inside asset selector (deposit, withdraw form) (#3590) 2023-05-03 20:35:05 +01:00
dexturr ce22da1c9a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-03 18:09:05 +00:00
Matthew Russell 2460a62a3e fix(governance): add custom styles for validators table (#3597) 2023-05-03 08:05:55 -07:00
daro-maj f37a8720a2 test(trading): handle unspecified side in fills table - e2e tests (#3594) 2023-05-03 13:16:55 +01:00
dexturr f5fe3cc18d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-03 12:10:31 +00:00
Joe Tsang 288f075cac test(governance): e2e tests updated to cypress 12 (#3582) 2023-05-03 11:23:17 +01:00
Sam Keen ca46861fd8 feat(governance): add local time zone abbreviation data to proposal form (#3577) 2023-05-03 11:23:03 +01:00
m.ray 2cb6ede492 feat(oracles): oracle basic profile (#3544) 2023-05-03 12:07:39 +02:00
Matthew Russell eefcc96149 fix(datagrid): prevent unmount of aggrid on theme change (#3588) 2023-05-03 09:45:14 +01:00
Maciek 7a99ded8e9 feat(trading): market view persistent pane sizes (#3537) 2023-05-03 09:44:45 +01:00
dexturr 4a4cdaa2b8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-03 06:07:16 +00:00
dexturr cd969549ab chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-03 00:13:45 +00:00
Matthew Russell 5a73b7e769 feat(trading): add generic welcome message for non mainnet networks (#3584) 2023-05-02 14:01:33 -07:00
dexturr a4f41eabb6 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-02 18:09:46 +00:00
Matthew Russell 351a20abad feat(trading,market-list): closed markets datagrid (#3429) 2023-05-02 10:41:21 -07:00
Sam Keen 8d42481130 feat(governance): eth chain should not inhibit usage (#3568) 2023-05-02 12:31:16 +00:00
dexturr 8a59722f09 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-02 12:08:21 +00:00
Sam Keen de48ffa563 feat(governance): update market proposal only available for enacted markets (#3542) 2023-05-02 10:10:03 +00:00
daro-maj 00c5252aea test(trading): ac for 6501-ASSE-assets - e2e tests (#3570) 2023-05-02 11:30:08 +02:00
dexturr 9acc083c11 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-02 06:09:38 +00:00
dexturr 77264e80f1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-02 00:15:50 +00:00
dexturr 50378bc8d2 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-01 18:07:37 +00:00
dexturr b88da51c68 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-01 12:08:18 +00:00
dexturr 2ae56bb113 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-01 06:07:17 +00:00
dexturr 752af9a983 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-01 00:17:06 +00:00
dexturr a01df081eb chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-30 18:07:29 +00:00
dexturr c2d14d1abe chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-30 12:10:07 +00:00
dexturr a76ff44ffd chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-30 06:09:37 +00:00
dexturr ac2e262bf3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-30 00:16:34 +00:00
dexturr ab180875b1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-29 18:07:34 +00:00
dexturr 66d3e89b9e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-29 12:09:56 +00:00
dexturr c9cce87606 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-29 06:08:49 +00:00
dexturr 50232ab089 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-29 00:16:25 +00:00
dexturr e86fb6d0b4 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-28 18:08:10 +00:00
Sam Keen 473ef3ae83 feat(governance): default font Alpha (#3543) 2023-04-28 17:08:36 +00:00
Edd 77ab719b37 fix(explorer): fix asset links and deterministic order details (#3567) 2023-04-28 16:00:49 +00:00
Edd a10f67d7ab feat(explorer): add epoch to block explorer homepage (#3536) 2023-04-28 13:08:42 +00:00
dexturr 66d2b83513 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-28 12:09:23 +00:00
dexturr e4fd040933 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-28 06:08:57 +00:00
dexturr 30c1dbd019 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-28 00:14:44 +00:00
daro-majandm.ray 5e558c4cd3 test(trading): 7001-COLL-collateral - e2e tests (#3561)
Co-authored-by: m.ray <16125548+MadalinaRaicu@users.noreply.github.com>
2023-04-27 21:28:25 +02:00
dexturr 85060a0421 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-27 18:10:05 +00:00
Sam Keen b336291b49 fix(governance): use default jsonrpc connector when the provider from useWe… (#3563) 2023-04-27 16:26:00 +00:00
Joe Tsang 0f7bffd38b test(ci): capsule update v0.71.1 (#3559) 2023-04-27 14:37:55 +01:00
dexturr 3665375b75 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-27 12:09:22 +00:00
m.ray 8572c0a570 feat(trading): data grid dropdown menu in collateral table and vega icons (#3472) 2023-04-27 09:21:05 +00:00
Maciek 6a29dc82ef feat(ledger): add link for download ledger entries to .csv (#3454) 2023-04-27 08:53:28 +00:00
Bartłomiej Głownia c19bcc5e0c feat(trading): add oracle banner e2e tests (#3524) 2023-04-27 09:47:18 +01:00
Maciek 6593bbf37b feat(trading): settings page quick adjust a css (#3558) 2023-04-27 07:38:57 +00:00
dexturr 1e5e57b978 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-27 06:10:10 +00:00
dexturr 5394b00349 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-27 00:16:39 +00:00
dexturr 32f5eaade5 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-26 18:07:54 +00:00
Maciek b7a440132d feat(trading): make Sentry only after opt in (#3448) 2023-04-26 15:17:23 +00:00
m.ray d6ecdf80fa fix(fills): handle side_unspecified added for the aggresor (#3550) 2023-04-26 13:34:56 +00:00
dexturr 21e545d941 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-26 12:09:35 +00:00
Sam Keen ef5fa7cba6 feat(governance): ensure the data node urls in the monorepo are valid (#3549) 2023-04-26 11:10:40 +00:00
Mikołaj Młodzikowski d1f465e2af Update Jenkinsfile 2023-04-26 12:54:34 +02:00
Mikołaj MłodzikowskiandMikołaj Młodzikowski 2740df48a3 fix(ci): urls in comments (#3539)
Co-authored-by: Mikołaj Młodzikowski <mikolaj.mlodzikowski@github.com>
2023-04-26 12:45:02 +02:00
Dexter Edwards cf1f10e324 chore(static): remove unusable mainnet data nodes (#3003) 2023-04-26 08:09:50 +01:00
dexturr f09a1abcfa chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-26 06:07:25 +00:00
dexturr 3de83c6eb8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-26 00:15:38 +00:00
dexturr e6545c13af chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-25 18:06:59 +00:00
Sam Keen 613582ee00 fix(governance): validator tables - user staking fixes (#3533) 2023-04-25 14:17:27 +00:00
dexturr 77582a62a8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-25 12:08:28 +00:00
Sam KeenandJoe 384c96376a fix(governance): scroll to top on route change (#3481)
Co-authored-by: Joe <joe@vega.xyz>
2023-04-25 12:31:34 +01:00
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
dexturr d4f5643799 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-19 06:09:43 +00:00
dexturr 72c49e62a8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-19 00:14:26 +00:00
dexturr 0988edc129 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-18 18:07:34 +00:00
botond 4d266963ae feat(governance): paginate rewards (#3391) 2023-04-18 14:40:57 +01:00
Bartłomiej Głownia ec12c7ecfd fix(trading): update cached Order objects (#3450) 2023-04-18 13:56:13 +01:00
m.ray 045dace274 feat(trading): add liquidity provision link to orders table (#3432) 2023-04-18 13:55:11 +01:00
Sam KeenandMatthew Russell 2346b2f1a0 feat(governance): full width Governance and Explorer header (#3453)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-04-18 13:06:30 +01:00
Bartłomiej Głownia 31859cb779 chore(trading): maintain always up to date active orders list (#3430) 2023-04-18 12:49:42 +02:00
dexturr 20507ecdd1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-18 06:08:58 +00:00
dexturr 13ba661ea0 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-18 00:16:31 +00:00
dexturr 03f5b9fc7b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-17 18:07:00 +00:00
dexturr b9fed65615 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-17 12:10:37 +00:00
Mikołaj Młodzikowski d671e51edf fix(ci): adjust timeouts 2023-04-17 12:45:30 +02:00
Mikołaj Młodzikowski 4f3295d3fc feat(ci): rebuild yarn on failed build 2023-04-17 11:24:53 +02:00
dexturr 7be7bab1ca chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-17 06:09:49 +00:00
dexturr 61380f06b9 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-17 00:14:49 +00:00
dexturr c113856d63 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-16 18:07:16 +00:00
dexturr 90884beee8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-16 12:07:18 +00:00
dexturr d9d2e428f4 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-16 06:09:55 +00:00
dexturr ba8d54b761 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-16 00:15:24 +00:00
dexturr dce4edb943 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-15 18:06:56 +00:00
dexturr b468a0fd84 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-15 12:07:02 +00:00
dexturr c98fbe7453 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-15 06:06:58 +00:00
dexturr d20928ec06 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-15 00:15:18 +00:00
dexturr 289559fe4f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-14 18:09:58 +00:00
Mikołaj Młodzikowski 071fd6128c feat: fix releasing dist 2023-04-14 15:45:14 +02:00
Mikołaj Młodzikowski 554d07a31b feat(ci): fix regressions detected after merging to develop (#3442) 2023-04-14 15:00:20 +02:00
dexturr 48b62380b0 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-14 12:10:09 +00:00
Mikołaj Młodzikowski a9f4604bad feat(governance,trading,explorer): pipelines improvements (#3422) 2023-04-14 11:47:41 +02:00
Sam Keen 54f2519a62 feat(governance): toggles design review tweaks (#3431) 2023-04-14 09:22:22 +01:00
dexturr 260e7bf9cf chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-14 06:09:41 +00:00
dexturr 83db796cdb chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-14 00:14:08 +00:00
m.ray 2f6800212e fix(trading): fix order toast intent on amendments (#3433) 2023-04-13 13:20:28 -07:00
dexturr 77e16ad1b7 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-13 18:09:10 +00:00
dexturr dcce983842 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-13 12:10:33 +00:00
Maciek 53ce9bfaa2 chore(assets): make query for asset list lighter (#3425) 2023-04-13 11:42:09 +00:00
Edd 6ae34d296f fix(explorer): tweak footer to show more detail on smaller screens (#3418) 2023-04-13 10:49:42 +01:00
Joe Tsang ee2aafb99c fix(governance): failing nightly tests (#3351) 2023-04-13 10:46:01 +01:00
dexturr e8fdb63323 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-13 06:09:41 +00:00
dexturr 3df9270b57 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-13 00:13:51 +00:00
dexturr ab26667265 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-12 18:08:22 +00:00
m.ray 9fc6b255c8 fix(orders): update order toast intent and title (#3424) 2023-04-12 15:19:15 +00:00
dexturr 91f61d8bb5 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-12 12:09:32 +00:00
Bartłomiej Głowniaandm.ray bbfda65bcc feat(withdraws): improve ux surrounding withdraw balances thresholds and delays (#3402)
Co-authored-by: m.ray <16125548+MadalinaRaicu@users.noreply.github.com>
2023-04-12 11:21:24 +02:00
Mikołaj Młodzikowski 45f2e926c3 feat(governance,trading,explorer): split steps by logic (#3387) 2023-04-12 09:38:26 +02:00
dexturr ccadbc2cb6 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-12 06:08:40 +00:00
dexturr 7128acb7b8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-12 00:14:18 +00:00
dexturr 357bdaa4f3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-11 18:07:51 +00:00
Maciek f3fe43724e fix(deposits): deposit dialog doesn't respect given assetId (#3414) 2023-04-11 16:41:20 +02:00
m.ray 03f5ca3096 fix(trading): fix formatting on clicking on orderbook cell after decimal resolution update (#3409) 2023-04-11 12:23:43 +00:00
dexturr 03d19349af chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-11 12:08:24 +00:00
daro-maj 1f53b2cbb5 test(trading): increase coverage for the remaining ACs (#3412) 2023-04-11 11:59:21 +02:00
Maciek b010c98346 fix(trading): welcome dialog with markets list click on market close window (#3404) 2023-04-11 11:34:44 +02:00
Matthew Russell 29d57af2ba fix(trading): make light theme sell volume bar match candle color (#3405) 2023-04-11 09:06:35 +02:00
Bartłomiej Głownia fd7940c4cf chore(deal-ticket): remove not used code (#3406) 2023-04-11 08:13:41 +02:00
dexturr 8ab7ac8414 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-11 06:07:03 +00:00
dexturr ce7cd03c3e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-11 00:15:30 +00:00
Matthew Russell dfa3355a68 chore(trading): prevent node poll if query fails (#3411) 2023-04-10 14:48:03 -07:00
dexturr 8553904d81 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-10 18:07:16 +00:00
dexturr 10afa3c1d4 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-10 12:10:31 +00:00
Maciek ecd362615e chore(deposits): impove UX on deposit dialog (#3401) 2023-04-10 12:59:02 +01:00
dexturr 0d9bd67465 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-10 06:07:18 +00:00
dexturr b5aa92f007 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-10 00:14:34 +00:00
dexturr 2955790be1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-09 18:09:21 +00:00
dexturr 89ff9309e9 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-09 12:08:56 +00:00
dexturr e1df3489f6 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-09 06:09:36 +00:00
dexturr f0fa9ca5e1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-09 00:17:04 +00:00
dexturr 9d92477c2a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-08 18:08:30 +00:00
dexturr b1a198be85 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-08 12:09:49 +00:00
dexturr 5fb385d43c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-08 06:07:03 +00:00
dexturr 8014b279fe chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-08 00:14:19 +00:00
dexturr f4bde57294 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-07 18:09:32 +00:00
John Walley 2e5ff07824 chore(candles-chart): upgrade pennant to v1.8.1 (#3399) 2023-04-07 10:35:10 -07:00
Bartłomiej Głownia 7accb42793 fix(market-depth): make market data up to date, use fixed number of decimals in cumulative vol (#3361) 2023-04-07 10:34:51 -07:00
Matthew Russell 9229e7f686 chore(trading): update approval amount to be max uint256 (#3395) 2023-04-07 10:33:53 -07:00
daro-maj b570b9c4c1 test(trading): tests for post and reduce functionality (#3400) 2023-04-07 13:03:15 -04:00
m.ray ed78261aad fix(trading): order tx toasts title and intent should be set by status (#3368) 2023-04-07 13:01:12 -04:00
m.ray 363ca9c6e1 fix(trading): add liquidity provision docs (#3403) 2023-04-07 13:00:57 -04:00
m.ray bafd3c384c feat(trading): include fees in transfer amount (#3345) 2023-04-07 13:00:11 -04:00
dexturr 3b830abe07 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-07 12:09:01 +00:00
dexturr 1787e22b69 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-07 06:07:23 +00:00
dexturr f105133959 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-07 00:14:21 +00:00
dexturr aff0e46d23 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-06 18:08:45 +00:00
Maciek 7e4aafcb77 chore(trading): add filters to the proposals table (#3375) 2023-04-06 15:30:21 +02:00
dexturr 643d5408cd chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-06 12:08:03 +00:00
m.ray 2a2af3ba9c fix(trading): fix docs resources (#3382) 2023-04-06 12:53:08 +01:00
Sam Keen 8d4e4a1228 fix(governance): fix incorrect validator penalties (#3381) 2023-04-06 13:31:21 +02:00
dexturr 84068c8081 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-06 06:09:30 +00:00
dexturr e1185b9a96 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-06 00:13:22 +00:00
dexturr f390448c24 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-05 18:09:37 +00:00
Maciek 70943c523c chore(deposits): persistence of deposit form state (#3348) 2023-04-05 14:53:55 +02:00
dexturr dcb79e70d3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-05 12:10:10 +00:00
dexturr cc72cdbe16 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-05 06:08:13 +00:00
dexturr 3fd1817e1e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-05 00:15:53 +00:00
Matthew Russell b483c13f81 chore(trading): fix bad grammar on approval notification (#3354) 2023-04-04 15:14:36 -07:00
Matthew Russell bde7a9fbf9 fix(smart-contracts): add increased gas limit estimation (#3371) 2023-04-04 11:41:11 -07:00
dexturr 5fd93ee9c8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-04 18:09:38 +00:00
botond 9ac07fd98a fix: add missing announcement config url (#3367) 2023-04-04 15:11:48 +00:00
dexturr 9c975ed822 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-04 12:10:23 +00:00
Edd 138bf7da00 build(explorer): update validator testnet be url (#3357) 2023-04-04 10:53:47 +00:00
dexturr 3e7fe517f3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-04 06:07:34 +00:00
dexturr 4f960d09b3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-04 00:15:07 +00:00
Bartłomiej Głownia 351a5aaf96 chore(trading): remove not used close position code and liquidity subscription (#3350) 2023-04-03 14:58:06 -07:00
Bartłomiej Głownia 381d9011a0 fix(orders): restore filter by marketId (#3342) 2023-04-03 14:20:31 -07:00
Matthew Russell 861760b4f9 chore(governance): add hardcoded token vesting contract address (#3352) 2023-04-03 21:17:32 +00:00
Matthew Russell 18f1c0014c chore(governance,explorer,multisig-signer): delete rest of sandbox/mirror env files (#3310) 2023-04-03 14:07:43 -07:00
m.ray 474543d91b fix(trading): order stopped intent toasts (#3347) 2023-04-03 19:21:56 +00:00
dexturr 662753c74b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-03 18:09:46 +00:00
daro-majandm.ray 71aa8882bc test(trading): renders correctly liquidity in trading tab (#3343)
Co-authored-by: m.ray <16125548+MadalinaRaicu@users.noreply.github.com>
2023-04-03 14:33:10 +00:00
Mikołaj Młodzikowski ecfbccf8ed feat(trading,governance,explorer): dist on s3 (#3332) 2023-04-03 15:53:50 +02:00
Bartłomiej Głownia 2aad6b1a14 feat(deal-ticket): show total margin available for an order, and where it will come from (#3318) 2023-04-03 15:17:23 +02:00
Bartłomiej Głownia 8463d371ad chore(trading): liquidity table DRY (#3346) 2023-04-03 15:02:43 +02:00
dexturr 0914e7ce4b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-03 12:08:48 +00:00
Maciek 7c82144f37 chore(trading): add metaKey detection - clean up some unit tests (#3337) 2023-04-03 10:20:20 +02:00
Joe Tsang 17ad0cc975 test(governance): add e2e tests for banner and footer links (#3340) 2023-04-03 09:16:42 +01:00
dexturr eb58dcd350 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-03 06:09:59 +00:00
dexturr c8c0bf2cc0 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-03 00:16:15 +00:00
dexturr 00579fcb1f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-02 18:06:45 +00:00
dexturr 5e13173efb chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-02 12:09:35 +00:00
dexturr 3a6c0554cc chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-02 06:06:55 +00:00
dexturr d4b237a6ba chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-02 00:17:15 +00:00
dexturr 5e765f3172 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-01 18:07:57 +00:00
dexturr 5ef8c11e6e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-01 12:07:28 +00:00
dexturr 84bae12def chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-01 06:06:47 +00:00
dexturr c5b22f5bfb chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-01 00:14:47 +00:00
dexturr 071dcc61a8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-31 18:09:16 +00:00
m.ray ce0ccdfebc feat(trading): add post only and reduce only orders (#3311) 2023-03-31 17:00:55 +01:00
Art f1524d3fcd feat(utils): make release script (#3290) 2023-03-31 17:01:19 +02:00
MaciekandMatthew Russell 82e5128ba1 chore(trading): add "holding CMD + click" external link (#3273)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-03-31 15:23:44 +02:00
Maciek 2bfc3abd15 chore(trading): liquidity provision, change query for set flag live on true (#3335) 2023-03-31 14:20:44 +01:00
dexturr bd3b557f3d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-31 12:10:35 +00:00
MaciekandBartłomiej Głownia c899da52c2 fix(trading): stabilize the liquidity provision table (#3320)
Co-authored-by: Bartłomiej Głownia <bglownia@gmail.com>
2023-03-31 11:41:16 +01:00
Matthew Russell b9c4057ce5 feat(oracles,trading): 3224 add oracle links to market info (#3297) 2023-03-31 09:06:21 +01:00
dexturr d02feee5c6 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-31 06:07:09 +00:00
dexturr 6d1ab36a72 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-31 00:14:21 +00:00
dexturr 5690fe91a8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-30 18:09:18 +00:00
Joe Tsang 1daae6a233 chore(governance): additional acs added for governance proposals (#3322) 2023-03-30 17:18:41 +01:00
dexturr cd35a34246 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-30 12:10:13 +00:00
Bartłomiej Głownia 77ada964b5 feat(market-depth): always show the same number of decimal places in order book (#3317) 2023-03-30 10:54:13 +01:00
dexturr d7404bcd76 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-30 06:07:12 +00:00
dexturr 91862701a7 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-30 00:14:12 +00:00
dexturr 0136efd78f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-29 18:14:47 +00:00
daro-maj c3a4954d0d test(trading): update live e2e tests (#3307) 2023-03-29 15:26:12 +02:00
botondandMikołaj Młodzikowski 528fd96721 feat(announcements): announcements (#3252)
Co-authored-by: Mikołaj Młodzikowski <mikolaj.mlodzikowski@gmail.com>
2023-03-29 15:20:49 +02:00
dexturr 155923ff8e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-29 12:07:49 +00:00
Matthew Russellandmaciek 5f7e60d22f chore(orders): update orders filters (#3277)
Co-authored-by: maciek <maciek@vegaprotocol.io>
2023-03-29 13:12:29 +02:00
Joe Tsang 351583ce8f chore(cypress): fix error seen in CI for staking test (#3304) 2023-03-29 11:52:46 +01:00
Maciek 88bf58b974 chore(trading): remove files of envs to kill (#3303) 2023-03-29 10:57:33 +01:00
Maciek fcda4d7fcd chore(wallet,positions): use reduceOnly and IOC order for close position tx (#3263) 2023-03-28 23:50:11 -07:00
dexturr b1b0039b33 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-29 06:08:40 +00:00
Art 6854980b32 fix(trading): volumes formatting (#3293) 2023-03-28 22:12:52 -07:00
dexturr d8aac83f2d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-29 00:18:30 +00:00
Sam Keen 5c17045752 fix(governance): paginate rewards as well as delegations data (#3288) 2023-03-28 20:35:29 +01:00
Bartłomiej Głownia 8863209342 feat(trading): persist state of chart intervals studies and overlays (#3261) 2023-03-28 21:03:53 +02:00
Joe Tsang 462bf6b8b5 test(governance): my stake e2e tests (#3295) 2023-03-28 19:03:58 +01:00
Ciaran McGhie e0b701e05a chore(react-helpers): react-helpers v0.1.0 (#3289) 2023-03-28 16:13:34 +01:00
Sam KeenandJoe eca212eee0 feat(governance): see user stake on validators table (#3250)
Co-authored-by: Joe <joe@vega.xyz>
2023-03-28 15:28:15 +01:00
Sam Keen c25858037a fix(governance): order proposals list by closing date (#3276) 2023-03-28 14:04:24 +01:00
Ciaran McGhie 081f5b48e2 chore(ui-toolkit): version 0.9.0 - includes healthbar in ui-toolkit (#3287) 2023-03-28 13:36:29 +01:00
dexturr e306d1c9fa chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-28 12:08:16 +00:00
dexturr 737dec4f5f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-28 06:08:37 +00:00
dexturr 6780b2f618 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-28 00:15:54 +00:00
Penny Andrews 08dc60086d chore(ci): update name of release issue template (#3279) 2023-03-27 11:47:35 -07:00
Bartłomiej Głownia 4595db07b0 fix(trading): throttle deal ticket submit (#3282) 2023-03-27 11:46:40 -07:00
dexturr c3da31146f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-27 18:08:26 +00:00
dexturr b6a9faaa7c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-27 12:10:42 +00:00
daro-maj 477d523582 test(trading): fixed capsule tests (#3281) 2023-03-27 12:50:22 +02:00
Maciek a2b112d898 fix(positions): make positions table smoothly updated (again) (#3266) 2023-03-27 12:30:55 +02:00
Mikołaj Młodzikowski 621ba497e8 feat: remove env vars file after setting up js file 2023-03-27 11:03:06 +02:00
dexturr a6964bc3cf chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-27 06:06:57 +00:00
dexturr 48a9998441 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-27 00:16:27 +00:00
dexturr bd1bd94ee7 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-26 18:07:12 +00:00
dexturr 2fdebbd694 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-26 12:10:22 +00:00
dexturr 96af8035d0 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-26 06:07:03 +00:00
dexturr 051e3da366 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-26 00:17:44 +00:00
dexturr af5e666d5e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-25 18:09:35 +00:00
dexturr 333a7d6206 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-25 12:10:21 +00:00
dexturr cb6b988466 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-25 06:09:33 +00:00
dexturr 806ea74f7e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-25 00:14:18 +00:00
Matthew Russell 8693f3bfd8 chore(trading): dont show faucet button until connected (#3251) 2023-03-24 17:06:22 -07:00
Bartłomiej Głownia 58c6652e29 feat(trading): use mini scroll in deal ticket, market info for and landing dialog (#3269) 2023-03-24 17:01:12 -07:00
Bartłomiej Głownia e8adff25c4 fix(trading): handle lack of approval in trading deposit flow (#3278) 2023-03-24 16:57:00 -07:00
Penny Andrews 3e594a783a chore(ci): add release issue template (#3272) 2023-03-24 16:55:22 -07:00
dexturr 1f7117075b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-24 18:09:07 +00:00
Bartłomiej Głownia 4c850ecead fix(trading): change etherscan link label on toast (#3262) 2023-03-24 17:57:59 +01:00
Mikołaj Młodzikowski 19f8fa909e feat(explorer,trading,governance): use nx to know which apps needs building (#3267) 2023-03-24 16:42:33 +01:00
Sam Keen 8214858685 feat(governance): lp vote now reflected on proposal cards (#3256) 2023-03-24 14:56:56 +00:00
dexturr 868f8e21dc chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-24 12:08:16 +00:00
dexturr 6ead84b57c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-24 06:09:30 +00:00
dexturr 3975477985 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-24 00:14:29 +00:00
Art 8a0c15ac11 feat(explorer): breadcrumbs (#3254) 2023-03-23 19:11:34 +00:00
dexturr a4f512f946 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-23 18:08:43 +00:00
dexturr 88f3c278f8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-23 12:08:36 +00:00
Mikołaj Młodzikowski 34d5f3fd13 feat(explorer): build docker image on pull request + refactor dockerfile for ipfs (#3245) 2023-03-23 10:50:23 +01:00
daro-maj a060f94146 test(trading): 0003-WTXN submit vega transaction e2e tests (#3246) 2023-03-23 09:46:28 +01:00
MaciekandMatthew Russell f649d78565 chore(orders): remove infinite scroll from order table (#3247)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-03-23 09:13:07 +01:00
dexturr b611d30b31 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-23 06:08:50 +00:00
dexturr 545324ccd6 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-23 00:16:17 +00:00
Bartłomiej Głownia 8c16759621 fix(trading): use unique keys in LocalStoragePersistTabs (#3255) 2023-03-22 16:34:58 -07:00
Matthew Russell e724aac2f1 feat(trading): add resources dropdown to console nav (#3249) 2023-03-22 16:33:29 -07:00
dexturr e3a6b75130 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-22 18:09:03 +00:00
Joe Tsang 8d8f6b4928 test(governance): governance tests refactor (#3059) 2023-03-22 17:35:00 +00:00
m.ray 6c1c5bf2a9 feat(trading): pin collateral row (#3218) 2023-03-22 13:05:05 +01:00
Ciaran McGhie 74a3aa8566 refactor(ui-toolkit): move healthbar to ui-toolkit (#3121) 2023-03-22 11:33:46 +00:00
dexturr 4cbd7a4928 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-22 06:09:20 +00:00
dexturr 201cf07a01 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-22 00:13:57 +00:00
Dexter EdwardsandMatthew Russell 90ceeebf15 fix(ui-toolkit): anchor button should be same size as button by default (#3172)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-03-21 15:24:34 -07:00
dexturr 965f7f6e2d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-21 18:08:39 +00:00
Ciaran McGhie 18633efec3 chore(ui-toolkit): rework intent colours (#3202) 2023-03-21 16:40:39 +00:00
a0b758334a fix(trading): auction triggers liquidity API change in develop for core 0.69.0 (#3197)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
2023-03-21 09:19:21 -07:00
Bartłomiej Głownia 9f3026aa4b fix(market-depth): fix depth chart data upate, use market depth as mid price source (#3242) 2023-03-21 08:46:04 -07:00
Maciek faa359e2fb chore(trading): 2764 link to mainnet incident reports (#3235) 2023-03-21 08:19:54 -07:00
Bartłomiej Głownia 1d178b940f feat(trading): store current tab selection (#3148) 2023-03-21 15:50:31 +01:00
dexturr b2dd053621 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-21 12:10:18 +00:00
dexturr 77f5193b7a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-21 06:07:47 +00:00
dexturr 055a0070db chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-21 00:13:48 +00:00
dexturr 29b221c86a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-20 18:09:57 +00:00
Dexter Edwards 3e619acd4b feat(ui-toolkit): button icons (#3233) 2023-03-20 14:40:04 +00:00
botond c720719ac5 chore(governance): update announcement banner text (#3234) 2023-03-20 13:52:03 +00:00
Art c676a7c1e2 chore(explorer): move banner up (#3237) 2023-03-20 13:38:31 +00:00
dexturr ca63a671c8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-20 12:09:43 +00:00
Maciek 4165f3905f chore(static): update domains in network conf files (#3219) 2023-03-20 09:58:05 +00:00
dexturr a359ccb755 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-20 06:07:41 +00:00
dexturr e584737005 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-20 00:17:40 +00:00
dexturr b12c5ed39f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-19 18:08:07 +00:00
dexturr d3dbd64cf1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-19 12:07:36 +00:00
dexturr 2df62bca61 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-19 06:07:48 +00:00
dexturr fd2a434b46 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-19 00:17:10 +00:00
dexturr 4e7a78f988 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-18 18:08:23 +00:00
dexturr 327619652a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-18 12:07:24 +00:00
dexturr d2339205cc chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-18 06:06:50 +00:00
dexturr 63df4cf465 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-18 00:13:54 +00:00
dexturr 5e34178291 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-17 18:06:54 +00:00
dexturr 0c44664aa5 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-17 12:07:53 +00:00
Bartłomiej Głownia 7ef1d75529 chore(trading): remove red background from trades table (#3214) 2023-03-17 09:52:40 +00:00
Maciek 84795b2d6a chore(trading): split bottom panel into two parts (#3205) 2023-03-17 09:50:43 +00:00
dexturr 300019f108 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-17 06:09:09 +00:00
dexturr 2d0aebd3fe chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-17 00:14:43 +00:00
dexturr 9e86d2aff5 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-16 18:09:41 +00:00
daro-maj 0f7e76ae01 test(trading): increase coverage for 0004-ewal (#3210) 2023-03-16 13:29:40 +01:00
dexturr 56732d1503 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-16 12:08:59 +00:00
Joe Tsang 5c19263653 chore(governance): include slippage factor to proposals (#3204) 2023-03-16 10:41:18 +00:00
dexturr 0d911b3029 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-16 06:08:43 +00:00
Matthew RussellandEdd 9f059e7862 chore(explorer,governance): update be endpoints (#3183)
Co-authored-by: Edd <edd@vega.xyz>
2023-03-15 20:12:04 -07:00
dexturr 92ea93dadb chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-16 00:16:50 +00:00
daro-maj 6165aefad7 test(trading): fixed settlement asset displayed test (#3209) 2023-03-15 18:38:57 +00:00
dexturr c95369d914 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-15 18:08:52 +00:00
Maciek 5dbc5d7997 chore(trading): make loading masks in tabs consistent along the app (#3155) 2023-03-15 16:08:48 +01:00
dexturr 47b3d5b55f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-15 12:07:50 +00:00
Maciek da7c0b84f7 chore(trading): display latency in block height progressing as warn or error (#3169) 2023-03-15 12:49:31 +01:00
Art 67e602ebb1 feat(explorer): try again for tx details (#3195) 2023-03-15 08:24:42 +00:00
Art f407110e95 chore(environment): etherscan link (#3193) 2023-03-15 08:24:20 +00:00
Art 66a85cce2a chore(explorer): market info shared panels (#3192) 2023-03-15 08:21:12 +00:00
Art 93f8450ecb fix(utils): missing flags (#3194) 2023-03-15 08:20:41 +00:00
dexturr 0447a6cf5d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-15 06:09:39 +00:00
dexturr 498be838c7 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-15 00:17:07 +00:00
945 changed files with 76119 additions and 17543 deletions
+4
View File
@@ -3,3 +3,7 @@ apps/**/node_modules/*
tmp/*
.dockerignore
dockerfiles
node_modules
.git
.github
.vscode
+21
View File
@@ -0,0 +1,21 @@
---
name: Release
about: A template to outline the steps needed to for a successful release of our frontend apps
title: 'Release [add dapp version]-core-[add core version]'
labels:
assignees: ''
---
### Tasks
- [ ] Review [link to core release](xxx)
- [ ] Tag frontend-monorepo
- [ ] Create release and generate release notes
- [ ] Run `@smoke` tests
- [ ] Run `@regression` tests
- [ ] Run `@slow` tests
- [ ] Explorative testing of key flows
- [ ] Set `release/[network]` to tagged commit
- [ ] Verify builds (on Netlify and Fleek) are successful
- [ ] Verify build has been deployed
- [ ] Smoke testing on deployed app
+1 -1
View File
@@ -13,7 +13,7 @@ env:
jobs:
add_issue:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: 'Add issue to project board'
run: |
+16
View File
@@ -0,0 +1,16 @@
name: 'Check if branch is shorter than 52 chars'
on: pull_request
jobs:
branch-naming-rules:
runs-on: ubuntu-latest
steps:
# echo "branches that are longer than 51 chars can't be parsed by kubernetes to create previews. Each app has prefix of it's name like: 'governance-' (12 chars), what leaves 51 max branch length"
# current parsable length: $( git rev-parse --abbrev-ref HEAD | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | wc -c)
- uses: deepakputhraya/action-branch-name@master
with:
# regex: '([a-z])+\/([a-z])+' # Regex the branch should match. This example enforces grouping
# allowed_prefixes: 'feature,stable,fix' # All branches should start with the given prefix
# ignore: master,develop # Ignore exactly matching branch names from convention
min_length: 1 # Min length of the branch name
max_length: 51 # Max length of the branch name
+211
View File
@@ -0,0 +1,211 @@
name: CI/CD
on:
push:
branches:
- release/*
- develop
pull_request:
types:
- opened
- ready_for_review
- reopened
- edited
- synchronize
jobs:
node-modules:
runs-on: ubuntu-22.04
name: 'Cache yarn modules'
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cache node modules
id: cache
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
# comment out "restore-keys" if you need to rebuild yarn from 0
restore-keys: |
${{ runner.os }}-cache-node-modules-
- name: Setup node
uses: actions/setup-node@v3
if: steps.cache.outputs.cache-hit != 'true'
with:
node-version-file: '.nvmrc'
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
cache: yarn
- name: yarn install
if: steps.cache.outputs.cache-hit != 'true'
run: yarn install --pure-lockfile
lint-pr-title:
needs: node-modules
if: ${{ github.event_name == 'pull_request' }}
name: Verify PR title
uses: ./.github/workflows/lint-pr.yml
secrets: inherit
lint-test-build:
timeout-minutes: 60
needs: node-modules
runs-on: ubuntu-22.04
name: '(CI) lint + unit test + build'
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup node
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
cache: yarn
- name: Cache node modules
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v3
with:
main-branch-name: develop
- name: Check formatting
run: yarn nx format:check
- name: Lint affected
run: yarn nx affected:lint --max-warnings=0
- name: Build affected spec
run: yarn nx affected --target=build-spec
- name: Test affected
run: yarn nx affected:test
- name: Build affected
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
# See affected apps
- name: See affected apps
run: |
echo ">>>> debug"
echo "NX Version: $nx_version"
echo "NX_BASE: ${{ env.NX_BASE }}"
echo "NX_HEAD: ${{ env.NX_HEAD }}"
echo ">>>> eof debug"
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)"
echo -n "Affected projects: $affected"
branch_slug="$(echo ${{ github.head_ref || github.ref_name }} | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
projects_e2e=""
preview_governance="not deployed"
preview_trading="not deployed"
preview_explorer="not deployed"
if [[ -z "$projects_e2e" ]]; then
projects_e2e+='"governance-e2e" "trading-e2e" "explorer-e2e" '
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
else
if [[ $affected == *"governance"* ]]; then
projects_e2e+='"governance-e2e" '
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
fi
if [[ $affected == *"trading"* ]]; then
projects_e2e+='"trading-e2e" '
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
fi
if [[ $affected == *"explorer"* ]]; then
projects_e2e+='"explorer-e2e" '
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
fi
fi
projects_e2e=${projects_e2e%?}
projects_e2e=[${projects_e2e// /,}]
echo PROJECTS_E2E=$projects_e2e >> $GITHUB_ENV
echo PROJECTS=$(echo $projects_e2e | sed 's|-e2e||g') >> $GITHUB_ENV
echo PREVIEW_GOVERNANCE=$preview_governance >> $GITHUB_ENV
echo PREVIEW_TRADING=$preview_trading >> $GITHUB_ENV
echo PREVIEW_EXPLORER=$preview_explorer >> $GITHUB_ENV
outputs:
projects: ${{ env.PROJECTS }}
projects-e2e: ${{ env.PROJECTS_E2E }}
preview_governance: ${{ env.PREVIEW_GOVERNANCE }}
preview_trading: ${{ env.PREVIEW_TRADING }}
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
cypress:
needs: lint-test-build
name: '(CI) cypress'
if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
uses: ./.github/workflows/cypress-run.yml
secrets: inherit
with:
projects: ${{ needs.lint-test-build.outputs.projects-e2e }}
tags: '@smoke @regression'
publish-dist:
needs: lint-test-build
name: '(CD) publish dist'
if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
uses: ./.github/workflows/publish-dist.yml
secrets: inherit
with:
projects: ${{ needs.lint-test-build.outputs.projects }}
dist-check:
runs-on: ubuntu-latest
needs:
- publish-dist
- lint-test-build
if: ${{ github.event_name == 'pull_request' }}
name: '(CD) comment preview links'
steps:
- name: Find Comment
uses: peter-evans/find-comment@v2
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
body-includes: Previews
- name: Create comment
uses: peter-evans/create-or-update-comment@v3
if: ${{ steps.fc.outputs.comment-id == 0 }}
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
Previews:
* governance: ${{ needs.lint-test-build.outputs.preview_governance }}
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
* trading: ${{ needs.lint-test-build.outputs.preview_trading }}
cypress-check:
name: '(CI) cypress - check'
runs-on: ubuntu-latest
needs: cypress
steps:
- run: echo Done!
# Report single result at the end, to avoid mess with required checks in PR
cypress-result:
if: ${{ always() }}
needs: cypress
runs-on: ubuntu-22.04
steps:
- run: |
result="${{ needs.cypress.result }}"
if [[ $result == "success" || $result == "skipped" ]]; then
exit 0
else
exit 1
fi
+1 -1
View File
@@ -13,7 +13,7 @@ on:
jobs:
cypress-run:
name: Run Cypress Trading tests -- live environment
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v2
-78
View File
@@ -1,78 +0,0 @@
name: Cypress tests - PR
on:
push:
branches:
- develop
- main
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review
jobs:
pr:
runs-on: ubuntu-latest
steps:
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup node
uses: actions/setup-node@v3
- name: Remove package.json & yarn.lock to avoid installing everything
run: rm package.json yarn.lock
- name: Install nx
run: yarn add nx
# Check SHAs
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v2
with:
main-branch-name: ${{ github.base_ref || github.ref_name }}
set-environment-variables-for-job: true
# See affected apps
- name: See affected apps
run: |
affected=$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)
echo -n "Affected projects: $affected"
projects=""
if [[ $affected == *"governance"* ]]; then projects+='"governance-e2e" '; fi
if [[ $affected == *"trading"* ]]; then projects+='"trading-e2e" '; fi
if [[ $affected == *"explorer"* ]]; then projects+='"explorer-e2e" '; fi
if [[ -z "$projects" ]]; then projects+='"governance-e2e" "trading-e2e" "explorer-e2e" '; fi
projects=${projects%?}
projects=[${projects// /,}]
echo PROJECTS=$projects >> $GITHUB_ENV
outputs:
projects: ${{ env.PROJECTS }}
run:
needs: pr
if: ${{ needs.pr.outputs.projects != '[]' }}
uses: ./.github/workflows/cypress-run.yml
secrets: inherit
with:
projects: ${{ needs.pr.outputs.projects }}
tags: '@smoke @regression'
# Report single result at the end, to avoid mess with required checks in PR
result:
if: ${{ always() }}
needs: run
runs-on: ubuntu-latest
name: Cypress result
steps:
- run: |
result="${{ needs.run.result }}"
if [[ $result == "success" || $result == "skipped" ]]; then
exit 0
else
exit 1
fi
+9 -1
View File
@@ -1,3 +1,4 @@
name: (CI) Cypress Run
on:
workflow_call:
inputs:
@@ -17,8 +18,9 @@ jobs:
fail-fast: false
matrix:
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
@@ -91,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
+12 -9
View File
@@ -8,22 +8,25 @@ on:
jobs:
master:
name: Generate Queries
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
fetch-depth: 0
- name: Use Node.js 16
id: Node
uses: actions/setup-node@v2
with:
node-version: 16.15.1
node-version-file: '.nvmrc'
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
cache: yarn
- name: Install root dependencies
run: yarn install
run: yarn install --frozen-lockfile
- name: Generate queries
run: node ./scripts/get-queries.js
- uses: actions/upload-artifact@v2
with:
name: queries
+29
View File
@@ -0,0 +1,29 @@
---
name: Verify PR title
on:
workflow_call:
jobs:
lint_pr:
timeout-minutes: 10
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
cache: yarn
- name: Cache node modules
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
- name: Check PR title
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
-23
View File
@@ -1,23 +0,0 @@
---
name: Verify PR title
on:
pull_request:
types: [opened, ready_for_review, reopened, edited, synchronize]
jobs:
lint_pr:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Use Node.js 16
id: Node
uses: actions/setup-node@v2
with:
node-version: 16.15.1
- name: Install root dependencies
run: yarn install
- name: Check PR title
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
+1 -1
View File
@@ -7,7 +7,7 @@ on:
jobs:
master:
name: Generate Queries
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Checkout
+171
View File
@@ -0,0 +1,171 @@
name: (CD) Publish docker + s3
on:
workflow_call:
inputs:
projects:
required: true
type: string
jobs:
publish-dist:
strategy:
fail-fast: false
matrix:
app: ${{ fromJSON(inputs.projects) }}
name: ${{ matrix.app }}
runs-on: ubuntu-22.04
timeout-minutes: 25
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Set up QEMU
id: quemu
uses: docker/setup-qemu-action@v2
- name: Available platforms
run: echo ${{ steps.qemu.outputs.platforms }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Setup node
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
cache: yarn
- name: Cache node modules
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
# https://docs.github.com/en/actions/learn-github-actions/contexts
- name: Define variables
run: |
envName=''
dockerfile="dist.Dockerfile"
if [[ "${{ github.event_name }}" = "push" ]]; then
domain="vega.rocks"
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
if [[ "${{ github.ref }}" =~ .*mainnet.* ]]; then
domain="vega.community"
if [[ "${{ matrix.app }}" = "trading" ]]; then
dockerfile="ipfs.Dockerfile"
fi
fi
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
envName="stagnet1"
fi
bucketName="${{ matrix.app }}.${envName}.${domain}"
echo BUCKET_NAME=${bucketName} >> $GITHUB_ENV
fi
nodeVersion=$(cat .nvmrc | head -n 1)
echo ENV_NAME=${envName} >> $GITHUB_ENV
echo NODE_VERSION=${nodeVersion} >> $GITHUB_ENV
echo DOCKERFILE=docker/${dockerfile} >> $GITHUB_ENV
- name: Build local dist
if: ${{ env.DOCKERFILE != 'docker/ipfs.Dockerfile' }}
run: |
flags=""
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
if [[ "${{ env.ENV_NAME }}" != "ops-vega" ]]; then
flags="--env=${{ env.ENV_NAME }}"
fi
fi
if [ "${{ matrix.app }}" = "trading" ]; then
yarn nx export trading $flags || (yarn install && yarn nx export trading $flags)
DIST_LOCATION=dist/apps/trading/exported
else
yarn nx build ${{ matrix.app }} $flags || (yarn install && yarn nx build ${{ matrix.app }} $flags)
DIST_LOCATION=dist/apps/${{ matrix.app }}
fi
mv $DIST_LOCATION dist-result
tree dist-result
- name: Build and export to local Docker
id: docker_build
if: ${{ github.event_name == 'pull_request' || ( env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' ) }}
uses: docker/build-push-action@v3
with:
context: .
file: ${{ env.DOCKERFILE }}
load: true
build-args: |
APP=${{ matrix.app }}
NODE_VERSION=${{ env.NODE_VERSION }}
ENV_NAME=${{ env.ENV_NAME }}
tags: |
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
- name: Image digest
if: ${{ github.event_name == 'pull_request' || ( env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' ) }}
run: echo ${{ steps.docker_build.outputs.digest }}
- name: Sanity check docker image
if: ${{ github.event_name == 'pull_request' || ( env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' ) }}
run: |
echo "Check ipfs-hash"
if [[ "${{ env.DOCKERFILE }}" = "docker/ipfs.Dockerfile" ]]; then
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash
fi
echo "List html directory"
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local sh -c 'apk add --update tree; tree .'
- name: Copy dist to local filesystem
if: ${{ env.DOCKERFILE == 'docker/ipfs.Dockerfile' && github.event_name == 'push' }}
run: |
docker create --name=dist ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
docker cp dist:/usr/share/nginx/html dist
echo "check local dist files"
tree dist/html
mv dist/html dist-result
- name: Publish dist as docker image
uses: docker/build-push-action@v3
if: ${{ github.event_name == 'pull_request' }}
with:
context: .
file: ${{ env.DOCKERFILE }}
push: true
build-args: |
APP=${{ matrix.app }}
NODE_VERSION=${{ env.NODE_VERSION }}
ENV_NAME=${{ env.ENV_NAME }}
tags: |
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ github.event.pull_request.head.sha || github.sha }}
# bucket creation in github.com/vegaprotocol/terraform//frontend
- name: Publish dist to s3
uses: jakejarvis/s3-sync-action@master
if: ${{ github.event_name == 'push' }}
with:
args: --acl private --follow-symlinks --delete
env:
AWS_S3_BUCKET: ${{ env.BUCKET_NAME }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: 'eu-west-1'
SOURCE_DIR: 'dist-result'
- name: Add preview label
uses: actions-ecosystem/action-add-labels@v1
if: ${{ github.event_name == 'pull_request' }}
with:
labels: ${{ matrix.app }}-preview
number: ${{ github.event.number }}
@@ -1,126 +0,0 @@
name: Publish docker containers
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-*'
workflow_dispatch:
inputs:
publish:
description: 'Publish tag to Docker Hub & GitHub Registry'
required: false
type: boolean
default: false
tag:
description: 'Git Tag to build and publish'
required: false
type: string
default: ''
apps:
description: 'Applications to build and publish'
required: false
type: choice
options:
- '["explorer", "token", "trading"]'
- '["explorer"]'
- '["token"]'
- '["trading"]'
archs:
description: 'Architecture to build and publish'
required: false
type: choice
options:
- linux/amd64, linux/arm64
- linux/amd64
- linux/arm64
jobs:
master:
strategy:
fail-fast: false
matrix:
app: ${{ fromJson(inputs.apps || '["explorer", "token", "trading"]') }}
name: Build the ${{ matrix.app }} image
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
with:
ref: ${{ inputs.tag }}
- name: Set up QEMU
id: quemu
uses: docker/setup-qemu-action@v2
- name: Available platforms
run: echo ${{ steps.qemu.outputs.platforms }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
if: ${{ inputs.publish || startsWith(github.ref, 'refs/tags/') }}
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Determine Docker Image tag
id: tags
run: |
hash=$(git rev-parse HEAD|cut -b1-8)
versionTag=${{ inputs.tag || startsWith(github.ref, 'refs/tags/') && github.ref_name || '${hash}' }}
echo ::set-output name=version::${versionTag}
echo ::set-output name=npmVersion::$(cat dockerfiles/${{ matrix.app =='trading' && 'Dockerfile.next' || 'Dockerfile.cra' }} | grep FROM | head -n 1 | awk '{print $2}' | cut -d ':' -f 2 | cut -d '-' -f 1 )
- name: Print config
run: |
git rev-parse --verify HEAD
git status
echo "inputs.tag=${{ inputs.tag }}"
echo "inputs.publish=${{ inputs.publish }}"
echo "inputs.apps=${{ inputs.apps }}"
echo "inputs.archs=${{ inputs.archs }}"
echo "steps.tags.outputs.version=${{ steps.tags.outputs.version }}"
- uses: actions/setup-node@v3
with:
node-version: ${{ steps.tags.outputs.npmVersion }}
- name: Build frontend dists
run: |
yarn --verbose --pure-lockfile
yarn nx ${{ matrix.app =='trading' && 'export' || 'build' }} ${{ matrix.app }} --pure-lockfile
- name: Build and export to local Docker
uses: docker/build-push-action@v3
with:
context: .
push: false
file: dockerfiles/${{ matrix.app =='trading' && 'Dockerfile.next' || 'Dockerfile.cra' }}.dist
build-args: APP=${{ matrix.app }}
load: true
tags: vegaprotocol/${{ matrix.app }}:local
- name: Sanity check docker image
run: |
docker run --rm vegaprotocol/${{ matrix.app }}:local cat .env
docker run --rm vegaprotocol/${{ matrix.app }}:local ls -lah
- name: Build and push to DockerHub
id: docker_build
uses: docker/build-push-action@v3
with:
context: .
push: ${{ inputs.publish || startsWith(github.ref, 'refs/tags/') }}
file: dockerfiles/${{ matrix.app =='trading' && 'Dockerfile.next' || 'Dockerfile.cra' }}.dist
build-args: APP=${{ matrix.app }}
platforms: ${{ inputs.archs || 'linux/amd64, linux/arm64' }}
tags: |
vegaprotocol/${{ matrix.app }}:latest
vegaprotocol/${{ matrix.app }}:${{ steps.tags.outputs.version }}
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
+10 -11
View File
@@ -8,6 +8,7 @@ on:
required: true
type: choice
options:
- announcements
- ui-toolkit
- react-helpers
- tailwindcss-config
@@ -18,29 +19,27 @@ on:
jobs:
publish:
name: Build & Publish - Tag
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
permissions:
contents: 'read'
actions: 'read'
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: User Node.js 16
id: Node
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 16.15.1
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: '**/node_modules'
key: node_modules-${{ hashFiles('**/yarn.lock') }}
node-version-file: '.nvmrc'
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
cache: yarn
- name: Install root dependencies
run: yarn install --frozen-lockfile
- name: Build project
run: yarn nx build ${{inputs.project}}
- name: Publish project to @vegaprotocol
uses: JS-DevTools/npm-publish@v1
with:
-46
View File
@@ -1,46 +0,0 @@
name: Unit tests & build
on:
push:
branches:
- develop
- main
pull_request:
jobs:
pr:
name: Test and lint - PR
runs-on: ubuntu-latest
permissions:
contents: 'read'
actions: 'read'
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v2
with:
main-branch-name: ${{ github.base_ref }}
- name: Use Node.js 16
id: Node
uses: actions/setup-node@v3
with:
node-version: 16.15.1
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: '**/node_modules'
key: node_modules-${{ hashFiles('**/yarn.lock') }}
- name: Install root dependencies
run: yarn install --frozen-lockfile
- name: Check formatting
run: yarn nx format:check
- name: Lint affected
run: yarn nx affected:lint --max-warnings=0
- name: Test affected
run: yarn nx affected:test
- name: Build affected
run: yarn nx affected:build
- name: Build affected spec
run: yarn nx affected --target=build-spec
+3
View File
@@ -46,3 +46,6 @@ cypress.env.json
# Next.js
.next
#cypress
/apps/trading-e2e/cypress/reports/
-1
View File
@@ -7,5 +7,4 @@ __generated___
apps/static/src/assets/devnet-tranches.json
apps/static/src/assets/mainnet-tranches.json
apps/static/src/assets/stagnet3-tranches.json
apps/static/src/assets/testnet-tranches.json
Vendored
+1 -19
View File
@@ -1,20 +1,2 @@
@Library('vega-shared-library') _
def commitHash = 'UNKNOWN'
pipeline {
agent any
options {
skipDefaultCheckout true
parallelsAlwaysFailFast()
}
stages {
stage('approbation') {
steps {
sh 'printenv'
checkout scm
runApprobation ignoreFailure: false, frontendBranch: env.BRANCH_NAME, type: 'frontend'
}
}
}
}
runApprobation ignoreFailure: false, frontendBranch: env.BRANCH_NAME, type: 'frontend'
+1 -1
View File
@@ -72,7 +72,7 @@ Run `nx serve my-app` for a dev server. Navigate to the port specified in `app/<
In order to generate the schemas for your GraphQL queries, you can run `GRAPHQL_SCHEMA_PATH=[YOUR SCHEMA FILE / API URL HERE] nx run types:generate`.
```bash
export GRAPHQL_SCHEMA_PATH=https://api.n11.testnet.vega.xyz/graphql
export GRAPHQL_SCHEMA_PATH=https://api.n07.testnet.vega.xyz/graphql
yarn nx run types:generate
```
+2 -2
View File
@@ -1,7 +1,7 @@
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
NX_TENDERMINT_URL=http://localhost:26617
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
NX_VEGA_URL=http://localhost:3028/query
NX_VEGA_URL=http://localhost:3008/graphql
NX_VEGA_ENV=CUSTOM
NX_VEGA_CONFIG_URL=
@@ -18,4 +18,4 @@ NX_EXPLORER_PARTIES=1
NX_EXPLORER_VALIDATORS=1
CYPRESS_VEGA_WALLET_API_TOKEN=
CYPRESS_VEGA_URL=http://localhost:3028/query
CYPRESS_VEGA_URL=http://localhost:3008/graphql
-18
View File
@@ -1,18 +0,0 @@
# App configuration variables
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n00.stagnet3.vega.xyz/websocket
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
NX_VEGA_ENV=STAGNET3
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
# App flags
NX_EXPLORER_ASSETS=1
NX_EXPLORER_GENESIS=1
NX_EXPLORER_GOVERNANCE=1
NX_EXPLORER_MARKETS=1
NX_EXPLORER_ORACLES=1
NX_EXPLORER_TXS_LIST=0
NX_EXPLORER_NETWORK_PARAMETERS=1
NX_EXPLORER_PARTIES=1
NX_EXPLORER_VALIDATORS=1
+1 -1
View File
@@ -2,7 +2,7 @@
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz/tm
NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket
NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
NX_VEGA_ENV=TESTNET
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
+2 -1
View File
@@ -21,10 +21,11 @@ module.exports = defineConfig({
chromeWebSecurity: false,
viewportWidth: 1440,
viewportHeight: 900,
testIsolation: false,
},
env: {
environment: 'CUSTOM',
networkQueryUrl: 'http://localhost:3028/query',
networkQueryUrl: 'http://localhost:3008/graphql',
ethUrl: 'https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
commitHash: 'dev',
tsConfig: 'tsconfig.json',
@@ -10,6 +10,8 @@
"governance.proposal.updateMarket.minVoterBalance",
"governance.proposal.updateNetParam.minProposerBalance",
"governance.proposal.updateNetParam.minVoterBalance",
"governance.proposal.updateAsset.minProposerBalance",
"governance.proposal.updateAsset.minVoterBalance",
"reward.staking.delegation.maxPayoutPerEpoch",
"reward.staking.delegation.maxPayoutPerParticipant",
"reward.staking.delegation.minimumValidatorStake",
@@ -19,9 +21,6 @@
"validators.delegation.minAmount"
],
"fiveDecimal": [
"governance.proposal.updateAsset.minProposerBalance",
"governance.proposal.updateAsset.minVoterBalance",
"governance.proposal.updateAsset.requiredParticipation",
"market.fee.factors.infrastructureFee",
"market.fee.factors.makerFee",
"market.liquidity.bondPenaltyParameter",
@@ -77,6 +76,7 @@
"governance.proposal.updateNetParam.requiredMajority",
"governance.proposal.updateNetParam.requiredParticipation",
"governance.proposal.updateMarket.minProposerEquityLikeShare",
"governance.proposal.updateAsset.requiredParticipation",
"validators.vote.required"
],
"duration": [
+19 -126
View File
@@ -6,75 +6,39 @@ context('Home Page', function () {
describe('Stats page', { tags: '@smoke' }, function () {
const statsValue = '[data-testid="stats-value"]';
it('Should show connected environment', function () {
const deployedEnv = Cypress.env('environment').toUpperCase();
cy.get('[data-testid="stats-environment"]').should(
'have.text',
`/ ${deployedEnv}`
);
});
it('should show connected environment stats', function () {
const statTitles = {
0: 'Status',
1: 'Height',
2: 'Uptime',
3: 'Total nodes',
4: 'Total staked',
5: 'Backlog',
6: 'Trades / second',
7: 'Orders / block',
8: 'Orders / second',
9: 'Transactions / block',
10: 'Block time',
11: 'Time',
12: 'App',
13: 'Tendermint',
14: 'Up since',
15: 'Chain ID',
1: 'Epoch',
2: 'Block height',
3: 'Uptime',
4: 'Total nodes',
5: 'Total staked',
6: 'Backlog',
7: 'Trades / second',
8: 'Orders / block',
9: 'Orders / second',
10: 'Transactions / block',
11: 'Block time',
12: 'Time',
13: 'App',
14: 'Tendermint',
15: 'Up since',
16: 'Chain ID',
};
cy.get('[data-testid="stats-title"]')
.each(($list, index) => {
cy.wrap($list).should('have.text', statTitles[index]);
cy.wrap($list).should('contain.text', statTitles[index]);
})
.then(($list) => {
cy.wrap($list).should('have.length', 16);
cy.wrap($list).should('have.length', 17);
});
cy.get(statsValue).eq(0).should('have.text', 'CONNECTED');
cy.get(statsValue).eq(1).should('not.be.empty');
cy.get(statsValue)
.eq(2)
.invoke('text')
.should('match', /\d+d \d+h \d+m \d+s/i);
cy.get(statsValue).eq(3).should('have.text', '2');
cy.get(statsValue)
.eq(4)
.invoke('text')
.should('match', /\d+\.\d\d(?!\d)/i);
cy.get(statsValue).eq(5).should('have.text', '0');
cy.get(statsValue).eq(6).should('have.text', '0');
cy.get(statsValue).eq(7).should('have.text', '0');
cy.get(statsValue).eq(8).should('have.text', '0');
cy.get(statsValue).eq(9).should('not.be.empty');
cy.get(statsValue).eq(10).should('not.be.empty');
cy.get(statsValue).eq(11).should('not.be.empty');
cy.get(statsValue)
.eq(12)
.invoke('text')
.should('match', /v\d+\.\d+\.\d+/i);
cy.get(statsValue)
.eq(13)
.invoke('text')
.should('match', /\d+\.\d+\.\d+/i);
cy.get(statsValue).eq(14).should('not.be.empty');
cy.get(statsValue).eq(15).should('not.be.empty');
});
it('Block height should be updating', function () {
cy.get(statsValue)
.eq(1)
.eq(2)
.invoke('text')
.then((blockHeightTxt) => {
cy.get(statsValue)
@@ -86,75 +50,4 @@ context('Home Page', function () {
});
});
});
describe('Git info', function () {
it('git info is rendered on the footer of the page', function () {
cy.getByTestId('git-info').within(() => {
cy.getByTestId('git-network-data').within(() => {
cy.contains('Reading network data from').should('be.visible');
cy.get('span').should('have.text', Cypress.env('networkQueryUrl'));
cy.getByTestId('link').should('be.visible');
});
cy.getByTestId('git-eth-data').within(() => {
cy.contains('Reading Ethereum data from').should('be.visible');
cy.get('span').should('have.text', Cypress.env('ethUrl'));
});
cy.getByTestId('git-commit-hash').within(() => {
cy.contains('Version/commit hash:').should('be.visible');
cy.getByTestId('link').should('have.text', Cypress.env('commitHash'));
});
});
});
});
describe('Search bar', function () {
it('Successful search for specific id by block id', function () {
const blockId = '973624';
search(blockId);
cy.url().should('include', blockId);
});
it('Successful search for specific id by tx hash', function () {
const txHash =
'9ED3718AA8308E7E08EC588EE7AADAF49711D2138860D8914B4D81A2054D9FB8';
search(txHash);
cy.url().should('include', txHash);
});
it('Successful search for specific id by tx id', function () {
const txId =
'0x61DCCEBB955087F50D0B85382DAE138EDA9631BF1A4F92E563D528904AA38898';
search(txId);
cy.url().should('include', txId);
});
it('Error message displayed when invalid search by wrong string length', function () {
search('9ED3718AA8308E7E08EC588EE7AADAF497D2138860D8914B4D81A2054D9FB8');
validateSearchError("Something doesn't look right");
});
it('Error message displayed when invalid search by invalid hash', function () {
search(
'9ED3718AA8308E7E08ECht8EE753DAF49711D2138860D8914B4D81A2054D9FB8'
);
validateSearchError('Transaction is not hexadecimal');
});
it('Error message displayed when searching empty field', function () {
cy.get('[data-testid="search"]').clear();
cy.get('[data-testid="search-button"]').click();
validateSearchError('Search required');
});
function search(searchTxt) {
cy.get('[data-testid="search"]').clear().type(searchTxt);
cy.get('[data-testid="search-button"]').click();
}
function validateSearchError(expectedError) {
cy.get('[data-testid="search-error"]').should('have.text', expectedError);
}
});
});
@@ -138,7 +138,7 @@ context('Network parameters page', { tags: '@smoke' }, function () {
});
});
it('should list each network parameter displayed as a currency value with four decimals - in the correct format', function () {
it.skip('should list each network parameter displayed as a currency value with four decimals - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
@@ -6,7 +6,7 @@ const customNodeBtn = 'custom-node';
context.skip('Node switcher', { tags: '@regression' }, function () {
beforeEach('visit home page', function () {
cy.intercept('GET', 'https://static.vega.xyz/assets/capsule-network.json', {
hosts: ['http://localhost:3028/query'],
hosts: ['http://localhost:3008/graphql'],
}).as('nodeData');
cy.visit('/');
cy.wait('@nodeData');
@@ -219,7 +219,7 @@ context.skip('Parties page', { tags: '@regression' }, function () {
balance type asset {id symbol decimals}}}}}}}}';
cy.request({
method: 'POST',
url: `http://localhost:3028/query`,
url: `http://localhost:3008/graphql`,
body: {
query: mutation,
},
+13 -8
View File
@@ -1,13 +1,18 @@
NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n00.stagnet3.vega.xyz/websocket
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
NX_VEGA_NETWORKS='{"SANDBOX":"https://sandbox.explorer.vega.xyz","STAGNET1":"https://stagnet1.token.vega.xyz", "STAGNET3":"https://stagnet3.explorer.vega.xyz","VALIDATOR_TESTNET":"https://validator-testnet.fairground.wtf","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_ENV=STAGNET3
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
NX_VEGA_ENV=STAGNET1
NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
NX_VEGA_TOKEN_URL=https://stagnet1.token.vega.xyz
NX_VEGA_WALLET_URL=http://localhost:1789
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.xyz/rest
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
NX_VEGA_GOVERNANCE_URL=https://stagnet1.token.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.jsoo
# App flags
NX_EXPLORER_ASSETS=1
+1 -8
View File
@@ -3,14 +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/test/announcements.json
# App flags
NX_EXPLORER_ASSETS=1
NX_EXPLORER_GENESIS=1
NX_EXPLORER_GOVERNANCE=1
NX_EXPLORER_MARKETS=1
NX_EXPLORER_ORACLES=1
NX_EXPLORER_TXS_LIST=0
NX_EXPLORER_NETWORK_PARAMETERS=1
NX_EXPLORER_PARTIES=1
NX_EXPLORER_VALIDATORS=1
+1
View File
@@ -8,3 +8,4 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://dev.token.vega.xyz
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
+1
View File
@@ -6,3 +6,4 @@ NX_VEGA_ENV=MAINNET
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest/
NX_ETHERSCAN_URL=https://etherscan.io
NX_VEGA_GOVERNANCE_URL=https://token.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
-19
View File
@@ -1,19 +0,0 @@
# App configuration variables
NX_TENDERMINT_URL=https://tm.be.mainnet-mirror.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.xyz/websocket
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
NX_VEGA_ENV=MIRROR
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.xyz/rest/
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://mainnet-mirror.token.vega.xyz
# App flags
NX_EXPLORER_ASSETS=1
NX_EXPLORER_GENESIS=1
NX_EXPLORER_GOVERNANCE=1
NX_EXPLORER_NETWORK_PARAMETERS=1
NX_EXPLORER_PARTIES=1
NX_EXPLORER_VALIDATORS=1
NX_EXPLORER_MARKETS=0
NX_EXPLORER_ORACLES=0
NX_EXPLORER_TXS_LIST=1
-11
View File
@@ -1,11 +0,0 @@
# App configuration variables
NX_VEGA_ENV=SANDBOX
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/sandbox/vegawallet-sandbox.toml
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_TENDERMINT_URL=https://tm.sandbox.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.sandbox.vega.xyz/websocket
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://sandbox.token.vega.xyz
+1 -13
View File
@@ -1,13 +1 @@
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
NX_VEGA_ENV=STAGNET1
NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
NX_VEGA_TOKEN_URL=https://stagnet1.token.vega.xyz
NX_VEGA_WALLET_URL=http://localhost:1789
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.xyz/rest
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://stagnet1.token.vega.xyz
# .env is stagnet1, so there are no overrides required
-7
View File
@@ -1,7 +0,0 @@
NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.stagnet3.vega.xyz/websocket
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml
NX_VEGA_ENV=STAGNET3
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
NX_VEGA_GOVERNANCE_URL=https://stagnet3.token.vega.xyz
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases/
+1
View File
@@ -8,3 +8,4 @@ NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://token.fairground.wtf
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
+4 -3
View File
@@ -2,11 +2,12 @@
NX_VEGA_ENV=VALIDATOR_TESTNET
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.toml
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
NX_VEGA_REST=https://api.validators-testnet.vega.xyz/
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_GOVERNANCE_URL=https://validator-testnet.governance.vega.xyz
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.xyz
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.xyz/rest
NX_TENDERMINT_URL=https://tm-be.validators-testnet.vega.rocks
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
+1
View File
@@ -4,3 +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/test/announcements.json
+1 -2
View File
@@ -35,12 +35,11 @@ Example configurations are provided here:
- [Devnet](./.env.devnet)
- [Capsule](./.env.capsule)
- [Testnet](./.env.testnet)
- [Stagnet3](./.env.stagnet3)
For convenience, you can boot the app injecting one of the configurations above by running:
```bash
yarn nx run explorer:serve --env={env} # e.g. stagnet3
yarn nx run explorer:serve --env={env} # e.g. stagnet1
```
There are a few different configuration options offered for this app:
+9 -75
View File
@@ -1,87 +1,21 @@
import { NetworkLoader, useInitializeEnv } from '@vegaprotocol/environment';
import { Header } from './components/header';
import { Main } from './components/main';
import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider';
import { Footer } from './components/footer/footer';
import {
AnnouncementBanner,
ExternalLink,
Icon,
} from '@vegaprotocol/ui-toolkit';
import {
AssetDetailsDialog,
useAssetDetailsDialogStore,
} from '@vegaprotocol/assets';
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
import classNames from 'classnames';
import { useState } from 'react';
import { RouterProvider } from 'react-router-dom';
import { router } from './routes/router-config';
const DialogsContainer = () => {
const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore();
return (
<AssetDetailsDialog
assetId={id}
trigger={trigger || null}
asJson={asJson}
open={isOpen}
onChange={setOpen}
/>
);
};
const MainnetSimAd = () => {
const [shouldDisplayBanner, setShouldDisplayBanner] = useState<boolean>(true);
// Return an empty div so that the grid layout in _app.page.ts
// renders correctly
if (!shouldDisplayBanner) {
return <div />;
}
return (
<AnnouncementBanner>
<div className="grid grid-cols-[auto_1fr] gap-4 font-alpha calt uppercase text-center text-lg text-white">
<button
className="flex items-center"
onClick={() => setShouldDisplayBanner(false)}
>
<Icon name="cross" className="w-6 h-6" ariaLabel="dismiss" />
</button>
<div>
<span className="pr-4">Mainnet sim 3 is live!</span>
<ExternalLink href="https://fairground.wtf/">Learn more</ExternalLink>
</div>
</div>
</AnnouncementBanner>
);
};
const splashLoading = (
<Splash>
<Loader />
</Splash>
);
function App() {
return (
<TendermintWebsocketProvider>
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
<div
className={classNames(
'max-w-[1500px] min-h-[100vh]',
'mx-auto my-0',
'grid grid-rows-[auto_1fr_auto] grid-cols-1',
'border-vega-light-200 dark:border-vega-dark-200 lg:border-l lg:border-r',
'antialiased text-black dark:text-white',
'overflow-hidden relative'
)}
>
<div>
<Header />
<MainnetSimAd />
</div>
<div>
<Main />
</div>
<div>
<Footer />
</div>
</div>
<DialogsContainer />
<RouterProvider router={router} fallbackElement={splashLoading} />
</NetworkLoader>
</TendermintWebsocketProvider>
);
@@ -4,7 +4,7 @@ import { t } from '@vegaprotocol/i18n';
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react';
import { AgGridColumn } from 'ag-grid-react';
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
import { useRef, useLayoutEffect } from 'react';
import { BREAKPOINT_MD } from '../../config/breakpoints';
@@ -10,7 +10,7 @@ export const Footer = () => {
const [nodeSwitcherOpen, setNodeSwitcherOpen] = useState(false);
const { screenSize } = useScreenDimensions();
const showFullFeedbackLabel = useMemo(
() => ['lg', 'xl'].includes(screenSize),
() => ['md', 'lg', 'xl', 'xxl', 'xxxl'].includes(screenSize),
[screenSize]
);
@@ -13,7 +13,7 @@ jest.mock('../search', () => ({
}));
const renderComponent = () => (
<MemoryRouter>
<MemoryRouter initialEntries={['/txs']}>
<Header />
</MemoryRouter>
);
@@ -24,6 +24,7 @@ describe('Header', () => {
expect(screen.getByTestId('navigation')).toHaveTextContent('Explorer');
});
it('should render search', () => {
render(renderComponent());
@@ -1,4 +1,4 @@
import { matchPath, useLocation } from 'react-router-dom';
import { matchPath, useLocation, useMatch } from 'react-router-dom';
import {
ThemeSwitcher,
Navigation,
@@ -13,23 +13,26 @@ import { t } from '@vegaprotocol/i18n';
import { Routes } from '../../routes/route-names';
import { NetworkSwitcher } from '@vegaprotocol/environment';
import type { Navigable } from '../../routes/router-config';
import routerConfig from '../../routes/router-config';
import { isNavigable } from '../../routes/router-config';
import { routerConfig } from '../../routes/router-config';
import { useMemo } from 'react';
import compact from 'lodash/compact';
import { Search } from '../search';
const routeToNavigationItem = (r: Navigable) => (
<NavigationItem key={r.name}>
<NavigationLink to={r.path}>{r.text}</NavigationLink>
<NavigationItem key={r.handle.name}>
<NavigationLink to={r.path}>{r.handle.text}</NavigationLink>
</NavigationItem>
);
export const Header = () => {
const isHome = Boolean(useMatch(Routes.HOME));
const pages = routerConfig[0].children || [];
const mainItems = compact(
[Routes.TX, Routes.BLOCKS, Routes.ORACLES, Routes.VALIDATORS].map((n) =>
routerConfig.find((r) => r.path === n)
pages.find((r) => r.path === n)
)
);
).filter(isNavigable);
const groupedItems = compact(
[
@@ -39,8 +42,8 @@ export const Header = () => {
Routes.GOVERNANCE,
Routes.NETWORK_PARAMETERS,
Routes.GENESIS,
].map((n) => routerConfig.find((r) => r.path === n))
);
].map((n) => pages.find((r) => r.path === n))
).filter(isNavigable);
const { pathname } = useLocation();
@@ -67,7 +70,7 @@ export const Header = () => {
actions={
<>
<ThemeSwitcher />
<Search />
{!isHome && <Search />}
</>
}
onResize={(width, el) => {
@@ -90,7 +93,7 @@ export const Header = () => {
hide={[NavigationBreakpoint.Small, NavigationBreakpoint.Narrow]}
>
{mainItems.map(routeToNavigationItem)}
{groupedItems && (
{groupedItems && groupedItems.length > 0 && (
<NavigationItem>
<NavigationTrigger isActive={Boolean(isOnOther)}>
{t('Other')}
@@ -43,7 +43,7 @@ export const AssetLink = ({
if (asDialog) {
open(assetId, e.target as HTMLElement);
} else {
navigate(`${Routes.ASSETS}/${asset?.id}`);
navigate(`/${Routes.ASSETS}/${asset?.id}`);
}
}}
{...props}
@@ -1,9 +0,0 @@
import { AppRouter } from '../../routes';
export const Main = () => {
return (
<main className="p-4">
<AppRouter />
</main>
);
};
@@ -1,143 +1,113 @@
import {
addDecimalsFormatNumber,
formatNumberPercentage,
getMarketExpiryDateFormatted,
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import type { MarketInfoWithData } from '@vegaprotocol/market-info';
import { MarketInfoTable } from '@vegaprotocol/market-info';
import { LiquidityInfoPanel } from '@vegaprotocol/market-info';
import { LiquidityMonitoringParametersInfoPanel } from '@vegaprotocol/market-info';
import {
MarketStateMapping,
MarketTradingModeMapping,
} from '@vegaprotocol/types';
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
import { Splash } from '@vegaprotocol/ui-toolkit';
import BigNumber from 'bignumber.js';
import { useMemo } from 'react';
import { Link } from 'react-router-dom';
InstrumentInfoPanel,
KeyDetailsInfoPanel,
LiquidityPriceRangeInfoPanel,
MetadataInfoPanel,
OracleInfoPanel,
RiskFactorsInfoPanel,
RiskModelInfoPanel,
RiskParametersInfoPanel,
SettlementAssetInfoPanel,
} from '@vegaprotocol/market-info';
import { MarketInfoTable } from '@vegaprotocol/market-info';
import type { DataSourceDefinition } from '@vegaprotocol/types';
import isEqual from 'lodash/isEqual';
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
const quoteUnit = market?.tradableInstrument.instrument.product.quoteName;
const assetId = useMemo(
() => market?.tradableInstrument.instrument.product?.settlementAsset.id,
[market]
);
const { data: asset } = useAssetDataProvider(assetId ?? '');
if (!market) return null;
const keyDetails = {
decimalPlaces: market.decimalPlaces,
positionDecimalPlaces: market.positionDecimalPlaces,
tradingMode: market.tradingMode,
state: MarketStateMapping[market.state],
};
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
const settlementData =
market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData
.data;
const terminationData =
market.tradableInstrument.instrument.product
.dataSourceSpecForTradingTermination.data;
const liquidityPriceRange = formatNumberPercentage(
new BigNumber(market.lpPriceRange).times(100)
);
const getSigners = (data: DataSourceDefinition) => {
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
const signers = data.sourceType.sourceType.signers || [];
return signers.map(({ signer }, i) => {
return (
(signer.__typename === 'ETHAddress' && signer.address) ||
(signer.__typename === 'PubKey' && signer.key)
);
});
}
return [];
};
const oraclePanels = isEqual(
getSigners(settlementData),
getSigners(terminationData)
)
? [
{
title: t('Settlement Oracle'),
content: (
<OracleInfoPanel
noBorder={false}
market={market}
type="settlementData"
/>
),
},
{
title: t('Termination Oracle'),
content: (
<OracleInfoPanel
noBorder={false}
market={market}
type="termination"
/>
),
},
]
: [
{
title: t('Oracle'),
content: (
<OracleInfoPanel
noBorder={false}
market={market}
type="settlementData"
/>
),
},
];
const panels = [
{
title: t('Key details'),
content: (
<MarketInfoTable
noBorder={false}
data={{
name: market.tradableInstrument.instrument.name,
marketID: market.id,
tradingMode:
keyDetails.tradingMode &&
MarketTradingModeMapping[keyDetails.tradingMode],
marketDecimalPlaces: market.decimalPlaces,
positionDecimalPlaces: market.positionDecimalPlaces,
settlementAssetDecimalPlaces: assetDecimals,
}}
/>
),
content: <KeyDetailsInfoPanel noBorder={false} market={market} />,
},
{
title: t('Instrument'),
content: (
<MarketInfoTable
noBorder={false}
data={{
marketName: market.tradableInstrument.instrument.name,
code: market.tradableInstrument.instrument.code,
productType:
market.tradableInstrument.instrument.product.__typename,
...market.tradableInstrument.instrument.product,
}}
/>
),
content: <InstrumentInfoPanel noBorder={false} market={market} />,
},
{
title: t('Settlement asset'),
content: asset ? (
<AssetDetailsTable
asset={asset}
inline={true}
noBorder={false}
dtClassName="text-black dark:text-white text-ui !px-0 !font-normal"
ddClassName="text-black dark:text-white text-ui !px-0 !font-normal max-w-full"
/>
) : (
<Splash>{t('No data')}</Splash>
),
content: <SettlementAssetInfoPanel market={market} noBorder={false} />,
},
{
title: t('Metadata'),
content: (
<MarketInfoTable
noBorder={false}
data={{
expiryDate: getMarketExpiryDateFormatted(
market.tradableInstrument.instrument.metadata.tags
),
...market.tradableInstrument.instrument.metadata.tags
?.map((tag) => {
const [key, value] = tag.split(':');
return { [key]: value };
})
.reduce((acc, curr) => ({ ...acc, ...curr }), {}),
}}
/>
),
content: <MetadataInfoPanel noBorder={false} market={market} />,
},
{
title: t('Risk model'),
content: (
<MarketInfoTable
noBorder={false}
data={market.tradableInstrument.riskModel}
unformatted={true}
omits={[]}
/>
),
content: <RiskModelInfoPanel noBorder={false} market={market} />,
},
{
title: t('Risk parameters'),
content: (
<MarketInfoTable
noBorder={false}
data={market.tradableInstrument.riskModel.params}
unformatted={true}
omits={[]}
/>
),
content: <RiskParametersInfoPanel noBorder={false} market={market} />,
},
{
title: t('Risk factors'),
content: (
<MarketInfoTable
noBorder={false}
data={market.riskFactors}
unformatted={true}
omits={['market', '__typename']}
/>
),
content: <RiskFactorsInfoPanel noBorder={false} market={market} />,
},
...(market.priceMonitoringSettings?.parameters?.triggers || []).map(
(trigger, i) => ({
@@ -151,14 +121,19 @@ 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}
data={{ referencePrice: trigger.referencePrice }}
decimalPlaces={assetDecimals}
decimalPlaces={
market.tradableInstrument.instrument.product.settlementAsset
.decimals
}
/>
</>
),
@@ -166,85 +141,29 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
{
title: t('Liquidity monitoring parameters'),
content: (
<MarketInfoTable
<LiquidityMonitoringParametersInfoPanel
noBorder={false}
data={{
triggeringRatio:
market.liquidityMonitoringParameters.triggeringRatio,
...market.liquidityMonitoringParameters.targetStakeParameters,
}}
market={market}
/>
),
},
{
title: t('Liquidity price range'),
content: (
<>
<p className="text-xs mb-4">
{`For liquidity orders to count towards a commitment, they must be
within the liquidity monitoring bounds.`}
</p>
<p className="text-xs mb-4">
{`The liquidity price range is a ${liquidityPriceRange} difference from the mid
price.`}
</p>
<MarketInfoTable
noBorder={false}
data={{
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
lowestPrice:
market.data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.minus(market.lpPriceRange)
.times(market.data.midPrice)
.toString(),
market.decimalPlaces
)} ${quoteUnit}`,
highestPrice:
market.data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.plus(market.lpPriceRange)
.times(market.data.midPrice)
.toString(),
market.decimalPlaces
)} ${quoteUnit}`,
}}
></MarketInfoTable>
</>
),
title: t('Liquidity'),
content: <LiquidityInfoPanel market={market} noBorder={false} />,
},
{
title: t('Oracle'),
title: t('Liquidity price range'),
content: (
<MarketInfoTable
noBorder={false}
data={
market.tradableInstrument.instrument.product.dataSourceSpecBinding
}
>
<Link
className="text-xs hover:underline"
to={`/oracles#${market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData.id}`}
>
{t('View settlement data oracle specification')}
</Link>
<Link
className="text-xs hover:underline"
to={`/oracles#${market.tradableInstrument.instrument.product.dataSourceSpecForTradingTermination.id}`}
>
{t('View termination oracle specification')}
</Link>
</MarketInfoTable>
<LiquidityPriceRangeInfoPanel market={market} noBorder={false} />
),
},
...oraclePanels,
];
return (
<>
{panels.map((p) => (
<div className="mb-3">
<div key={p.title} className="mb-3">
<h2 className="font-alpha calt text-xl">{p.title}</h2>
{p.content}
</div>
@@ -3,7 +3,7 @@ import { t } from '@vegaprotocol/i18n';
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react';
import { AgGridColumn } from 'ag-grid-react';
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import type {
VegaICellRendererParams,
VegaValueGetterParams,
@@ -9,7 +9,7 @@ import SizeInMarket from '../size-in-market/size-in-market';
export interface DeterministicOrderDetailsProps {
id: string;
// Version to fetch, with 0 being 'latest' and 1 being 'first'. Defaults to 0
version?: number;
version?: number | null;
}
export const wrapperClasses =
@@ -28,7 +28,7 @@ export const wrapperClasses =
*/
const DeterministicOrderDetails = ({
id,
version = 0,
version = null,
}: DeterministicOrderDetailsProps) => {
const { data, error } = useExplorerDeterministicOrderQuery({
variables: { orderId: id, version },
@@ -3,7 +3,7 @@ import { VoteProgress } from '@vegaprotocol/proposals';
import type { AgGridReact } from 'ag-grid-react';
import { AgGridColumn } from 'ag-grid-react';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import type {
VegaICellRendererParams,
VegaValueFormatterParams,
@@ -12,7 +12,10 @@ import { useLayoutEffect, useMemo, useRef, useState } from 'react';
import type { RowClickedEvent } from 'ag-grid-community';
import { getDateTimeFormat } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { NetworkParams, useNetworkParams } from '@vegaprotocol/react-helpers';
import {
NetworkParams,
useNetworkParams,
} from '@vegaprotocol/network-parameters';
import { ProposalStateMapping } from '@vegaprotocol/types';
import BigNumber from 'bignumber.js';
import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment';
@@ -1,4 +1,5 @@
import { t } from '@vegaprotocol/i18n';
import { Button } from '@vegaprotocol/ui-toolkit';
import { StatusMessage } from '../status-message';
interface RenderFetchedProps {
@@ -7,6 +8,7 @@ interface RenderFetchedProps {
loading: boolean | undefined;
className?: string;
errorMessage?: string;
refetch?: () => void;
}
export const RenderFetched = ({
@@ -15,6 +17,7 @@ export const RenderFetched = ({
children,
className,
errorMessage = t('Error retrieving data'),
refetch,
}: RenderFetchedProps) => {
if (loading) {
return (
@@ -23,7 +26,20 @@ export const RenderFetched = ({
}
if (error) {
return <StatusMessage className={className}>{errorMessage}</StatusMessage>;
return (
<>
<StatusMessage className={className}>{errorMessage}</StatusMessage>
{refetch && (
<Button
onClick={() => {
refetch();
}}
>
{t('Try again')}
</Button>
)}
</>
);
}
return children;
@@ -1,32 +0,0 @@
import { t } from '@vegaprotocol/i18n';
import React from 'react';
interface RouteErrorBoundaryProps {
children: React.ReactElement;
}
export class RouteErrorBoundary extends React.Component<
RouteErrorBoundaryProps,
{ hasError: boolean }
> {
constructor(props: RouteErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
override componentDidCatch(error: Error) {
console.log(`Error caught in App error boundary ${error.message}`, error);
}
override render() {
if (this.state.hasError) {
return <h1>{t('Something went wrong')}</h1>;
}
return this.props.children;
}
}
@@ -1,189 +1,70 @@
import {
detectTypeByFetching,
detectTypeFromQuery,
getSearchType,
determineType,
isBlock,
isHexadecimal,
isNetworkParty,
isNonHex,
SearchTypes,
toHex,
toNonHex,
isHash,
} from './detect-search';
import { DATA_SOURCES } from '../../config';
global.fetch = jest.fn();
describe('Detect Search', () => {
it("should detect that it's a hexadecimal", () => {
const expected = true;
const testString =
'0x073ceaab59e5f2dd0561dec4883e7ee5bc7165cd4de34717a3ab8f2cbe3007f9';
const actual = isHexadecimal(testString);
expect(actual).toBe(expected);
});
it("should detect that it's not hexadecimal", () => {
const expected = true;
const testString =
'073ceaab59e5f2dd0561dec4883e7ee5bc7165cd4de34717a3ab8f2cbe3007f9';
const actual = isNonHex(testString);
expect(actual).toBe(expected);
it.each([
['0000000000000000000000000000000000000000000000000000000000000000', true],
['0000000000000000000000000000000000000000000000000000000000000001', true],
[
'LOOONG0000000000000000000000000000000000000000000000000000000000000000',
false,
],
['xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', false],
['something else', false],
])("should detect that it's a hash", (input, expected) => {
expect(isHash(input)).toBe(expected);
});
it("should detect that it's a network party", () => {
const expected = true;
const testString = 'network';
const actual = isNetworkParty(testString);
expect(actual).toBe(expected);
expect(isNetworkParty('network')).toBe(true);
expect(isNetworkParty('web')).toBe(false);
});
it("should detect that it's a block", () => {
const expected = true;
const testString = '3188';
const actual = isBlock(testString);
expect(actual).toBe(expected);
expect(isBlock('123')).toBe(true);
expect(isBlock('x123')).toBe(false);
});
it('should convert from non-hex to hex', () => {
const expected = '0x123';
const testString = '123';
const actual = toHex(testString);
expect(actual).toBe(expected);
});
it('should convert from hex to non-hex', () => {
const expected = '123';
const testString = '0x123';
const actual = toNonHex(testString);
expect(actual).toBe(expected);
});
it("should detect type client side from query if it's a hexadecimal", () => {
const expected = [SearchTypes.Party, SearchTypes.Transaction];
const testString =
'0x4624293CFE3D8B67A0AB448BAFF8FBCF1A1B770D9D5F263761D3D6CBEA94D97F';
const actual = detectTypeFromQuery(testString);
expect(actual).toStrictEqual(expected);
});
it("should detect type client side from query if it's a non hex", () => {
const expected = [SearchTypes.Party, SearchTypes.Transaction];
const testString =
'4624293CFE3D8B67A0AB448BAFF8FBCF1A1B770D9D5F263761D3D6CBEA94D97F';
const actual = detectTypeFromQuery(testString);
expect(actual).toStrictEqual(expected);
});
it("should detect type client side from query if it's a network party", () => {
const expected = [SearchTypes.Party];
const testString = 'network';
const actual = detectTypeFromQuery(testString);
expect(actual).toStrictEqual(expected);
});
it("should detect type client side from query if it's a block (number)", () => {
const expected = [SearchTypes.Block];
const testString = '23432';
const actual = detectTypeFromQuery(testString);
expect(actual).toStrictEqual(expected);
});
it("detectTypeByFetching should call fetch with non-hex query it's a transaction", async () => {
const query = '0xabc';
const type = SearchTypes.Transaction;
// @ts-ignore issue related to polyfill
fetch.mockImplementation(
jest.fn(() =>
Promise.resolve({
ok: true,
json: () =>
Promise.resolve({
transaction: {
hash: query,
},
}),
})
)
);
const result = await detectTypeByFetching(query);
expect(fetch).toHaveBeenCalledWith(
`${DATA_SOURCES.blockExplorerUrl}/transactions/${toNonHex(query)}`
);
expect(result).toBe(type);
});
it("detectTypeByFetching should call fetch with non-hex query it's a party", async () => {
const query = 'abc';
const type = SearchTypes.Party;
// @ts-ignore issue related to polyfill
fetch.mockImplementation(
jest.fn(() =>
Promise.resolve({
ok: false,
})
)
);
const result = await detectTypeByFetching(query);
expect(result).toBe(type);
});
it('getSearchType should return party from fetch response', async () => {
const query =
'0x4624293CFE3D8B67A0AB448BAFF8FBCF1A1B770D9D5F263761D3D6CBEA94D97F';
const expected = SearchTypes.Party;
// @ts-ignore issue related to polyfill
fetch.mockImplementation(
jest.fn(() =>
Promise.resolve({
ok: false,
})
)
);
const result = await getSearchType(query);
expect(result).toBe(expected);
});
it('getSearchType should return transaction from fetch response', async () => {
const query =
'4624293CFE3D8B67A0AB448BAFF8FBCF1A1B770D9D5F263761D3D6CBEA94D97F';
const expected = SearchTypes.Transaction;
// @ts-ignore issue related to polyfill
fetch.mockImplementation(
jest.fn(() =>
Promise.resolve({
ok: true,
json: () =>
Promise.resolve({
transaction: {
hash: query,
},
}),
})
)
);
const result = await getSearchType(query);
expect(result).toBe(expected);
});
it('getSearchType should return undefined from transaction response', async () => {
const query = 'u';
const expected = undefined;
const result = await getSearchType(query);
expect(result).toBe(expected);
});
it('getSearchType should return block if query is number', async () => {
const query = '123';
const expected = SearchTypes.Block;
const result = await getSearchType(query);
expect(result).toBe(expected);
});
it('getSearchType should return party if query is network', async () => {
const query = 'network';
const expected = SearchTypes.Party;
const result = await getSearchType(query);
expect(result).toBe(expected);
});
it.each([
[
'0000000000000000000000000000000000000000000000000000000000000000',
SearchTypes.Transaction,
],
[
'0000000000000000000000000000000000000000000000000000000000000001',
SearchTypes.Party,
],
['123', SearchTypes.Block],
['network', SearchTypes.Party],
['something else', SearchTypes.Unknown],
])(
"detectTypeByFetching should call fetch with non-hex query it's a transaction",
async (input, type) => {
// @ts-ignore issue related to polyfill
fetch.mockImplementation(
jest.fn(() =>
Promise.resolve({
ok:
input ===
'0000000000000000000000000000000000000000000000000000000000000000',
json: () =>
Promise.resolve({
transaction: {
hash: input,
},
}),
})
)
);
const result = await determineType(input);
expect(result).toBe(type);
}
);
});
@@ -1,3 +1,4 @@
import { remove0x } from '@vegaprotocol/utils';
import { DATA_SOURCES } from '../../config';
import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response';
@@ -6,15 +7,20 @@ export enum SearchTypes {
Party = 'party',
Block = 'block',
Order = 'order',
Unknown = 'unknown',
}
export const TX_LENGTH = 64;
export const HASH_LENGTH = 64;
export const isHash = (value: string) =>
/[0-9a-fA-F]+/.test(remove0x(value)) &&
remove0x(value).length === HASH_LENGTH;
export const isHexadecimal = (search: string) =>
search.startsWith('0x') && search.length === 2 + TX_LENGTH;
search.startsWith('0x') && search.length === 2 + HASH_LENGTH;
export const isNonHex = (search: string) =>
!search.startsWith('0x') && search.length === TX_LENGTH;
!search.startsWith('0x') && search.length === HASH_LENGTH;
export const isBlock = (search: string) => !Number.isNaN(Number(search));
@@ -23,121 +29,44 @@ export const isNetworkParty = (search: string) => search === 'network';
export const toHex = (query: string) =>
isHexadecimal(query) ? query : `0x${query}`;
export const toNonHex = (query: string) =>
isNonHex(query) ? query : `${query.replace('0x', '')}`;
export const toNonHex = remove0x;
export const detectTypeFromQuery = (
query: string
): SearchTypes[] | undefined => {
const i = query.toLowerCase();
if (isHexadecimal(i) || isNonHex(i)) {
return [SearchTypes.Party, SearchTypes.Transaction];
} else if (isNetworkParty(i)) {
return [SearchTypes.Party];
} else if (isBlock(i)) {
return [SearchTypes.Block];
/**
* Determine the type of the given query
*/
export const determineType = async (query: string): Promise<SearchTypes> => {
const value = query.toLowerCase();
if (isHash(value)) {
// it can be either `SearchTypes.Party` or `SearchTypes.Transaction`
if (await isTransactionHash(value)) {
return SearchTypes.Transaction;
} else {
return SearchTypes.Party;
}
} else if (isNetworkParty(value)) {
return SearchTypes.Party;
} else if (isBlock(value)) {
return SearchTypes.Block;
}
return undefined;
return SearchTypes.Unknown;
};
export const detectTypeByFetching = async (
query: string
): Promise<SearchTypes | undefined> => {
const hash = toNonHex(query);
/**
* Checks if given input is a transaction hash by querying the transactions
* endpoint
*/
export const isTransactionHash = async (input: string): Promise<boolean> => {
const hash = remove0x(input);
const request = await fetch(
`${DATA_SOURCES.blockExplorerUrl}/transactions/${hash}`
);
if (request?.ok) {
const body: BlockExplorerTransaction = await request.json();
if (body?.transaction) {
return SearchTypes.Transaction;
return true;
}
}
return SearchTypes.Party;
};
// Code commented out because the current solution to detect a hex is temporary (by process of elimination)
// export const detectTypeByFetching = async (
// query: string,
// type: SearchTypes
// ): Promise<SearchTypes | undefined> => {
// const TYPES = [SearchTypes.Party, SearchTypes.Transaction];
//
// if (!TYPES.includes(type)) {
// throw new Error('Search type provided not recognised');
// }
//
// if (type === SearchTypes.Transaction) {
// const hash = toNonHex(query);
// const request = await fetch(
// `${DATA_SOURCES.blockExplorerUrl}/transactions/${hash}`
// );
//
// if (request?.ok) {
// const body: BlockExplorerTransaction = await request.json();
//
// if (body?.transaction) {
// return SearchTypes.Transaction;
// }
// }
// } else if (type === SearchTypes.Party) {
// const party = toNonHex(query);
//
// const request = await fetch(
// `${DATA_SOURCES.blockExplorerUrl}/transactions?limit=1&filters[tx.submitter]=${party}`
// );
//
// if (request.ok) {
// const body: BlockExplorerTransactions = await request.json();
//
// if (body?.transactions?.length) {
// return SearchTypes.Party;
// }
// }
// }
//
// return undefined;
// };
// export const getSearchType = async (
// query: string
// ): Promise<SearchTypes | undefined> => {
// const searchTypes = detectTypeFromQuery(query);
// const hasResults = searchTypes?.length;
//
// if (hasResults) {
// if (hasResults > 1) {
// const promises = searchTypes.map((type) =>
// detectTypeByFetching(query, type)
// );
// const results = await Promise.all(promises);
// return results.find((result) => result !== undefined);
// }
//
// return searchTypes[0];
// }
//
// return undefined;
// };
export const getSearchType = async (
query: string
): Promise<SearchTypes | undefined> => {
const searchTypes = detectTypeFromQuery(query);
const hasResults = searchTypes?.length;
if (hasResults) {
if (hasResults > 1) {
return await detectTypeByFetching(query);
}
return searchTypes[0];
}
return undefined;
return false;
};
@@ -1,157 +1,82 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { Search } from './search';
import {
act,
fireEvent,
render,
screen,
waitFor,
} from '@testing-library/react';
import { SearchForm } from './search';
import { MemoryRouter } from 'react-router-dom';
import { Routes } from '../../routes/route-names';
import { SearchTypes, getSearchType } from './detect-search';
global.fetch = jest.fn();
const mockedNavigate = jest.fn();
const mockGetSearchType = getSearchType as jest.MockedFunction<
typeof getSearchType
>;
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => mockedNavigate,
}));
jest.mock('./detect-search', () => ({
...jest.requireActual('./detect-search'),
getSearchType: jest.fn(),
}));
beforeEach(() => {
mockedNavigate.mockClear();
});
const renderComponent = () => (
<MemoryRouter>
<Search />
</MemoryRouter>
);
const renderComponent = () =>
render(
<MemoryRouter>
<SearchForm />
</MemoryRouter>
);
const getInputs = () => ({
input: screen.getByTestId('search'),
button: screen.getByTestId('search-button'),
});
describe('Search', () => {
describe('SearchForm', () => {
it('should render search input and button', () => {
render(renderComponent());
renderComponent();
expect(screen.getByTestId('search')).toBeInTheDocument();
expect(screen.getByTestId('search-button')).toHaveTextContent('Search');
});
it('should render error if input is not known', async () => {
render(renderComponent());
const { button, input } = getInputs();
fireEvent.change(input, { target: { value: 'asd' } });
fireEvent.click(button);
expect(await screen.findByTestId('search-error')).toHaveTextContent(
'Transaction type is not recognised'
it.each([
[
Routes.TX,
'0000000000000000000000000000000000000000000000000000000000000000',
],
[
Routes.PARTIES,
'0000000000000000000000000000000000000000000000000000000000000001',
],
[Routes.BLOCKS, '123'],
[undefined, 'something else'],
])('should redirect to %s', async (route, input) => {
// @ts-ignore issue related to polyfill
fetch.mockImplementation(
jest.fn(() =>
Promise.resolve({
ok:
input ===
'0000000000000000000000000000000000000000000000000000000000000000',
json: () =>
Promise.resolve({
transaction: {
hash: input,
},
}),
})
)
);
});
it('should render error if no input is given', async () => {
render(renderComponent());
const { button } = getInputs();
fireEvent.click(button);
expect(await screen.findByTestId('search-error')).toHaveTextContent(
'Search query required'
);
});
it('should redirect to transactions page', async () => {
render(renderComponent());
const { button, input } = getInputs();
mockGetSearchType.mockResolvedValue(SearchTypes.Transaction);
fireEvent.change(input, {
target: {
value:
'0x1234567890123456789012345678901234567890123456789012345678901234',
},
renderComponent();
await act(async () => {
fireEvent.change(screen.getByTestId('search'), {
target: {
value: input,
},
});
fireEvent.click(screen.getByTestId('search-button'));
});
fireEvent.click(button);
await waitFor(() => {
expect(mockedNavigate).toBeCalledWith(
`${Routes.TX}/0x1234567890123456789012345678901234567890123456789012345678901234`
);
});
});
it('should redirect to transactions page without proceeding 0x', async () => {
render(renderComponent());
const { button, input } = getInputs();
mockGetSearchType.mockResolvedValue(SearchTypes.Transaction);
fireEvent.change(input, {
target: {
value:
'1234567890123456789012345678901234567890123456789012345678901234',
},
});
fireEvent.click(button);
await waitFor(() => {
expect(mockedNavigate).toBeCalledWith(
`${Routes.TX}/0x1234567890123456789012345678901234567890123456789012345678901234`
);
});
});
it('should redirect to parties page', async () => {
render(renderComponent());
const { button, input } = getInputs();
mockGetSearchType.mockResolvedValue(SearchTypes.Party);
fireEvent.change(input, {
target: {
value:
'0x1234567890123456789012345678901234567890123456789012345678901234',
},
});
fireEvent.click(button);
await waitFor(() => {
expect(mockedNavigate).toBeCalledWith(
`${Routes.PARTIES}/0x1234567890123456789012345678901234567890123456789012345678901234`
);
});
});
it('should redirect to parties page without proceeding 0x', async () => {
render(renderComponent());
const { button, input } = getInputs();
mockGetSearchType.mockResolvedValue(SearchTypes.Party);
fireEvent.change(input, {
target: {
value:
'1234567890123456789012345678901234567890123456789012345678901234',
},
});
fireEvent.click(button);
await waitFor(() => {
expect(mockedNavigate).toBeCalledWith(
`${Routes.PARTIES}/0x1234567890123456789012345678901234567890123456789012345678901234`
);
});
});
it('should redirect to blocks page if passed a number', async () => {
render(renderComponent());
const { button, input } = getInputs();
mockGetSearchType.mockResolvedValue(SearchTypes.Block);
fireEvent.change(input, {
target: {
value: '123',
},
});
fireEvent.click(button);
await waitFor(() => {
expect(mockedNavigate).toBeCalledWith(`${Routes.BLOCKS}/123`);
expect(mockedNavigate).toBeCalledTimes(route ? 1 : 0);
if (route) {
// eslint-disable-next-line jest/no-conditional-expect
expect(mockedNavigate).toBeCalledWith(`${route}/${input}`);
}
});
});
});
@@ -1,12 +1,13 @@
import { useCallback, useState } from 'react';
import { useCallback } from 'react';
import { t } from '@vegaprotocol/i18n';
import { Button, Input, InputError } from '@vegaprotocol/ui-toolkit';
import { useForm } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
import { getSearchType, SearchTypes, toHex } from './detect-search';
import { Routes } from '../../routes/route-names';
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import classNames from 'classnames';
import { remove0x } from '@vegaprotocol/utils';
import { determineType, isBlock, isHash, SearchTypes } from './detect-search';
interface FormFields {
search: string;
@@ -30,101 +31,26 @@ const MagnifyingGlass = () => (
</svg>
);
const Clear = () => (
<svg
className="w-3 h-3"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.3748 1.37478L1.37478 11.3748L0.625244 10.6252L10.6252 0.625244L11.3748 1.37478Z"
fill="currentColor"
/>
<path
d="M1.37478 0.625244L11.3748 10.6252L10.6252 11.3748L0.625244 1.37478L1.37478 0.625244Z"
fill="currentColor"
/>
</svg>
);
export const Search = () => {
const { register, handleSubmit } = useForm<FormFields>();
const navigate = useNavigate();
const [error, setError] = useState<Error | null>(null);
const onSubmit = useCallback(
async (fields: FormFields) => {
setError(null);
const query = fields.search;
if (!query) {
return setError(new Error(t('Search query required')));
}
const result = await getSearchType(query);
const urlAsHex = toHex(query);
const unrecognisedError = new Error(
t('Transaction type is not recognised')
);
if (result) {
switch (result) {
case SearchTypes.Party:
return navigate(`${Routes.PARTIES}/${urlAsHex}`);
case SearchTypes.Transaction:
return navigate(`${Routes.TX}/${urlAsHex}`);
case SearchTypes.Block:
return navigate(`${Routes.BLOCKS}/${Number(query)}`);
default:
return setError(unrecognisedError);
}
}
return setError(unrecognisedError);
},
[navigate]
);
const searchForm = (
<form className="block min-w-[290px]" onSubmit={handleSubmit(onSubmit)}>
<div className="flex relative items-stretch gap-2 text-xs">
<label htmlFor="search" className="sr-only">
{t('Search by block number or transaction hash')}
</label>
<button
className={classNames(
'absolute top-[50%] translate-y-[-50%] left-2',
'text-vega-light-300 dark:text-vega-dark-300'
)}
>
<MagnifyingGlass />
</button>
<Input
{...register('search')}
id="search"
data-testid="search"
className={classNames(
'peer',
'pl-8 py-2 text-xs',
'border rounded border-vega-light-200 dark:border-vega-dark-200'
)}
hasError={Boolean(error?.message)}
type="text"
placeholder={t('Enter block number, public key or transaction hash')}
/>
{error?.message && (
<div
className={classNames(
'hidden peer-focus:block',
'bg-white dark:bg-black',
'border rounded-b border-t-0 border-vega-light-200 dark:border-vega-dark-200',
'absolute top-[100%] flex-1 w-full pb-2 px-2 text-black dark:text-white'
)}
>
<InputError
data-testid="search-error"
intent="danger"
className="text-xs"
>
{error.message}
</InputError>
</div>
)}
<Button
className="hidden [.search-dropdown_&]:block"
type="submit"
size="xs"
data-testid="search-button"
>
{t('Search')}
</Button>
</div>
</form>
);
const searchForm = <SearchForm />;
const searchTrigger = (
<DropdownMenu.Root>
@@ -154,10 +80,135 @@ export const Search = () => {
return (
<>
<div className="hidden [.nav-search-full_&]:block">{searchForm}</div>
<div className="hidden [.nav-search-full_&]:block min-w-[290px]">
{searchForm}
</div>
<div className="hidden [.nav-search-compact_&]:block">
{searchTrigger}
</div>
</>
);
};
export const SearchForm = () => {
const {
register,
handleSubmit,
setValue,
setError,
clearErrors,
formState,
watch,
} = useForm<FormFields>();
const navigate = useNavigate();
const onSubmit = useCallback(
async (fields: FormFields) => {
clearErrors();
const type = await determineType(fields.search);
if (type) {
switch (type) {
case SearchTypes.Party:
return navigate(`${Routes.PARTIES}/${remove0x(fields.search)}`);
case SearchTypes.Transaction:
return navigate(`${Routes.TX}/${remove0x(fields.search)}`);
case SearchTypes.Block:
return navigate(`${Routes.BLOCKS}/${Number(fields.search)}`);
}
}
setError('search', new Error(t('The search term is not a valid query')));
},
[clearErrors, navigate, setError]
);
const searchQuery = watch('search', '');
return (
<form className="block min-w-[200px]" onSubmit={handleSubmit(onSubmit)}>
<div className="flex relative items-stretch gap-2 text-xs">
<div className="relative w-full">
<label htmlFor="search" className="sr-only">
{t('Search by block number or transaction hash')}
</label>
<button
className={classNames(
'absolute top-[50%] translate-y-[-50%] left-2',
'text-vega-light-300 dark:text-vega-dark-300'
)}
>
<MagnifyingGlass />
</button>
<button
onClick={(e) => {
e.preventDefault();
setValue('search', '');
clearErrors();
}}
className={classNames(
{ hidden: searchQuery.length === 0 },
'absolute top-[50%] translate-y-[-50%] right-2',
'text-vega-light-300 dark:text-vega-dark-300'
)}
>
<Clear />
</button>
<Input
{...register('search', {
required: t('Search query is required'),
validate: (value) =>
isHash(value) ||
isBlock(value) ||
t('Search query has to be a number or a 64 character hash'),
onBlur: () => clearErrors('search'),
})}
id="search"
data-testid="search"
className={classNames(
'pl-8 py-2 text-xs',
{ 'pr-8': searchQuery.length > 1 },
'border rounded border-vega-light-200 dark:border-vega-dark-200',
{
'border-vega-pink dark:border-vega-pink': Boolean(
formState.errors.search
),
}
)}
hasError={Boolean(formState.errors.search)}
type="text"
placeholder={t(
'Enter block number, public key or transaction hash'
)}
/>
</div>
{formState.errors.search && (
<div
className={classNames(
'[nav_&]:border [nav_&]:rounded [nav_&]:border-vega-light-300 [nav_&]:dark:border-vega-light-300',
'[.search-dropdown_&]:border [.search-dropdown_&]:rounded [.search-dropdown_&]:border-vega-light-300 [.search-dropdown_&]:dark:border-vega-light-300',
'bg-white dark:bg-black',
'absolute top-[100%] flex-1 w-full pb-2 px-2 text-black dark:text-white'
)}
>
<InputError
data-testid="search-error"
intent="danger"
className="text-xs"
>
{formState.errors.search.message}
</InputError>
</div>
)}
<Button
variant="primary"
type="submit"
size="xs"
data-testid="search-button"
className="[nav_&]:hidden"
>
{t('Search')}
</Button>
</div>
</form>
);
};
@@ -1,6 +1,6 @@
import { proposalsDataProvider } from '@vegaprotocol/proposals';
import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { ProposalsTable } from '../../components/proposals/proposals-table';
import { RouteTitle } from '../../components/route-title';
+8 -3
View File
@@ -1,14 +1,19 @@
import { StatsManager } from '@vegaprotocol/network-stats';
import { SearchForm } from '../../components/search';
import { useDocumentTitle } from '../../hooks/use-document-title';
const Home = () => {
const classnames = 'mt-4 grid grid-cols-1 lg:grid-cols-2 lg:gap-4';
const classnames = 'mt-4 mb-4';
useDocumentTitle();
return (
<section>
<StatsManager className={classnames} />
<div className="p-20 max-sm:py-10 max-sm:px-0">
<SearchForm />
</div>
<div className="px-20 max-sm:px-0">
<StatsManager className={classnames} />
</div>
</section>
);
};
-26
View File
@@ -1,26 +0,0 @@
import React from 'react';
import { useRoutes } from 'react-router-dom';
import { RouteErrorBoundary } from '../components/router-error-boundary';
import routerConfig from './router-config';
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
export interface RouteChildProps {
name: string;
}
export const AppRouter = () => {
const routes = useRoutes(routerConfig);
const splashLoading = (
<Splash>
<Loader />
</Splash>
);
return (
<RouteErrorBoundary>
<React.Suspense fallback={splashLoading}>{routes}</React.Suspense>
</RouteErrorBoundary>
);
};
+166
View File
@@ -0,0 +1,166 @@
import {
AssetDetailsDialog,
useAssetDetailsDialogStore,
} from '@vegaprotocol/assets';
import { t } from '@vegaprotocol/i18n';
import { useEnvironment } from '@vegaprotocol/environment';
import { AnnouncementBanner } from '@vegaprotocol/announcements';
import {
BackgroundVideo,
BreadcrumbsContainer,
ButtonLink,
} from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames';
import {
isRouteErrorResponse,
Link,
Outlet,
useMatch,
useRouteError,
} from 'react-router-dom';
import { Footer } from '../components/footer/footer';
import { Header } from '../components/header';
import { Routes } from './route-names';
const DialogsContainer = () => {
const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore();
return (
<AssetDetailsDialog
assetId={id}
trigger={trigger || null}
asJson={asJson}
open={isOpen}
onChange={setOpen}
/>
);
};
export const Layout = () => {
const isHome = Boolean(useMatch(Routes.HOME));
const { ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
const fixedWidthClasses = 'w-full max-w-[1500px] mx-auto';
return (
<>
<div
className={classNames(
'min-h-screen',
'mx-auto my-0',
'grid grid-rows-[auto_1fr_auto] grid-cols-1',
'border-vega-light-200 dark:border-vega-dark-200',
'antialiased text-black dark:text-white',
'overflow-hidden relative'
)}
>
<div>
{ANNOUNCEMENTS_CONFIG_URL && (
<AnnouncementBanner
app="explorer"
configUrl={ANNOUNCEMENTS_CONFIG_URL}
/>
)}
<Header />
</div>
<div className={fixedWidthClasses}>
<main className="p-4">
{!isHome && <BreadcrumbsContainer className="mb-4" />}
<Outlet />
</main>
</div>
<div className={fixedWidthClasses}>
<Footer />
</div>
</div>
<DialogsContainer />
</>
);
};
export const ErrorBoundary = () => {
const error = useRouteError();
const errorTitle = isRouteErrorResponse(error)
? `${error.status} ${error.statusText}`
: t('Something went wrong');
const errorMessage = isRouteErrorResponse(error)
? error.error?.message
: (error as Error).message || JSON.stringify(error);
return (
<>
<BackgroundVideo className="brightness-50" />
<div
className={classNames(
'max-w-[620px] p-2 mt-[10vh]',
'mx-auto my-0',
'antialiased text-white',
'overflow-hidden relative',
'flex flex-col gap-2'
)}
>
<div className="flex gap-4">
<div>{GHOST}</div>
<h1 className="text-[2.7rem] font-alpha calt break-words uppercase">
{errorTitle}
</h1>
</div>
<div className="text-sm mt-10 overflow-auto break-all font-mono">
{errorMessage}
</div>
<div>
<ButtonLink onClick={() => window.location.reload()}>
{t('Try refreshing')}
</ButtonLink>{' '}
{t('or go back to')}{' '}
<Link className="underline" to="/">
{t('Home')}
</Link>
</div>
</div>
</>
);
};
const GHOST = (
<svg
width="56"
height="85"
viewBox="0 0 56 85"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M41 0.5H3V60.5H41V0.5Z" fill="white" />
<path d="M15 18.5H13V20.5H15V18.5Z" fill="black" />
<path d="M17 20.5H15V22.5H17V20.5Z" fill="black" />
<path d="M19 18.5H17V20.5H19V18.5Z" fill="black" />
<path d="M15 22.5H13V24.5H15V22.5Z" fill="black" />
<path d="M19 22.5H17V24.5H19V22.5Z" fill="black" />
<path d="M29 28.5H15V30.5H29V28.5Z" fill="black" />
<path d="M27 18.5H25V20.5H27V18.5Z" fill="black" />
<path d="M29 20.5H27V22.5H29V20.5Z" fill="black" />
<path d="M31 18.5H29V20.5H31V18.5Z" fill="black" />
<path d="M27 22.5H25V24.5H27V22.5Z" fill="black" />
<path d="M31 22.5H29V24.5H31V22.5Z" fill="black" />
<path d="M31 26.5H29V28.5H31V26.5Z" fill="black" />
<path d="M19 60.5H17V84.5H19V60.5Z" fill="black" />
<path d="M27 60.5H25V84.5H27V60.5Z" fill="black" />
<path
d="M3 42.5V58.64V60.5V64.5H21V60.5H23V64.5H41V60.5V58.64V42.5H3Z"
fill="#FF077F"
/>
<path d="M35 46.5H41V42.5H3V46.5H31H35Z" fill="#CB0666" />
<path d="M3 32.32V29.5L0 32.5V60.5H2V33.33L3 32.32Z" fill="black" />
<path d="M41 31.8V29.49L54.79 21.53L55.79 23.26L41 31.8Z" fill="black" />
<path d="M36 54.5H35V55.5H36V54.5Z" fill="black" />
<path d="M35 53.5H34V54.5H35V53.5Z" fill="black" />
<path d="M34 48.5H33V53.5H34V48.5Z" fill="black" />
<path d="M38 48.5H37V52.5H38V48.5Z" fill="black" />
<path d="M37 53.5H36V54.5H37V53.5Z" fill="black" />
<path d="M39 52.5H38V53.5H39V52.5Z" fill="black" />
<path
d="M55.7901 23.27L53.0601 22.54L45.1001 8.75L46.8301 7.75L55.7901 23.27Z"
fill="black"
/>
</svg>
);
@@ -1,5 +1,5 @@
import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
import { useState } from 'react';
import { useParams } from 'react-router-dom';
@@ -8,7 +8,7 @@ import { useScrollToLocation } from '../../hooks/scroll-to-location';
import { useDocumentTitle } from '../../hooks/use-document-title';
import compact from 'lodash/compact';
import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
import { marketInfoProvider } from '@vegaprotocol/market-info';
import { marketInfoWithDataProvider } from '@vegaprotocol/market-info';
import { PageTitle } from '../../components/page-helpers/page-title';
export const MarketPage = () => {
@@ -17,7 +17,7 @@ export const MarketPage = () => {
const { marketId } = useParams<{ marketId: string }>();
const { data, loading, error } = useDataProvider({
dataProvider: marketInfoProvider,
dataProvider: marketInfoWithDataProvider,
skipUpdates: true,
variables: {
marketId: marketId || '',
@@ -4,7 +4,7 @@ import { marketsProvider } from '@vegaprotocol/market-list';
import { RouteTitle } from '../../components/route-title';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { MarketsTable } from '../../components/markets/markets-table';
export const MarketsPage = () => {
@@ -1,5 +1,5 @@
import { render, screen } from '@testing-library/react';
import type { NetworkParamsQuery } from '@vegaprotocol/react-helpers';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import { NetworkParametersTable } from './network-parameters';
describe('NetworkParametersTable', () => {
@@ -13,14 +13,15 @@ import {
import { t } from '@vegaprotocol/i18n';
import { RouteTitle } from '../../components/route-title';
import orderBy from 'lodash/orderBy';
import { useNetworkParamsQuery } from '@vegaprotocol/react-helpers';
import type { NetworkParamsQuery } from '@vegaprotocol/react-helpers';
import { useNetworkParamsQuery } from '@vegaprotocol/network-parameters';
import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import { useScrollToLocation } from '../../hooks/scroll-to-location';
import { useDocumentTitle } from '../../hooks/use-document-title';
const PERCENTAGE_PARAMS = [
'governance.proposal.asset.requiredMajority',
'governance.proposal.asset.requiredParticipation',
'governance.proposal.updateAsset.requiredParticipation',
'governance.proposal.freeform.requiredMajority',
'governance.proposal.freeform.requiredParticipation',
'governance.proposal.market.requiredMajority',
@@ -53,6 +54,8 @@ const BIG_NUMBER_PARAMS = [
'governance.proposal.asset.minProposerBalance',
'governance.proposal.market.minProposerBalance',
'governance.proposal.market.minVoterBalance',
'governance.proposal.updateAsset.minProposerBalance',
'governance.proposal.updateAsset.minVoterBalance',
];
export const NetworkParameterRow = ({
@@ -71,7 +71,7 @@ export const PartyAccounts = ({ accounts }: PartyAccountsProps) => {
/>
</td>
<td className="text-md">
<AssetLink assetId={account.asset.id} />
<AssetLink assetId={account.asset.id} asDialog={true} />
</td>
</TableRow>
);
+201 -77
View File
@@ -8,7 +8,6 @@ import { Oracle } from './oracles/id';
import Party from './parties';
import { Parties } from './parties/home';
import { Party as PartySingle } from './parties/id';
import Txs from './txs';
import { ValidatorsPage } from './validators';
import Genesis from './genesis';
import { Block } from './blocks/id';
@@ -20,23 +19,55 @@ import flags from '../config/flags';
import { t } from '@vegaprotocol/i18n';
import { Routes } from './route-names';
import { NetworkParameters } from './network-parameters';
import type { RouteObject } from 'react-router-dom';
import type { Params, RouteObject } from 'react-router-dom';
import { createBrowserRouter } from 'react-router-dom';
import { Link } from 'react-router-dom';
import { MarketPage, MarketsPage } from './markets';
import type { ReactNode } from 'react';
import { ErrorBoundary, Layout } from './layout';
import compact from 'lodash/compact';
import { AssetLink, MarketLink } from '../components/links';
import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
import { remove0x } from '@vegaprotocol/utils';
export type Navigable = {
path: string;
name: string;
text: string;
handle: {
name: string;
text: string;
};
};
export const isNavigable = (item: RouteObject): item is Navigable =>
(item as Navigable).path !== undefined &&
(item as Navigable).handle !== undefined &&
(item as Navigable).handle.name !== undefined &&
(item as Navigable).handle.text !== undefined;
export type Breadcrumbable = {
handle: { breadcrumb: (data?: Params<string>) => ReactNode | string };
};
export const isBreadcrumbable = (item: RouteObject): item is Breadcrumbable =>
(item as Breadcrumbable).handle !== undefined &&
(item as Breadcrumbable).handle.breadcrumb !== undefined;
type RouteItem =
| RouteObject
| (RouteObject & Navigable)
| (RouteObject & Breadcrumbable);
type Route = RouteItem & {
children?: RouteItem[];
};
type Route = RouteObject & Navigable;
const partiesRoutes: Route[] = flags.parties
? [
{
path: Routes.PARTIES,
name: t('Parties'),
text: t('Parties'),
element: <Party />,
handle: {
name: t('Parties'),
text: t('Parties'),
breadcrumb: () => <Link to={Routes.PARTIES}>{t('Parties')}</Link>,
},
children: [
{
index: true,
@@ -45,6 +76,13 @@ const partiesRoutes: Route[] = flags.parties
{
path: ':party',
element: <PartySingle />,
handle: {
breadcrumb: (params: Params<string>) => (
<Link to={linkTo(Routes.PARTIES, params.party)}>
{truncateMiddle(params.party as string)}
</Link>
),
},
},
],
},
@@ -55,8 +93,11 @@ const assetsRoutes: Route[] = flags.assets
? [
{
path: Routes.ASSETS,
text: t('Assets'),
name: t('Assets'),
handle: {
name: t('Assets'),
text: t('Assets'),
breadcrumb: () => <Link to={Routes.ASSETS}>{t('Assets')}</Link>,
},
children: [
{
index: true,
@@ -65,6 +106,11 @@ const assetsRoutes: Route[] = flags.assets
{
path: ':assetId',
element: <AssetPage />,
handle: {
breadcrumb: (params: Params<string>) => (
<AssetLink assetId={params.assetId as string} />
),
},
},
],
},
@@ -75,8 +121,13 @@ const genesisRoutes: Route[] = flags.genesis
? [
{
path: Routes.GENESIS,
name: t('Genesis'),
text: t('Genesis Parameters'),
handle: {
name: t('Genesis'),
text: t('Genesis Parameters'),
breadcrumb: () => (
<Link to={Routes.GENESIS}>{t('Genesis Parameters')}</Link>
),
},
element: <Genesis />,
},
]
@@ -86,8 +137,13 @@ const governanceRoutes: Route[] = flags.governance
? [
{
path: Routes.GOVERNANCE,
name: t('Governance proposals'),
text: t('Governance Proposals'),
handle: {
name: t('Governance proposals'),
text: t('Governance Proposals'),
breadcrumb: () => (
<Link to={Routes.GOVERNANCE}>{t('Governance Proposals')}</Link>
),
},
element: <Proposals />,
},
]
@@ -97,8 +153,11 @@ const marketsRoutes: Route[] = flags.markets
? [
{
path: Routes.MARKETS,
name: t('Markets'),
text: t('Markets'),
handle: {
name: t('Markets'),
text: t('Markets'),
breadcrumb: () => <Link to={Routes.MARKETS}>{t('Markets')}</Link>,
},
children: [
{
index: true,
@@ -107,6 +166,11 @@ const marketsRoutes: Route[] = flags.markets
{
path: ':marketId',
element: <MarketPage />,
handle: {
breadcrumb: (params: Params<string>) => (
<MarketLink id={params.marketId as string} />
),
},
},
],
},
@@ -117,8 +181,15 @@ const networkParametersRoutes: Route[] = flags.networkParameters
? [
{
path: Routes.NETWORK_PARAMETERS,
name: t('NetworkParameters'),
text: t('Network Parameters'),
handle: {
name: t('NetworkParameters'),
text: t('Network Parameters'),
breadcrumb: () => (
<Link to={Routes.NETWORK_PARAMETERS}>
{t('Network Parameters')}
</Link>
),
},
element: <NetworkParameters />,
},
]
@@ -128,80 +199,133 @@ const validators: Route[] = flags.validators
? [
{
path: Routes.VALIDATORS,
name: t('Validators'),
text: t('Validators'),
handle: {
name: t('Validators'),
text: t('Validators'),
breadcrumb: () => (
<Link to={Routes.VALIDATORS}>{t('Validators')}</Link>
),
},
element: <ValidatorsPage />,
},
]
: [];
const routerConfig: Route[] = [
const linkTo = (...segments: (string | undefined)[]) =>
compact(segments).join('/');
export const routerConfig: Route[] = [
{
path: Routes.HOME,
name: t('Home'),
text: t('Home'),
element: <Home />,
index: true,
},
{
path: Routes.TX,
name: t('Txs'),
text: t('Transactions'),
element: <Txs />,
children: [
{
path: 'pending',
element: <PendingTxs />,
},
{
path: ':txHash',
element: <Tx />,
},
{
index: true,
element: <TxsList />,
},
],
},
{
path: Routes.BLOCKS,
name: t('Blocks'),
text: t('Blocks'),
element: <BlockPage />,
element: <Layout />,
handle: {
name: t('Home'),
text: t('Home'),
breadcrumb: () => <Link to={Routes.HOME}>{t('Home')}</Link>,
},
errorElement: <ErrorBoundary />,
children: [
{
index: true,
element: <Blocks />,
element: <Home />,
},
{
path: ':block',
element: <Block />,
path: Routes.TX,
handle: {
name: t('Txs'),
text: t('Transactions'),
breadcrumb: () => <Link to={Routes.TX}>{t('Transactions')}</Link>,
},
children: [
{
path: 'pending',
element: <PendingTxs />,
handle: {
breadcrumb: () => (
<Link to={linkTo(Routes.TX, 'pending')}>
{t('Pending transactions')}
</Link>
),
},
},
{
path: ':txHash',
element: <Tx />,
handle: {
breadcrumb: (params: Params<string>) => (
<Link to={linkTo(Routes.TX, params.txHash)}>
{truncateMiddle(remove0x(params.txHash as string))}
</Link>
),
},
},
{
index: true,
element: <TxsList />,
},
],
},
{
path: Routes.BLOCKS,
handle: {
name: t('Blocks'),
text: t('Blocks'),
breadcrumb: () => <Link to={Routes.BLOCKS}>{t('Blocks')}</Link>,
},
element: <BlockPage />,
children: [
{
index: true,
element: <Blocks />,
},
{
path: ':block',
element: <Block />,
handle: {
breadcrumb: (params: Params<string>) => (
<Link to={linkTo(Routes.BLOCKS, params.block)}>
{params.block}
</Link>
),
},
},
],
},
{
path: Routes.ORACLES,
handle: {
name: t('Oracles'),
text: t('Oracles'),
breadcrumb: () => <Link to={Routes.ORACLES}>{t('Oracles')}</Link>,
},
element: <OraclePage />,
children: [
{
index: true,
element: <Oracles />,
},
{
path: ':id',
element: <Oracle />,
handle: {
breadcrumb: (params: Params<string>) => (
<Link to={linkTo(Routes.ORACLES, params.id)}>
{truncateMiddle(params.id as string)}
</Link>
),
},
},
],
},
...partiesRoutes,
...assetsRoutes,
...genesisRoutes,
...governanceRoutes,
...marketsRoutes,
...networkParametersRoutes,
...validators,
],
},
{
path: Routes.ORACLES,
name: t('Oracles'),
text: t('Oracles'),
element: <OraclePage />,
children: [
{
index: true,
element: <Oracles />,
},
{
path: ':id',
element: <Oracle />,
},
],
},
...partiesRoutes,
...assetsRoutes,
...genesisRoutes,
...governanceRoutes,
...marketsRoutes,
...networkParametersRoutes,
...validators,
];
export default routerConfig;
export const router = createBrowserRouter(routerConfig);
+3 -16
View File
@@ -1,5 +1,4 @@
import React from 'react';
import { Link, useParams } from 'react-router-dom';
import { useParams } from 'react-router-dom';
import { remove0x } from '@vegaprotocol/utils';
import { useFetch } from '@vegaprotocol/react-helpers';
import { DATA_SOURCES } from '../../../config';
@@ -8,9 +7,6 @@ import { TxDetails } from './tx-details';
import type { BlockExplorerTransaction } from '../../../routes/types/block-explorer-response';
import { toNonHex } from '../../../components/search/detect-search';
import { PageHeader } from '../../../components/page-header';
import { Routes } from '../../../routes/route-names';
import { IconNames } from '@blueprintjs/icons';
import { Icon } from '@vegaprotocol/ui-toolkit';
import { useDocumentTitle } from '../../../hooks/use-document-title';
const Tx = () => {
@@ -22,6 +18,7 @@ const Tx = () => {
const {
state: { data, loading, error },
refetch,
} = useFetch<BlockExplorerTransaction>(
`${DATA_SOURCES.blockExplorerUrl}/transactions/${toNonHex(hash)}`
);
@@ -34,17 +31,6 @@ const Tx = () => {
return (
<section>
<Link
className="font-normal underline underline-offset-4 block mb-5"
to={`/${Routes.TX}`}
>
<Icon
className="text-vega-light-150 dark:text-vega-light-150"
name={IconNames.CHEVRON_LEFT}
/>
All Transactions
</Link>
<PageHeader
title="transaction"
truncateStart={5}
@@ -56,6 +42,7 @@ const Tx = () => {
error={error}
loading={loading}
errorMessage={errorMessage}
refetch={refetch}
>
<TxDetails
className="mb-28"
@@ -21,7 +21,7 @@ import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
import { PageTitle } from '../../components/page-helpers/page-title';
import BigNumber from 'bignumber.js';
import {
ContractAddressLink,
EtherscanLink,
DApp,
TOKEN_VALIDATOR,
useLinks,
@@ -224,7 +224,7 @@ export const ValidatorsPage = () => {
<KeyValueTableRow>
<div>{t('Ethereum address')}</div>
<div className="break-all text-xs">
<ContractAddressLink address={v.ethereumAddress} />{' '}
<EtherscanLink address={v.ethereumAddress} />{' '}
<CopyWithTooltip text={v.ethereumAddress}>
<button title={t('Copy address to clipboard')}>
<Icon size={3} name="duplicate" />
+1 -4
View File
@@ -1,5 +1,4 @@
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import './styles.css';
import App from './app/app';
@@ -10,8 +9,6 @@ const root = rootElement && createRoot(rootElement);
root?.render(
<StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
<App />
</StrictMode>
);
+44
View File
@@ -1,3 +1,7 @@
@import 'ag-grid-community/dist/styles/ag-grid.css';
@import 'ag-grid-community/dist/styles/ag-theme-balham.css';
@import 'ag-grid-community/dist/styles/ag-theme-balham-dark.css';
/* You can add global styles to this file, and also import other style files */
@tailwind base;
@tailwind components;
@@ -11,3 +15,43 @@
.react-markdown-container a:before {
content: '🔗 ';
}
/* AG GRID - Do not edit without updating other global stylesheets for each app */
.vega-ag-grid .ag-root-wrapper {
border: solid 0px;
}
.vega-ag-grid .ag-react-container {
overflow: hidden;
text-overflow: ellipsis;
}
.vega-ag-grid .ag-cell,
.vega-ag-grid .ag-full-width-row .ag-cell-wrapper.ag-row-group {
line-height: calc(min(var(--ag-line-height, 26px), 26px) - 4px);
}
/* Light variables */
.ag-theme-balham {
--ag-background-color: theme(colors.white);
--ag-border-color: theme(colors.neutral[300]);
--ag-header-background-color: theme(colors.white);
--ag-odd-row-background-color: theme(colors.white);
--ag-header-column-separator-color: theme(colors.neutral[300]);
--ag-row-border-color: theme(colors.white);
--ag-row-hover-color: theme(colors.neutral[100]);
--ag-font-size: 12px;
}
/* Dark variables */
.ag-theme-balham-dark {
--ag-background-color: theme(colors.black);
--ag-border-color: theme(colors.neutral[700]);
--ag-header-background-color: theme(colors.black);
--ag-odd-row-background-color: theme(colors.black);
--ag-header-column-separator-color: theme(colors.neutral[600]);
--ag-row-border-color: theme(colors.black);
--ag-row-hover-color: theme(colors.neutral[800]);
--ag-font-size: 12px;
}
+7 -4
View File
@@ -5,18 +5,22 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_FAIRGROUND=false
NX_VEGA_NETWORKS={}
NX_VEGA_URL=http://localhost:3028/query
NX_VEGA_URL=http://localhost:3008/graphql
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_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
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
CYPRESS_VEGA_URL=http://localhost:3028/query
CYPRESS_VEGA_URL=http://localhost:3008/graphql
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
CYPRESS_ETHEREUM_PROVIDER_URL=http://localhost:8545
CYPRESS_EXPLORER_URL=https://explorer.fairground.wtf
@@ -27,6 +31,5 @@ CYPRESS_VEGA_ENV=CUSTOM
CYPRESS_VEGA_PUBLIC_KEY=02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65
CYPRESS_VEGA_PUBLIC_KEY2=7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535
CYPRESS_VEGA_TOKEN_URL=https://token.fairground.wtf
CYPRESS_VEGA_URL=http://localhost:3028/query
CYPRESS_VEGA_WALLET_URL=http://localhost:1789
CYPRESS_VEGA_WALLET_API_TOKEN=
-5
View File
@@ -1,5 +0,0 @@
# App configuration variables
NX_VEGA_ENV=STAGNET3
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
+1 -1
View File
@@ -1,5 +1,5 @@
# App configuration variables
NX_VEGA_ENV=TESTNET
NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
+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',
},
};
@@ -2,12 +2,14 @@
"changes": {
"decimalPlaces": "5",
"positionDecimalPlaces": "5",
"linearSlippageFactor": "0.001",
"quadraticSlippageFactor": "0",
"lpPriceRange": "10",
"instrument": {
"name": "Token test market",
"code": "Token.24h",
"future": {
"settlementAsset": "fBTC",
"settlementAsset": "73174a6fb1d5802ba0ac7bd7ab79e0a3a4837b262de0a4e80815a55442692bd0",
"quoteName": "fBTC",
"dataSourceSpecForSettlementData": {
"external": {
@@ -1,5 +1,7 @@
{
"lpPriceRange": "10",
"linearSlippageFactor": "0.001",
"quadraticSlippageFactor": "0",
"instrument": {
"code": "TEST.24h",
"future": {
@@ -1,9 +1,28 @@
import { associateTokenStartOfTests } from '../../support/common.functions';
import {
navigateTo,
waitForSpinner,
navigation,
} from '../../support/common.functions';
import {
convertUnixTimestampToDateformat,
createRawProposal,
createTenDigitUnixTimeStampForSpecifiedDays,
enterUniqueFreeFormProposalBody,
generateFreeFormProposalTitle,
getGovernanceProposalDateFormatForSpecifiedDays,
getProposalIdFromList,
getProposalInformationFromTable,
getSubmittedProposalFromProposalList,
goToMakeNewProposal,
governanceProposalType,
} from '../../support/governance.functions';
voteForProposal,
waitForProposalSubmitted,
waitForProposalSync,
} from '../../../../governance-e2e/src/support/governance.functions';
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../../../governance-e2e/src/support/staking.functions';
import { ethereumWalletConnect } from '../../../../governance-e2e/src/support/wallet-eth.functions';
import { vegaWalletSetSpecifiedApprovalAmount } from '../../../../governance-e2e/src/support/wallet-teardown.functions';
import type { testFreeformProposal } from '../../support/common-interfaces';
const proposalVoteProgressForPercentage =
'[data-testid="vote-progress-indicator-percentage-for"]';
@@ -25,24 +44,25 @@ describe(
function () {
before('connect wallets and set approval limit', function () {
cy.visit('/');
cy.vega_wallet_set_specified_approval_amount('1000');
associateTokenStartOfTests();
ethereumWalletConnect();
cy.associateTokensToVegaWallet('1');
});
beforeEach('visit proposals tab', function () {
cy.clearLocalStorage();
cy.reload();
cy.wait_for_spinner();
waitForSpinner();
cy.connectVegaWallet();
cy.ethereum_wallet_connect();
cy.ensure_specified_unstaked_tokens_are_associated(1);
cy.navigate_to_page_if_not_already_loaded('proposals');
ethereumWalletConnect();
ensureSpecifiedUnstakedTokensAreAssociated('1');
navigateTo(navigation.proposals);
});
// 3001-VOTE-055
// 3001-VOTE-050 3001-VOTE-054 3001-VOTE-055 3002-PROP-019
it('Newly created raw proposal details - shows proposal title and full description', function () {
createRawProposal();
cy.get('@rawProposal').then((rawProposal) => {
cy.get_proposal_id_from_list(rawProposal.rationale.title);
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalIdFromList(rawProposal.rationale.title);
cy.get('@proposalIdText').then((proposalId) => {
cy.get(openProposals).within(() => {
cy.get(`#${proposalId}`).within(() => {
@@ -69,30 +89,26 @@ describe(
it('Newly created freeform proposal details - shows proposed and closing dates', function () {
const closingVoteHrs = '72';
const proposalTitle = generateFreeFormProposalTitle();
const proposalTimeStamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.create_ten_digit_unix_timestamp_for_specified_days('3').then(
(closingDateTimestamp) => {
cy.enter_unique_freeform_proposal_body(closingVoteHrs, proposalTitle);
cy.wait_for_proposal_submitted();
cy.wait_for_proposal_sync();
cy.navigate_to('proposals');
cy.get_submitted_proposal_from_proposal_list(proposalTitle).within(
() => cy.get(viewProposalButton).click()
);
cy.convert_unix_timestamp_to_governance_data_table_date_format(
closingDateTimestamp
).then((closingDate) => {
cy.get_proposal_information_from_table('Closes on')
.contains(closingDate)
.should('be.visible');
});
goToMakeNewProposal(governanceProposalType.FREEFORM);
enterUniqueFreeFormProposalBody(closingVoteHrs, proposalTitle);
waitForProposalSubmitted();
waitForProposalSync();
navigateTo(navigation.proposals);
getSubmittedProposalFromProposalList(proposalTitle).within(() =>
cy.get(viewProposalButton).click()
);
convertUnixTimestampToDateformat(proposalTimeStamp).then(
(closingDate) => {
getProposalInformationFromTable('Closes on')
.contains(closingDate)
.should('be.visible');
}
);
cy.get_governance_proposal_date_format_for_specified_days('0').then(
getGovernanceProposalDateFormatForSpecifiedDays(0).then(
(proposalDate) => {
cy.get_proposal_information_from_table('Proposed on')
getProposalInformationFromTable('Proposed on')
.contains(proposalDate)
.should('be.visible');
}
@@ -104,25 +120,25 @@ describe(
// 3001-VOTE-040
// 3001-VOTE-067
createRawProposal();
cy.get('@rawProposal').then((rawProposal) => {
cy.get_submitted_proposal_from_proposal_list(
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getSubmittedProposalFromProposalList(
rawProposal.rationale.title
).within(() => cy.get(viewProposalButton).click());
});
cy.contains('Participation: Not Met 0.00 0.00%(0.00% Required)').should(
'be.visible'
);
cy.get_proposal_information_from_table('Expected to pass')
getProposalInformationFromTable('Expected to pass')
.contains('👎')
.should('be.visible');
// 3001-VOTE-062
// 3001-VOTE-040
// 3001-VOTE-070
cy.get_proposal_information_from_table('Token majority met')
getProposalInformationFromTable('Token majority met')
.contains('👎')
.should('be.visible');
// 3001-VOTE-068
cy.get_proposal_information_from_table('Token participation met')
getProposalInformationFromTable('Token participation met')
.contains('👎')
.should('be.visible');
});
@@ -130,28 +146,27 @@ describe(
// 3001-VOTE-080 3001-VOTE-090 3001-VOTE-069 3001-VOTE-072 3001-VOTE-073
it('Newly created proposal details - ability to vote for and against proposal - with minimum required tokens associated', function () {
createRawProposal();
cy.get('@rawProposal').then((rawProposal) => {
cy.get_submitted_proposal_from_proposal_list(
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getSubmittedProposalFromProposalList(
rawProposal.rationale.title
).within(() => cy.get(viewProposalButton).click());
});
// 3001-VOTE-080
cy.getByTestId('vote-buttons').contains('against').should('be.visible');
cy.getByTestId('vote-buttons').contains('for').should('be.visible');
cy.vote_for_proposal('for');
cy.get_governance_proposal_date_format_for_specified_days(
'0',
'shortMonth'
).then((votedDate) => {
// 3001-VOTE-051
// 3001-VOTE-093
cy.contains('You voted:')
.siblings()
.contains('For')
.siblings()
.contains(votedDate)
.should('be.visible');
});
voteForProposal('for');
getGovernanceProposalDateFormatForSpecifiedDays(0, 'shortMonth').then(
(votedDate) => {
// 3001-VOTE-051
// 3001-VOTE-093
cy.contains('You voted:')
.siblings()
.contains('For')
.siblings()
.contains(votedDate)
.should('be.visible');
}
);
cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072
.contains('100.00%')
.and('be.visible');
@@ -162,69 +177,71 @@ describe(
cy.get(proposalVoteProgressAgainstTokens)
.contains('0.00')
.and('be.visible');
cy.get_proposal_information_from_table('Tokens for proposal')
.should('have.text', parseFloat(1).toFixed(2))
getProposalInformationFromTable('Tokens for proposal')
.should('have.text', (1).toFixed(2))
.and('be.visible');
cy.get_proposal_information_from_table('Tokens against proposal')
getProposalInformationFromTable('Tokens against proposal')
.should('have.text', '0.00')
.and('be.visible');
// 3001-VOTE-061
cy.get_proposal_information_from_table('Participation required')
.contains(0.001)
getProposalInformationFromTable('Participation required')
.contains('0.00%')
.should('be.visible');
// 3001-VOTE-066
cy.get_proposal_information_from_table('Majority Required') // 3001-VOTE-073
.contains(`${parseFloat(100).toFixed(2)}%`)
getProposalInformationFromTable('Majority Required') // 3001-VOTE-073
.contains(`${(66).toFixed(2)}%`)
.should('be.visible');
cy.get_proposal_information_from_table('Number of voting parties')
getProposalInformationFromTable('Number of voting parties')
.should('have.text', '1')
.and('be.visible');
cy.get(changeVoteButton).should('be.visible').click();
cy.vote_for_proposal('for');
voteForProposal('for');
// 3001-VOTE-064
cy.get_proposal_information_from_table('Tokens for proposal')
.should('have.text', parseFloat(1).toFixed(2))
getProposalInformationFromTable('Tokens for proposal')
.should('have.text', (1).toFixed(2))
.and('be.visible');
cy.get(changeVoteButton).should('be.visible').click();
cy.vote_for_proposal('against');
voteForProposal('against');
cy.get(proposalVoteProgressAgainstPercentage)
.contains('100.00%')
.and('be.visible');
cy.get_proposal_information_from_table('Tokens against proposal')
.should('have.text', parseFloat(1).toFixed(2))
getProposalInformationFromTable('Tokens against proposal')
.should('have.text', (1).toFixed(2))
.and('be.visible');
cy.get_proposal_information_from_table('Number of voting parties')
getProposalInformationFromTable('Number of voting parties')
.should('have.text', '1')
.and('be.visible');
});
// 3001-VOTE-042, 3001-VOTE-057, 3001-VOTE-058, 3001-VOTE-059, 3001-VOTE-060
it('Newly created proposal details - ability to increase associated tokens - by voting again after association', function () {
vegaWalletSetSpecifiedApprovalAmount('1000');
createRawProposal();
cy.get('@rawProposal').then((rawProposal) => {
cy.get_submitted_proposal_from_proposal_list(
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getSubmittedProposalFromProposalList(
rawProposal.rationale.title
)
.as('submittedProposal')
.within(() => cy.get(viewProposalButton).click());
).within(() => cy.get(viewProposalButton).click());
});
cy.vote_for_proposal('for');
voteForProposal('for');
// 3001-VOTE-079
cy.contains('You voted: For').should('be.visible');
cy.get(proposalVoteProgressForTokens).contains('1').and('be.visible');
cy.get_proposal_information_from_table('Total Supply')
getProposalInformationFromTable('Total Supply')
.invoke('text')
.then((totalSupply) => {
let tokensRequiredToAchieveResult = parseFloat(
(totalSupply.replace(/,/g, '') * 0.001) / 100
const tokensRequiredToAchieveResult = (
(Number(totalSupply.replace(/,/g, '')) * 0.001) /
100
).toFixed(2);
cy.ensure_specified_unstaked_tokens_are_associated(
ensureSpecifiedUnstakedTokensAreAssociated(
tokensRequiredToAchieveResult
);
cy.navigate_to_page_if_not_already_loaded('proposals');
cy.get('@submittedProposal').within(() =>
cy.get(viewProposalButton).click()
);
navigateTo(navigation.proposals);
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getSubmittedProposalFromProposalList(
rawProposal.rationale.title
).within(() => cy.get(viewProposalButton).click());
});
cy.get(proposalVoteProgressForPercentage)
.contains('100.00%')
.and('be.visible');
@@ -233,38 +250,36 @@ describe(
.and('be.visible');
// 3001-VOTE-065
cy.get(changeVoteButton).should('be.visible').click();
cy.vote_for_proposal('for');
voteForProposal('for');
cy.get(proposalVoteProgressForTokens)
.contains(tokensRequiredToAchieveResult)
.and('be.visible');
cy.get(proposalVoteProgressAgainstTokens)
.contains('0.00')
.and('be.visible');
cy.get_proposal_information_from_table(
'Total tokens voted percentage'
)
getProposalInformationFromTable('Total tokens voted percentage')
.should('have.text', '0.00%')
.and('be.visible');
cy.get_proposal_information_from_table('Tokens for proposal')
getProposalInformationFromTable('Tokens for proposal')
.should('have.text', tokensRequiredToAchieveResult)
.and('be.visible');
cy.get_proposal_information_from_table('Tokens against proposal')
getProposalInformationFromTable('Tokens against proposal')
.should('have.text', '0.00')
.and('be.visible');
cy.get_proposal_information_from_table('Number of voting parties')
getProposalInformationFromTable('Number of voting parties')
.should('have.text', '1')
.and('be.visible');
cy.get_proposal_information_from_table('Expected to pass')
getProposalInformationFromTable('Expected to pass')
.contains('👍')
.should('be.visible');
// 3001-VOTE-062
cy.get_proposal_information_from_table('Token majority met')
getProposalInformationFromTable('Token majority met')
.contains('👍')
.should('be.visible');
cy.get_proposal_information_from_table('Token participation met')
getProposalInformationFromTable('Token participation met')
.contains('👍')
.should('be.visible');
cy.get_proposal_information_from_table('Tokens for proposal')
getProposalInformationFromTable('Tokens for proposal')
.contains(tokensRequiredToAchieveResult)
.and('be.visible');
});
@@ -1,11 +1,22 @@
/// <reference types="cypress" />
import { associateTokenStartOfTests } from '../../support/governance.functions';
import {
navigateTo,
navigation,
waitForSpinner,
} from '../../support/common.functions';
import {
getProposalInformationFromTable,
voteForProposal,
} from '../../support/governance.functions';
import {
createUpdateNetworkProposalTxBody,
createFreeFormProposalTxBody,
} from '../../support/proposal.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
const proposalListItem = '[data-testid="proposals-list-item"]';
const closedProposals = '[data-testid="closed-proposals"]';
const proposalStatus = '[data-testid="proposal-status"]';
const viewProposalButton = '[data-testid="view-proposal-btn"]';
@@ -21,20 +32,16 @@ context(
function () {
before('Connect wallets and set approval', function () {
cy.visit('/');
cy.vega_wallet_set_specified_approval_amount('1000');
associateTokenStartOfTests();
cy.connectVegaWallet();
cy.ethereum_wallet_connect();
cy.ensure_specified_unstaked_tokens_are_associated(1);
cy.clearLocalStorage();
vegaWalletSetSpecifiedApprovalAmount('1000');
});
beforeEach('visit proposals', function () {
cy.clearLocalStorage();
cy.reload();
cy.wait_for_spinner();
waitForSpinner();
cy.connectVegaWallet();
cy.ethereum_wallet_connect();
cy.navigate_to('proposals');
ethereumWalletConnect();
navigateTo(navigation.proposals);
});
// 3001-VOTE-006
@@ -43,17 +50,18 @@ context(
cy.createMarket();
cy.reload();
cy.wait_for_spinner();
waitForSpinner();
cy.get(closedProposals).within(() => {
cy.contains(proposalTitle)
.parentsUntil('[data-testid="proposals-list-item"]')
.parentsUntil(proposalListItem)
.last()
.within(() => {
cy.get(proposalStatus).should('have.text', 'Enacted ');
cy.get(viewProposalButton).click();
});
});
cy.getByTestId('proposal-type').should('have.text', 'New market');
cy.get_proposal_information_from_table('State')
getProposalInformationFromTable('State')
.contains('Enacted')
.and('be.visible');
cy.get(votesTable).within(() => {
@@ -68,22 +76,23 @@ context(
const proposalTx = createUpdateNetworkProposalTxBody();
cy.VegaWalletSubmitProposal(proposalTx);
cy.navigate_to('proposals');
navigateTo(navigation.proposals);
cy.reload();
cy.wait_for_spinner();
waitForSpinner();
cy.get(openProposals).within(() => {
cy.contains(proposalTitle)
.parentsUntil('[data-testid="proposals-list-item"]')
.parentsUntil(proposalListItem)
.last()
.within(() => cy.get(viewProposalButton).click());
});
cy.get_proposal_information_from_table('State')
getProposalInformationFromTable('State')
.contains('Open')
.and('be.visible');
cy.vote_for_proposal('for');
cy.get_proposal_information_from_table('State') // 3001-VOTE-047
voteForProposal('for');
getProposalInformationFromTable('State') // 3001-VOTE-047
.contains('Passed', proposalTimeout)
.and('be.visible');
cy.get_proposal_information_from_table('State')
getProposalInformationFromTable('State')
.contains('Enacted', proposalTimeout)
.and('be.visible');
cy.get(votesTable).within(() => {
@@ -101,43 +110,45 @@ context(
const proposalTx = createFreeFormProposalTxBody();
cy.VegaWalletSubmitProposal(proposalTx);
cy.navigate_to('proposals');
navigateTo(navigation.proposals);
cy.reload();
cy.wait_for_spinner();
cy.get(openProposals).within(() => {
waitForSpinner();
cy.get(openProposals, { timeout: 6000 }).within(() => {
cy.contains(proposalTitle)
.parentsUntil('[data-testid="proposals-list-item"]')
.parentsUntil(proposalListItem)
.last()
.within(() => cy.get(viewProposalButton).click());
});
cy.get_proposal_information_from_table('State')
getProposalInformationFromTable('State')
.contains('Open')
.and('be.visible');
cy.vote_for_proposal('for');
cy.get_proposal_information_from_table('State')
voteForProposal('for');
getProposalInformationFromTable('State')
.contains('Enacted', proposalTimeout)
.and('be.visible');
});
// 3001-VOTE-048 3001-VOTE-049
// 3001-VOTE-048 3001-VOTE-049 3001-VOTE-050
it('Able to fail proposal due to lack of participation', function () {
const proposalTitle = 'Add New free form proposal with short enactment';
const proposalTx = createFreeFormProposalTxBody();
cy.VegaWalletSubmitProposal(proposalTx);
cy.navigate_to('proposals');
navigateTo(navigation.proposals);
cy.reload();
cy.wait_for_spinner();
waitForSpinner();
cy.get(openProposals).within(() => {
cy.contains(proposalTitle)
.parentsUntil('[data-testid="proposals-list-item"]')
.parentsUntil(proposalListItem)
.last()
.within(() => cy.get(viewProposalButton).click());
});
cy.get_proposal_information_from_table('State')
getProposalInformationFromTable('State')
.contains('Open')
.and('be.visible');
cy.get_proposal_information_from_table('State') // 3001-VOTE-047
getProposalInformationFromTable('State') // 3001-VOTE-047
.contains('Declined', proposalTimeout)
.and('be.visible');
cy.get_proposal_information_from_table('Rejection reason')
getProposalInformationFromTable('Rejection reason')
.contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED')
.and('be.visible');
});
@@ -1,22 +1,47 @@
/// <reference types="cypress" />
import {
createRawProposal,
createTenDigitUnixTimeStampForSpecifiedDays,
enterRawProposalBody,
enterUniqueFreeFormProposalBody,
generateFreeFormProposalTitle,
getProposalInformationFromTable,
getSubmittedProposalFromProposalList,
goToMakeNewProposal,
governanceProposalType,
voteForProposal,
waitForProposalSubmitted,
waitForProposalSync,
} from '../../support/governance.functions';
import { associateTokenStartOfTests } from '../../support/common.functions';
import {
verifyUnstakedBalance,
waitForSpinner,
navigateTo,
navigation,
closeDialog,
} from '../../support/common.functions';
import {
clickOnValidatorFromList,
closeStakingDialog,
ensureSpecifiedUnstakedTokensAreAssociated,
stakingPageDisassociateTokens,
stakingValidatorPageAddStake,
} from '../../support/staking.functions';
import {
vegaWalletSetSpecifiedApprovalAmount,
vegaWalletTeardown,
} from '../../support/wallet-teardown.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import type { testFreeformProposal } from '../../support/common-interfaces';
const vegaWalletUnstakedBalance =
'[data-testid="vega-wallet-balance-unstaked"]';
const vegaWalletStakedBalances =
'[data-testid="vega-wallet-balance-staked-validators"]';
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
const vegaWalletAssociatedBalance = '[data-testid="associated-amount"]';
const vegaWalletNameElement = '[data-testid="wallet-name"]';
const vegaWallet = '[data-testid="vega-wallet"]';
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
const dialogCloseButton = '[data-testid="dialog-close"]';
const viewProposalButton = '[data-testid="view-proposal-btn"]';
const rawProposalData = '[data-testid="proposal-data"]';
const minVoteButton = '[data-testid="min-vote"]';
@@ -40,30 +65,32 @@ context(
cy.visit('/');
cy.get_network_parameters().then((network_parameters) => {
cy.wrap(
network_parameters['spam.protection.proposal.min.tokens'] /
Number(network_parameters['spam.protection.proposal.min.tokens']) /
1000000000000000000
).as('minProposerBalance');
cy.wrap(
network_parameters['spam.protection.voting.min.tokens'] /
Number(network_parameters['spam.protection.voting.min.tokens']) /
1000000000000000000
).as('minVoterBalance');
cy.wrap(
network_parameters['governance.proposal.freeform.requiredMajority'] *
100
Number(
network_parameters['governance.proposal.freeform.requiredMajority']
) * 100
).as('requiredMajority');
});
cy.vega_wallet_set_specified_approval_amount('1000');
associateTokenStartOfTests();
vegaWalletSetSpecifiedApprovalAmount('1000');
cy.associateTokensToVegaWallet('1');
});
beforeEach('visit governance tab', function () {
cy.clearLocalStorage();
cy.reload();
cy.wait_for_spinner();
waitForSpinner();
cy.connectVegaWallet();
cy.ethereum_wallet_connect();
cy.ensure_specified_unstaked_tokens_are_associated(1);
cy.navigate_to_page_if_not_already_loaded('proposals');
ethereumWalletConnect();
ensureSpecifiedUnstakedTokensAreAssociated('1');
navigateTo(navigation.proposals);
});
it('Should be able to see that no proposals exist', function () {
@@ -80,7 +107,7 @@ context(
// 3002-PROP-003
it('Submit a proposal form - shows how many vega tokens are required to make a proposal', function () {
// 3002-PROP-005
cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET);
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
cy.contains(
`You must have at least 1 VEGA associated to make a proposal`
).should('be.visible');
@@ -88,7 +115,7 @@ context(
// 3002-PROP-011
it('Able to submit a valid freeform proposal - with minimum required tokens associated', function () {
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
goToMakeNewProposal(governanceProposalType.FREEFORM);
cy.get(minVoteButton).should('be.visible'); // 3002-PROP-008
cy.get(maxVoteButton).should('be.visible');
cy.get(votingDate).should('not.be.empty');
@@ -96,40 +123,31 @@ context(
'contain.text',
'we add 2 minutes of extra time'
);
cy.enter_unique_freeform_proposal_body(
'50',
generateFreeFormProposalTitle()
);
enterUniqueFreeFormProposalBody('50', generateFreeFormProposalTitle());
// 3002-PROP-012
// 3002-PROP-016
cy.wait_for_proposal_submitted();
waitForProposalSubmitted();
});
it('Able to submit a valid freeform proposal - with minimum required tokens associated - but also staked', function () {
cy.ensure_specified_unstaked_tokens_are_associated('2');
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', '2');
cy.navigate_to('validators');
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('2');
cy.close_staking_dialog();
ensureSpecifiedUnstakedTokensAreAssociated('2');
verifyUnstakedBalance(2);
navigateTo(navigation.validators);
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('2');
closeStakingDialog();
cy.get(vegaWalletStakedBalances, txTimeout).should('contain', '2');
cy.navigate_to('proposals');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body(
'50',
generateFreeFormProposalTitle()
);
cy.wait_for_proposal_submitted();
navigateTo(navigation.proposals);
goToMakeNewProposal(governanceProposalType.FREEFORM);
enterUniqueFreeFormProposalBody('50', generateFreeFormProposalTitle());
waitForProposalSubmitted();
});
it('Creating a proposal - proposal rejected - when closing time sooner than system default', function () {
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body(
'0.1',
generateFreeFormProposalTitle()
);
goToMakeNewProposal(governanceProposalType.FREEFORM);
enterUniqueFreeFormProposalBody('0.1', generateFreeFormProposalTitle());
cy.contains('Awaiting network confirmation', epochTimeout).should(
'not.exist'
);
@@ -139,8 +157,8 @@ context(
});
it('Creating a proposal - proposal rejected - when closing time later than system default', function () {
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body(
goToMakeNewProposal(governanceProposalType.FREEFORM);
enterUniqueFreeFormProposalBody(
'100000',
generateFreeFormProposalTitle()
);
@@ -154,22 +172,18 @@ context(
// 3001-VOTE-006
it('Creating a proposal - proposal rejected - able to access rejected proposals', function () {
cy.go_to_make_new_proposal(governanceProposalType.RAW);
cy.create_ten_digit_unix_timestamp_for_specified_days('1000').then(
(closingDateTimestamp) => {
cy.enter_raw_proposal_body(closingDateTimestamp).as('rawProposal');
}
);
goToMakeNewProposal(governanceProposalType.RAW);
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(1000));
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('proposals');
closeDialog();
waitForProposalSync();
navigateTo(navigation.proposals);
cy.get(rejectProposalsLink).click();
cy.get('@rawProposal').then((rawProposal) => {
cy.get_submitted_proposal_from_proposal_list(
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getSubmittedProposalFromProposalList(
rawProposal.rationale.title
).within(() => {
cy.contains('Rejected').should('be.visible');
@@ -177,79 +191,68 @@ context(
cy.get(viewProposalButton).click();
});
});
cy.get_proposal_information_from_table('State')
getProposalInformationFromTable('State')
.contains('Rejected')
.and('be.visible');
cy.get_proposal_information_from_table('Rejection reason')
getProposalInformationFromTable('Rejection reason')
.contains('PROPOSAL_ERROR_CLOSE_TIME_TOO_LATE')
.and('be.visible');
cy.get_proposal_information_from_table('Error details')
getProposalInformationFromTable('Error details')
.contains('proposal closing time too late')
.and('be.visible');
});
// 0005-ETXN-004
it('Unable to create a proposal - when no tokens are associated', function () {
cy.vega_wallet_teardown();
const errorMsg =
'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)';
vegaWalletTeardown();
cy.get(vegaWalletAssociatedBalance, txTimeout).contains(
'0.00',
txTimeout
);
cy.go_to_make_new_proposal(governanceProposalType.RAW);
cy.create_ten_digit_unix_timestamp_for_specified_days('8').then(
(closingDateTimestamp) => {
cy.enter_raw_proposal_body(closingDateTimestamp).as;
}
);
goToMakeNewProposal(governanceProposalType.RAW);
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError).should(
'have.text',
'Network error: the network blocked the transaction through the spam protection'
);
cy.get(dialogCloseButton).click();
cy.get(feedbackError).should('have.text', errorMsg);
closeDialog();
});
// 3002-PROP-009
it('Unable to create a proposal - when some but not enough tokens are associated', function () {
cy.ensure_specified_unstaked_tokens_are_associated(0.000001);
cy.go_to_make_new_proposal(governanceProposalType.RAW);
cy.create_ten_digit_unix_timestamp_for_specified_days('8').then(
(closingDateTimestamp) => {
cy.enter_raw_proposal_body(closingDateTimestamp);
}
);
const errorMsg =
'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)';
ensureSpecifiedUnstakedTokensAreAssociated('0.000001');
goToMakeNewProposal(governanceProposalType.RAW);
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError).should(
'have.text',
'Network error: the network blocked the transaction through the spam protection'
);
cy.get(dialogCloseButton).click();
cy.get(feedbackError).should('have.text', errorMsg);
closeDialog();
});
it('Unable to create a freeform proposal - when json parent section contains unexpected field', function () {
const errorMsg =
'Invalid params: the transaction does not use a valid Vega command: unknown field "unexpected" in vega.commands.v1.ProposalSubmission';
// 3001-VOTE-038 3002-PROP-013 3002-PROP-014
cy.go_to_make_new_proposal(governanceProposalType.RAW);
cy.create_ten_digit_unix_timestamp_for_specified_days('8').then(
(closingDateTimestamp) => {
cy.fixture('/proposals/raw.json').then((freeformProposal) => {
freeformProposal.terms.closingTimestamp = closingDateTimestamp;
freeformProposal.unexpected = `i shouldn't be here`;
let proposalPayload = JSON.stringify(freeformProposal);
cy.get(rawProposalData).type(proposalPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
}
);
goToMakeNewProposal(governanceProposalType.RAW);
cy.fixture('/proposals/raw.json').then((freeformProposal) => {
freeformProposal.terms.closingTimestamp =
createTenDigitUnixTimeStampForSpecifiedDays(8);
freeformProposal.unexpected = `i shouldn't be here`;
const proposalPayload = JSON.stringify(freeformProposal);
cy.get(rawProposalData).type(proposalPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError).should(
'have.text',
'Invalid params: the transaction is malformed'
);
cy.get(dialogCloseButton).click();
cy.get(feedbackError).should('have.text', errorMsg);
closeDialog();
cy.get(rawProposalData)
.invoke('val')
.should('contain', "i shouldn't be here");
@@ -257,71 +260,64 @@ context(
it('Unable to create a freeform proposal - when json terms section contains unexpected field', function () {
// 3001-VOTE-038
cy.go_to_make_new_proposal(governanceProposalType.RAW);
cy.create_ten_digit_unix_timestamp_for_specified_days('8').then(
(closingDateTimestamp) => {
cy.fixture('/proposals/raw.json').then((rawProposal) => {
rawProposal.terms.closingTimestamp = closingDateTimestamp;
rawProposal.terms.unexpectedField = `i shouldn't be here`;
let proposalPayload = JSON.stringify(rawProposal);
const errorMsg =
'Invalid params: the transaction does not use a valid Vega command: unknown field "unexpectedField" in vega.ProposalTerms';
cy.get(rawProposalData).type(proposalPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
}
);
goToMakeNewProposal(governanceProposalType.RAW);
cy.fixture('/proposals/raw.json').then((rawProposal) => {
rawProposal.terms.closingTimestamp =
createTenDigitUnixTimeStampForSpecifiedDays(8);
rawProposal.terms.unexpectedField = `i shouldn't be here`;
const proposalPayload = JSON.stringify(rawProposal);
cy.get(rawProposalData).type(proposalPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError).should(
'have.text',
'Invalid params: the transaction is malformed'
);
cy.get(dialogCloseButton).click();
cy.get(feedbackError).should('have.text', errorMsg);
closeDialog();
});
// 1005-PROP-009
it.skip(
'Unable to vote on a freeform proposal - when some but not enough vega associated',
{ tags: '@smoke' },
function () {
const proposalTitle = generateFreeFormProposalTitle();
it('Unable to vote on a freeform proposal - when some but not enough vega associated', function () {
const proposalTitle = generateFreeFormProposalTitle();
cy.ensure_specified_unstaked_tokens_are_associated(1);
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50', proposalTitle);
cy.wait_for_proposal_submitted();
cy.staking_page_disassociate_tokens('0.0001');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance).should('have.length', 1);
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'0.9999'
);
});
cy.navigate_to('proposals');
cy.get_submitted_proposal_from_proposal_list(proposalTitle).within(() =>
cy.get(viewProposalButton).click()
ensureSpecifiedUnstakedTokensAreAssociated('1');
goToMakeNewProposal(governanceProposalType.FREEFORM);
enterUniqueFreeFormProposalBody('50', proposalTitle);
waitForProposalSubmitted();
stakingPageDisassociateTokens('0.0001');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'0.9999'
);
cy.contains('Vote breakdown').should('be.visible', {
timeout: 10000,
});
cy.get(voteButtons).should('not.exist');
cy.getByTestId('min-proposal-requirements').should(
'have.text',
`You must have at least ${this.minVoterBalance} VEGA associated to vote on this proposal`
);
}
);
});
navigateTo(navigation.proposals);
getSubmittedProposalFromProposalList(proposalTitle).within(() =>
cy.get(viewProposalButton).click()
);
cy.contains('Vote breakdown').should('be.visible', {
timeout: 10000,
});
cy.get(voteButtons).should('not.exist');
cy.getByTestId('min-proposal-requirements').should(
'have.text',
`You must have at least ${this.minVoterBalance} VEGA associated to vote on this proposal`
);
});
it('Unable to vote on a proposal - when vega wallet disconnected - option to connect from within', function () {
createRawProposal();
cy.get('[data-testid="manage-vega-wallet"]').click();
cy.get('[data-testid="manage-vega-wallet"]:visible').click();
cy.get('[data-testid="disconnect"]').click();
cy.get('@rawProposal').then((rawProposal) => {
cy.get_submitted_proposal_from_proposal_list(
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getSubmittedProposalFromProposalList(
rawProposal.rationale.title
).within(() => cy.get(viewProposalButton).click());
});
@@ -339,7 +335,7 @@ context(
'1.00',
txTimeout
);
cy.vote_for_proposal('against');
voteForProposal('against');
// 3001-VOTE-079
cy.contains('You voted: Against').should('be.visible');
});
@@ -1,3 +1,23 @@
import {
closeDialog,
navigateTo,
navigation,
waitForSpinner,
} from '../../support/common.functions';
import {
getProposalInformationFromTable,
goToMakeNewProposal,
voteForProposal,
waitForProposalSubmitted,
} from '../../support/governance.functions';
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import {
vegaWalletSetSpecifiedApprovalAmount,
vegaWalletTeardown,
} from '../../support/wallet-teardown.functions';
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions';
const proposalListItem = '[data-testid="proposals-list-item"]';
const openProposals = '[data-testid="open-proposals"]';
const proposalType = '[data-testid="proposal-type"]';
@@ -20,7 +40,6 @@ const maxVoteDeadline = '[data-testid="max-vote"]';
const minValidationDeadline = '[data-testid="min-validation"]';
const minEnactDeadline = '[data-testid="min-enactment"]';
const maxEnactDeadline = '[data-testid="max-enactment"]';
const dialogCloseButton = '[data-testid="dialog-close"]';
const inputError = '[data-testid="input-error-text"]';
const enactmentDeadlineError =
'[data-testid="enactment-before-voting-deadline"]';
@@ -29,7 +48,10 @@ const feedbackError = '[data-testid="Error"]';
const viewProposalBtn = 'view-proposal-btn';
const liquidityVoteStatus = 'liquidity-votes-status';
const tokenVoteStatus = 'token-votes-status';
const proposalTermsSection = 'proposal';
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
const fUSDCId =
'816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc';
const epochTimeout = Cypress.env('epochTimeout');
const proposalTimeout = { timeout: 14000 };
@@ -49,22 +71,23 @@ context(
{ tags: '@slow' },
function () {
before('connect wallets and set approval limit', function () {
cy.createMarket();
cy.visit('/');
cy.vega_wallet_set_specified_approval_amount('1000');
vegaWalletSetSpecifiedApprovalAmount('1000');
});
beforeEach('visit governance tab', function () {
cy.clearLocalStorage();
cy.reload();
cy.wait_for_spinner();
waitForSpinner();
cy.connectVegaWallet();
cy.ethereum_wallet_connect();
cy.ensure_specified_unstaked_tokens_are_associated('1');
cy.navigate_to('proposals');
ethereumWalletConnect();
cy.createMarket();
ensureSpecifiedUnstakedTokensAreAssociated('1');
navigateTo(navigation.proposals);
});
it('Able to submit valid update network parameter proposal', function () {
cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER);
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
// 3002-PROP-006
cy.get(newProposalTitle).type('Test update network parameter proposal');
// 3002-PROP-007
@@ -78,12 +101,12 @@ context(
cy.get(currentParameterValue).should('have.value', '2s');
cy.get(newProposedParameterValue).type('5s'); // 3007-PNEC-003
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.wait_for_proposal_submitted();
waitForProposalSubmitted();
});
it('Unable to submit network parameter with missing/invalid fields', function () {
cy.navigate_to_page_if_not_already_loaded('proposals');
cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER);
navigateTo(navigation.proposals);
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.get(inputError).should('have.length', 3);
cy.get(newProposalTitle).type(
@@ -108,7 +131,7 @@ context(
it('Able to download network param proposal json', function () {
const downloadFolder = './cypress/downloads/';
cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER);
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
cy.log('Download proposal file');
cy.get(proposalDownloadBtn)
.should('be.visible')
@@ -156,8 +179,8 @@ context(
});
it('Unable to submit network parameter proposal with vote deadline above enactment deadline', function () {
cy.navigate_to_page_if_not_already_loaded('proposals');
cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER);
navigateTo(navigation.proposals);
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
cy.get(newProposalTitle).type('Test update network parameter proposal');
cy.get(newProposalDescription).type('invalid deadlines');
cy.get(proposalParameterSelect).select(
@@ -175,36 +198,39 @@ context(
'have.text',
'Invalid params: proposal_submission.terms.closing_timestamp (cannot be after enactment time)'
);
cy.get(dialogCloseButton).click();
closeDialog();
cy.get(minVoteDeadline).click();
cy.get(enactmentDeadlineError).should('not.exist');
});
// 3003-PMAN-001
it('Able to submit valid new market proposal', function () {
cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET);
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
cy.get(newProposalTitle).type('Test new market proposal');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
let newMarketPayload = JSON.stringify(newMarketProposal);
const newMarketPayload = JSON.stringify(newMarketProposal);
cy.get(newProposalTerms).type(newMarketPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.wait_for_proposal_submitted();
waitForProposalSubmitted();
});
it('Unable to submit new market proposal with missing/invalid fields', function () {
cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET);
const errorMsg =
'Invalid params: the transaction does not use a valid Vega command: unknown field "invalid" in vega.NewMarket';
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.get(inputError).should('have.length', 3);
cy.get(newProposalTitle).type('Test new market proposal');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
newMarketProposal.invalid = 'I am an invalid field';
let newMarketPayload = JSON.stringify(newMarketProposal);
const newMarketPayload = JSON.stringify(newMarketProposal);
cy.get(newProposalTerms).type(newMarketPayload, {
parseSpecialCharSequences: false,
delay: 2,
@@ -212,21 +238,18 @@ context(
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError).should(
'have.text',
'Invalid params: the transaction is not a valid Vega command: unknown field "invalid" in vega.NewMarket'
);
cy.get(feedbackError).should('have.text', errorMsg);
});
// Will fail if run after 'Able to submit update market proposal and vote for proposal'
// 3002-PROP-022
it('Unable to submit update market proposal without equity-like share in the market', function () {
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET);
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
cy.get(newProposalTitle).type('Test update market proposal - rejected');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.get(proposalMarketSelect).select('Test market 1');
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
let newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
parseSpecialCharSequences: false,
delay: 2,
@@ -237,23 +260,23 @@ context(
cy.getByTestId('dialog-content')
.find('p')
.should('have.text', 'PROPOSAL_ERROR_INSUFFICIENT_EQUITY_LIKE_SHARE');
cy.ensure_specified_unstaked_tokens_are_associated('1');
ensureSpecifiedUnstakedTokensAreAssociated('1');
});
// 3002-PROP-020
it('Unable to submit update market proposal without minimum amount of tokens', function () {
cy.vega_wallet_teardown();
cy.vega_wallet_faucet_assets_without_check(
'fUSDC',
vegaWalletTeardown();
vegaWalletFaucetAssetsWithoutCheck(
fUSDCId,
'1000000',
vegaWalletPublicKey
);
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET);
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
cy.get(newProposalTitle).type('Test update market proposal - rejected');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.get(proposalMarketSelect).select('Test market 1');
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
let newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
parseSpecialCharSequences: false,
delay: 2,
@@ -267,14 +290,14 @@ context(
);
});
// 3001-VOTE-092
// 3001-VOTE-092 3004-PMAC-001
it('Able to submit update market proposal and vote for proposal', function () {
cy.vega_wallet_faucet_assets_without_check(
'fUSDC',
vegaWalletFaucetAssetsWithoutCheck(
fUSDCId,
'1000000',
vegaWalletPublicKey
);
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET);
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
cy.get(newProposalTitle).type('Test update market proposal');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.get(proposalMarketSelect).select('Test market 1');
@@ -282,24 +305,28 @@ context(
cy.get('dd').eq(0).should('have.text', 'Test market 1');
cy.get('dd').eq(1).should('have.text', 'TEST.24h');
cy.get('dd').eq(2).should('not.be.empty');
cy.get('dd').eq(2).invoke('text').as('EnactedMarketId');
cy.get('dd')
.eq(2)
.invoke('text')
.as('EnactedMarketId', { type: 'static' });
});
cy.get('@EnactedMarketId').then((marketId) => {
cy.VegaWalletSubmitLiquidityProvision(marketId, '1');
cy.VegaWalletSubmitLiquidityProvision(String(marketId), '1');
});
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
let newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.wait_for_proposal_submitted();
cy.navigate_to('proposals');
waitForProposalSubmitted();
navigateTo(navigation.proposals);
cy.get('@EnactedMarketId').then((marketId) => {
cy.contains(marketId)
cy.contains(String(marketId))
.parentsUntil(proposalListItem)
.last()
.within(() => {
cy.getByTestId(viewProposalBtn).click();
});
@@ -312,7 +339,7 @@ context(
'contain.text',
'Currently expected to fail'
);
cy.vote_for_proposal('for');
voteForProposal('for');
cy.getByTestId(liquidityVoteStatus).should(
'contain.text',
'Currently expected to pass'
@@ -321,18 +348,19 @@ context(
'contain.text',
'Currently expected to pass'
);
cy.get_proposal_information_from_table('Expected to pass')
.contains('👍 by Token vote')
getProposalInformationFromTable('Expected to pass')
.contains('👍 by token vote')
.should('be.visible');
});
// 3001-VOTE-026 3001-VOTE-027 3001-VOTE-028 3001-VOTE-095 3001-VOTE-096 3005-PASN-001
it('Able to submit new asset proposal using min deadlines', function () {
cy.go_to_make_new_proposal(governanceProposalType.NEW_ASSET);
cy.get(newProposalTitle).type('Test new asset proposal');
const proposalTitle = 'Test new asset proposal';
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
cy.get(newProposalTitle).type(proposalTitle);
cy.get(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/new-asset').then((newAssetProposal) => {
let newAssetPayload = JSON.stringify(newAssetProposal);
const newAssetPayload = JSON.stringify(newAssetProposal);
cy.get(newProposalTerms).type(newAssetPayload, {
parseSpecialCharSequences: false,
delay: 2,
@@ -348,20 +376,34 @@ context(
cy.contains('Proposal waiting for node vote', proposalTimeout).should(
'be.visible'
);
cy.get(dialogCloseButton).click();
closeDialog();
cy.get(newProposalSubmitButton).should('be.visible').click();
// cannot submit a proposal with ERC20 address already in use
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
cy.getByTestId('dialog-content').within(() => {
cy.get('p').should(
'have.text',
'PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE'
);
cy.getByTestId('dialog-content')
.last()
.within(() => {
cy.get('p').should(
'have.text',
'PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE'
);
});
closeDialog();
navigateTo(navigation.proposals);
cy.contains(proposalTitle)
.parentsUntil(proposalListItem)
.last()
.within(() => {
cy.getByTestId(viewProposalBtn).click();
});
cy.getByTestId(proposalTermsSection).within(() => {
cy.contains('USDT Coin').should('be.visible');
cy.contains('USDT').should('be.visible');
});
});
it('Unable to submit new asset proposal with missing/invalid fields', function () {
cy.go_to_make_new_proposal(governanceProposalType.NEW_ASSET);
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.get(inputError).should('have.length', 3);
cy.get(newProposalTitle).type('Invalid new asset proposal');
@@ -377,38 +419,45 @@ context(
const assetId =
'ebcd94151ae1f0d39a4bde3b21a9c7ae81a80ea4352fb075a92e07608d9c953d';
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_ASSET);
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
enterUpdateAssetProposalDetails();
cy.get(minVoteDeadline).click();
cy.get(minEnactDeadline).click();
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.wait_for_proposal_submitted();
cy.navigate_to('proposals');
waitForProposalSubmitted();
navigateTo(navigation.proposals);
cy.get(openProposals).within(() => {
cy.get(proposalType)
.contains('Update asset')
.parentsUntil(proposalListItem)
.last()
.within(() => {
cy.get(proposalDetails).should('contain.text', assetId); // 3001-VOTE-029
cy.getByTestId(viewProposalBtn).click();
});
});
cy.get_proposal_information_from_table('Proposed enactment') // 3001-VOTE-044
getProposalInformationFromTable('Proposed enactment') // 3001-VOTE-044
.invoke('text')
.should('not.be.empty');
// 3001-VOTE-030 3001-VOTE-031
cy.getByTestId(proposalTermsSection).within(() => {
cy.contains('UpdateAsset').should('be.visible');
cy.contains('UpdateERC20').should('be.visible');
cy.contains('"lifetimeLimit": "10"').should('be.visible');
});
});
it('Able to submit update asset proposal using max deadline', function () {
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_ASSET);
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
enterUpdateAssetProposalDetails();
cy.get(maxVoteDeadline).click();
cy.get(maxEnactDeadline).click();
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.wait_for_proposal_submitted();
waitForProposalSubmitted();
});
it('Unable to submit edit asset proposal with missing/invalid fields', function () {
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_ASSET);
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.get(inputError).should('have.length', 3);
});
@@ -428,7 +477,7 @@ context(
cy.get(newProposalTitle).type('Test update asset proposal');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/update-asset').then((newAssetProposal) => {
let newAssetPayload = JSON.stringify(newAssetProposal);
const newAssetPayload = JSON.stringify(newAssetProposal);
cy.get(newProposalTerms).type(newAssetPayload, {
parseSpecialCharSequences: false,
delay: 2,
@@ -1,162 +0,0 @@
import {
createFreeformProposal,
createRawProposal,
generateFreeFormProposalTitle,
governanceProposalType,
} from '../../support/governance.functions';
const proposalDetailsTitle = '[data-testid="proposal-title"]';
const openProposals = '[data-testid="open-proposals"]';
const voteStatus = '[data-testid="vote-status"]';
const viewProposalButton = '[data-testid="view-proposal-btn"]';
describe('Governance flow for proposal list', { tags: '@slow' }, function () {
before('connect wallets and set approval limit', function () {
cy.vega_wallet_set_specified_approval_amount('1000');
cy.visit('/');
});
beforeEach('visit proposals tab', function () {
cy.reload();
cy.wait_for_spinner();
cy.connectVegaWallet();
cy.ethereum_wallet_connect();
cy.ensure_specified_unstaked_tokens_are_associated(1);
cy.navigate_to_page_if_not_already_loaded('proposals');
});
it('Newly created proposals list - proposals closest to closing date appear higher in list', function () {
const minCloseDays = 2;
const maxCloseDays = 3;
// 3001-VOTE-005
let proposalDays = [
minCloseDays + 1,
maxCloseDays,
minCloseDays + 3,
minCloseDays + 2,
];
for (var index = 0; index < proposalDays.length; index++) {
cy.go_to_make_new_proposal(governanceProposalType.RAW);
cy.create_ten_digit_unix_timestamp_for_specified_days(
proposalDays[index]
).then((closingDateTimestamp) => {
cy.enter_raw_proposal_body(closingDateTimestamp);
});
cy.wait_for_proposal_submitted();
cy.wait_for_proposal_sync();
}
let arrayOfProposals = [];
cy.navigate_to('proposals');
cy.get(proposalDetailsTitle)
.each((proposalTitleElement) => {
arrayOfProposals.push(proposalTitleElement.text());
})
.then(() => {
cy.get_sort_order_of_supplied_array(arrayOfProposals).should(
'equal',
'descending'
);
});
});
it('Newly created proposals list - able to filter by proposerID to show it in list', function () {
const proposerId = Cypress.env('vegaWalletPublicKey');
const proposalTitle = generateFreeFormProposalTitle();
createFreeformProposal(proposalTitle);
cy.get_proposal_id_from_list(proposalTitle);
cy.get('@proposalIdText').then((proposalId) => {
cy.get('[data-testid="set-proposals-filter-visible"]').click();
cy.get('[data-testid="filter-input"]').type(proposerId);
cy.get(`#${proposalId}`).should('contain', proposalId);
});
});
it('Newly created proposals list - shows title and portion of summary', function () {
createRawProposal(this.minProposerBalance); // 3001-VOTE-052
cy.get('@rawProposal').then((rawProposal) => {
cy.get_proposal_id_from_list(rawProposal.rationale.title);
cy.get('@proposalIdText').then((proposalId) => {
cy.get(openProposals).within(() => {
// 3001-VOTE-008
// 3001-VOTE-034
cy.get(`#${proposalId}`)
// 3001-VOTE-097
.should('contain', rawProposal.rationale.title)
.and('be.visible');
cy.get(`#${proposalId}`)
.should(
'contain',
rawProposal.rationale.description.substring(0, 59)
)
.and('be.visible');
});
});
});
});
it('Newly created proposals list - shows open proposals in an open state', function () {
// 3001-VOTE-004
// 3001-VOTE-035
createRawProposal(this.minProposerBalance);
cy.get('@rawProposal').then((rawProposal) => {
cy.get_submitted_proposal_from_proposal_list(
rawProposal.rationale.title
).within(() => {
cy.get(viewProposalButton).should('be.visible').click();
});
cy.get('@proposalIdText').then((proposalId) => {
cy.get_proposal_information_from_table('ID')
.contains(proposalId)
.and('be.visible');
});
cy.get_proposal_information_from_table('State')
.contains('Open')
.and('be.visible');
cy.get_proposal_information_from_table('Type')
.contains('Freeform')
.and('be.visible');
});
});
// 3001-VOTE-071
it('Newly created freeform proposals list - shows proposal participation - both met and not', function () {
const proposalTitle = generateFreeFormProposalTitle();
const requiredParticipation = 0.001;
createFreeformProposal(proposalTitle);
cy.get_submitted_proposal_from_proposal_list(proposalTitle)
.as('submittedProposal')
.within(() => {
// 3001-VOTE-039
cy.get(voteStatus).should('have.text', 'Participation not reached');
cy.get(viewProposalButton).click();
});
cy.vote_for_proposal('for');
cy.get_proposal_information_from_table('Total Supply')
.invoke('text')
.then((totalSupply) => {
let tokensRequiredToAchieveResult = parseFloat(
(totalSupply.replace(/,/g, '') * requiredParticipation) / 100
).toFixed(2);
cy.ensure_specified_unstaked_tokens_are_associated(
tokensRequiredToAchieveResult
);
cy.navigate_to_page_if_not_already_loaded('proposals');
cy.get('@submittedProposal').within(() =>
cy.get(viewProposalButton).click()
);
cy.get_proposal_information_from_table('Token participation met')
.contains('👍')
.should('be.visible');
cy.navigate_to('proposals');
cy.get('@submittedProposal').within(() =>
cy.get(voteStatus).should('have.text', 'Set to pass')
);
});
});
});
@@ -0,0 +1,151 @@
import type { testFreeformProposal } from '../../support/common-interfaces';
import {
navigateTo,
navigation,
waitForSpinner,
} from '../../support/common.functions';
import {
createFreeformProposal,
createRawProposal,
createTenDigitUnixTimeStampForSpecifiedDays,
enterRawProposalBody,
generateFreeFormProposalTitle,
getProposalIdFromList,
getProposalInformationFromTable,
getSubmittedProposalFromProposalList,
goToMakeNewProposal,
governanceProposalType,
voteForProposal,
waitForProposalSubmitted,
waitForProposalSync,
} from '../../support/governance.functions';
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
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 () {
before('connect wallets and set approval limit', function () {
vegaWalletSetSpecifiedApprovalAmount('1000');
cy.visit('/');
});
beforeEach('visit proposals tab', function () {
cy.clearLocalStorage();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
ethereumWalletConnect();
ensureSpecifiedUnstakedTokensAreAssociated('1');
navigateTo(navigation.proposals);
});
it('Newly created proposals list - proposals closest to closing date appear higher in list', function () {
// 3001-VOTE-005
const proposalDays = [364, 50, 2];
for (let index = 0; index < proposalDays.length; index++) {
goToMakeNewProposal(governanceProposalType.RAW);
enterRawProposalBody(
createTenDigitUnixTimeStampForSpecifiedDays(proposalDays[index])
);
waitForProposalSubmitted();
waitForProposalSync();
}
navigateTo(navigation.proposals);
cy.get(openProposals).within(() => {
cy.get(proposalClosingDate).first().should('contain.text', 'year');
cy.get(proposalClosingDate).should('contain.text', 'months');
cy.get(proposalClosingDate)
.last()
.invoke('text')
.should('match', /days|minutes/);
});
});
it('Newly created proposals list - able to filter by proposerID to show it in list', function () {
const proposerId = Cypress.env('vegaWalletPublicKey');
const proposalTitle = generateFreeFormProposalTitle();
createFreeformProposal(proposalTitle);
getProposalIdFromList(proposalTitle);
cy.get('@proposalIdText').then((proposalId) => {
cy.get('[data-testid="set-proposals-filter-visible"]').click();
cy.get('[data-testid="filter-input"]').type(proposerId);
cy.get(`#${proposalId}`).should('contain', proposalId);
});
});
it('Newly created proposals list - shows title and portion of summary', function () {
createRawProposal(this.minProposerBalance); // 3001-VOTE-052
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalIdFromList(rawProposal.rationale.title);
cy.get('@proposalIdText').then((proposalId) => {
cy.get(openProposals).within(() => {
// 3001-VOTE-008
// 3001-VOTE-034
cy.get(`#${proposalId}`)
// 3001-VOTE-097
.should('contain', rawProposal.rationale.title)
.and('be.visible');
cy.get(`#${proposalId}`)
.should(
'contain',
rawProposal.rationale.description.substring(0, 59)
)
.and('be.visible');
});
});
});
});
it('Newly created proposals list - shows open proposals in an open state', function () {
// 3001-VOTE-004
// 3001-VOTE-035
createRawProposal(this.minProposerBalance);
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getSubmittedProposalFromProposalList(rawProposal.rationale.title).within(
() => {
cy.get(viewProposalButton).should('be.visible').click();
}
);
cy.get('@proposalIdText').then((proposalId) => {
getProposalInformationFromTable('ID')
.contains(String(proposalId))
.and('be.visible');
});
getProposalInformationFromTable('State')
.contains('Open')
.and('be.visible');
getProposalInformationFromTable('Type')
.contains('Freeform')
.and('be.visible');
});
});
// 3001-VOTE-071
it('Newly created freeform proposals list - shows proposal participation - both met and not', function () {
const proposalTitle = generateFreeFormProposalTitle();
createFreeformProposal(proposalTitle);
getSubmittedProposalFromProposalList(proposalTitle).within(() => {
// 3001-VOTE-039
cy.get(voteStatus).should('have.text', 'Participation not reached');
cy.get(viewProposalButton).click();
});
voteForProposal('for');
navigateTo(navigation.proposals);
getSubmittedProposalFromProposalList(proposalTitle).within(() => {
cy.get(voteStatus).should('have.text', 'Set to pass');
cy.get(viewProposalButton).click();
});
getProposalInformationFromTable('Token participation met')
.contains('👍')
.should('be.visible');
});
});
@@ -1,3 +1,21 @@
import {
navigateTo,
navigation,
waitForSpinner,
} from '../../support/common.functions';
import {
clickOnValidatorFromList,
closeStakingDialog,
stakingPageAssociateTokens,
stakingValidatorPageAddStake,
waitForBeginningOfEpoch,
} from '../../support/staking.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import {
depositAsset,
vegaWalletTeardown,
} from '../../support/wallet-teardown.functions';
const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de';
const vegaWalletUnstakedBalance =
'[data-testid="vega-wallet-balance-unstaked"]';
@@ -7,30 +25,31 @@ const rewardsTimeOut = { timeout: 60000 };
context('rewards - flow', { tags: '@slow' }, function () {
before('set up environment to allow rewards', function () {
cy.clearLocalStorage();
cy.visit('/');
cy.wait_for_spinner();
cy.deposit_asset(vegaAssetAddress, '1000');
waitForSpinner();
depositAsset(vegaAssetAddress, '1000', 18);
cy.validatorsSelfDelegate();
cy.ethereum_wallet_connect();
ethereumWalletConnect();
cy.connectVegaWallet();
topUpRewardsPool();
cy.navigate_to('validators');
cy.vega_wallet_teardown();
cy.staking_page_associate_tokens('6000');
cy.VegaWalletTopUpRewardsPool(30, 200);
navigateTo(navigation.validators);
vegaWalletTeardown();
stakingPageAssociateTokens('6000');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
'6,000.0',
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('3000');
cy.close_staking_dialog();
cy.navigate_to('validators');
cy.click_on_validator_from_list(1);
cy.staking_validator_page_add_stake('3000');
cy.close_staking_dialog();
cy.navigate_to('rewards');
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('3000');
closeStakingDialog();
navigateTo(navigation.validators);
clickOnValidatorFromList(1);
stakingValidatorPageAddStake('3000');
closeStakingDialog();
navigateTo(navigation.rewards);
});
it('Should display rewards per epoch', function () {
@@ -38,7 +57,7 @@ context('rewards - flow', { tags: '@slow' }, function () {
cy.getByTestId(rewardsTable)
.first()
.within(() => {
cy.getByTestId('asset').should('have.text', 'Vega');
cy.getByTestId('asset', rewardsTimeOut).should('have.text', 'Vega');
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD').should('have.text', '1');
cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE').should(
'have.text',
@@ -54,7 +73,7 @@ context('rewards - flow', { tags: '@slow' }, function () {
.within(() => {
cy.get('h2').first().invoke('text').as('epochNumber');
});
cy.wait_for_beginning_of_epoch();
waitForBeginningOfEpoch();
cy.get('@epochNumber').then((epochNumber) => {
cy.getByTestId(rewardsTable)
.first()
@@ -75,7 +94,7 @@ context('rewards - flow', { tags: '@slow' }, function () {
.within(() => {
cy.get('h2').first().should('contain.text', 'EPOCH');
cy.getByTestId('individual-rewards-asset').should('have.text', 'Vega');
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD')
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD', rewardsTimeOut)
.should('contain.text', '0.4415')
.and('contain.text', '(44.15%)');
cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE')
@@ -84,20 +103,4 @@ context('rewards - flow', { tags: '@slow' }, function () {
cy.getByTestId('total').should('have.text', '0.4419');
});
});
function topUpRewardsPool() {
// Must ensure that test wallet contains assets already and that the tests are within the start and end epochs
cy.exec(
`vega wallet transaction send --wallet ${Cypress.env(
'vegaWalletName'
)} --pubkey ${Cypress.env(
'vegaWalletPublicKey'
)} -p "./src/fixtures/wallet/passphrase" --network DV '{"transfer":{"fromAccountType":4,"toAccountType":12,"to":"0000000000000000000000000000000000000000000000000000000000000000","asset":"b4f2726571fbe8e33b442dc92ed2d7f0d810e21835b7371a7915a365f07ccd9b","amount":"1000000000000000000","recurring":{"startEpoch":30, "endEpoch": 200, "factor":"1"}}}' --home ${Cypress.env(
'vegaWalletLocation'
)}`,
{ failOnNonZeroExit: false }
)
.its('stderr')
.should('contain', '');
}
});
@@ -1,876 +0,0 @@
/// <reference types="cypress" />
const stakeValidatorListTotalStake = '[col-id="stake"] > div > span';
const stakeValidatorListTotalShare = '[col-id="stakeShare"] > div > span';
const stakeValidatorListValidatorStake = '[col-id="stake"] > div > span';
const stakeRemoveStakeRadioButton = '[data-testid="remove-stake-radio"]';
const stakeTokenAmountInputBox = '[data-testid="token-amount-input"]';
const stakeTokenSubmitButton = '[data-testid="token-input-submit-button"]';
const stakeNextEpochValue = '[data-testid="stake-next-epoch"]';
const stakeThisEpochValue = '[data-testid="stake-this-epoch"]';
const stakeAddStakeRadioButton = '[data-testid="add-stake-radio"]';
const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]';
const totalStake = '[data-testid="total-stake"]';
const stakeShare = '[data-testid="stake-percentage"]';
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
const vegaWalletUnstakedBalance =
'[data-testid="vega-wallet-balance-unstaked"]:visible';
const vegaWalletStakedBalances =
'[data-testid="vega-wallet-balance-staked-validators"]';
const ethWalletAssociatedBalances =
'[data-testid="eth-wallet-associated-balances"]';
const ethWalletTotalAssociatedBalance =
'[data-testid="currency-locked"]:visible';
const ethWalletContainer = '[data-testid="ethereum-wallet"]:visible';
const vegaWallet = '[data-testid="vega-wallet"]';
const partValidatorId = '…';
const txTimeout = Cypress.env('txTimeout');
const epochTimeout = Cypress.env('epochTimeout');
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.visit('/');
cy.vega_wallet_set_specified_approval_amount('1000');
});
describe('Eth wallet - contains VEGA tokens', function () {
beforeEach(
'teardown wallet & drill into a specific validator',
function () {
cy.reload();
cy.wait_for_spinner();
cy.connectVegaWallet();
cy.ethereum_wallet_connect();
cy.vega_wallet_teardown();
cy.navigate_to('validators');
}
);
it('Able to stake against a validator - using vega from wallet', function () {
cy.staking_page_associate_tokens('3');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('3.0', txTimeout)
.should('be.visible');
cy.get(ethWalletAssociatedBalances, txTimeout)
.contains(vegaWalletPublicKeyShort, txTimeout)
.parent()
.should('contain', 3.0, txTimeout);
cy.get('button').contains('Select a validator to nominate').click();
// 2001-STKE-031
cy.click_on_validator_from_list(0);
// 2001-STKE-033, 2001-STKE-034, 2001-STKE-037
cy.staking_validator_page_add_stake('2');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
1.0,
txTimeout
);
// 2001-STKE-039
cy.get(vegaWalletStakedBalances, txTimeout)
.should('contain', 2.0, txTimeout)
.and('contain', partValidatorId);
cy.get(stakeNextEpochValue, epochTimeout) // 2001-STKE-016 2001-STKE-038
.contains(2.0, epochTimeout)
.should('be.visible');
cy.get(stakeThisEpochValue, epochTimeout) // 2001-STKE-013
.contains(2.0, epochTimeout)
.should('be.visible');
cy.close_staking_dialog();
cy.navigate_to('validators');
// 2002-SINC-007
cy.validate_validator_list_total_stake_and_share(
'0',
'2.00',
'100.00%'
);
});
it('Able to stake against a validator - using vega from vesting contract', function () {
cy.staking_page_associate_tokens('3', { type: 'contract' });
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('3.0', txTimeout)
.should('be.visible');
cy.get(ethWalletAssociatedBalances, txTimeout)
.contains(vegaWalletPublicKeyShort, txTimeout)
.parent()
.should('contain', 3.0, txTimeout);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('2');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
1.0,
txTimeout
);
cy.get(vegaWalletStakedBalances, txTimeout)
.should('contain', 2.0, txTimeout)
.and('contain', partValidatorId);
cy.get(stakeNextEpochValue, epochTimeout)
.contains(2.0, epochTimeout)
.should('be.visible');
cy.get(stakeThisEpochValue, epochTimeout)
.contains(2.0, epochTimeout)
.should('be.visible');
cy.close_staking_dialog();
cy.navigate_to('validators');
cy.validate_validator_list_total_stake_and_share(
'0',
'2.00',
'100.00%'
);
});
it('Able to stake against a validator - using vega from both wallet and vesting contract', function () {
cy.staking_page_associate_tokens('3', { type: 'contract' });
cy.navigate_to('validators');
cy.staking_page_associate_tokens('4', { type: 'wallet' });
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
7.0,
txTimeout
);
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('3.0', txTimeout)
.should('be.visible');
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('4.0', txTimeout)
.should('be.visible');
cy.get(ethWalletAssociatedBalances, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get(ethWalletAssociatedBalances, txTimeout).should(
'contain',
4.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('6');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
1.0,
txTimeout
);
cy.get(vegaWalletStakedBalances, txTimeout)
.should('contain', 6.0, txTimeout)
.and('contain', partValidatorId);
cy.get(stakeNextEpochValue, epochTimeout)
.contains(6.0, epochTimeout)
.should('be.visible');
cy.get(stakeThisEpochValue, epochTimeout)
.contains(6.0, epochTimeout)
.should('be.visible');
cy.close_staking_dialog();
cy.navigate_to('validators');
cy.validate_validator_list_total_stake_and_share(
'0',
'6.00',
'100.00%'
);
});
it('Able to stake against multiple validators', function () {
cy.staking_page_associate_tokens('5');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
5.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('2');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get(vegaWalletStakedBalances, txTimeout)
.parent()
.should('contain', 2.0, txTimeout);
cy.close_staking_dialog();
cy.navigate_to('validators');
cy.click_on_validator_from_list(1);
cy.staking_validator_page_add_stake('1');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
2.0,
txTimeout
);
cy.get(vegaWalletStakedBalances, txTimeout)
.should('have.length', 2, txTimeout)
.eq(0)
.should('contain', 2.0, txTimeout);
cy.get(vegaWalletStakedBalances, txTimeout)
.eq(1)
.should('contain', 1.0, txTimeout);
cy.close_staking_dialog();
cy.navigate_to('validators');
cy.get(`[row-id="${0}"]`).within(() => {
cy.get(stakeValidatorListTotalStake)
.should('have.text', '2.00')
.and('be.visible');
cy.get(stakeValidatorListTotalShare)
.should('have.text', '66.67%')
.and('be.visible');
cy.get(stakeValidatorListValidatorStake)
.scrollIntoView()
.should('have.text', '2.00')
.and('be.visible');
});
cy.get(`[row-id="${1}"]`).within(() => {
cy.get(stakeValidatorListTotalStake)
.scrollIntoView()
.should('have.text', '1.00')
.and('be.visible');
cy.get(stakeValidatorListTotalShare)
.should('have.text', '33.33%')
.and('be.visible');
cy.get(stakeValidatorListValidatorStake)
.scrollIntoView()
.should('have.text', '1.00')
.and('be.visible');
});
});
// 2001-STKE-041
it(
'Able to remove part of a stake against a validator',
{ tags: '@smoke' },
function () {
cy.staking_page_associate_tokens('4');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
4.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('3');
cy.get(stakeNextEpochValue, epochTimeout)
.contains(3.0, epochTimeout)
.should('be.visible');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
1.0,
txTimeout
);
cy.close_staking_dialog();
cy.navigate_to('validators');
// 2001-STKE-040
cy.click_on_validator_from_list(0);
// 2001-STKE-044, 2001-STKE-048
cy.staking_validator_page_remove_stake('1');
// 2001-STKE-049
cy.get(stakeNextEpochValue, epochTimeout).contains(2.0, epochTimeout);
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
2.0,
txTimeout
);
cy.get(vegaWalletStakedBalances, txTimeout).should(
'contain',
2.0,
txTimeout
);
cy.get(stakeNextEpochValue, epochTimeout)
.contains(2.0, epochTimeout)
.should('be.visible');
cy.get(stakeThisEpochValue, epochTimeout)
.contains(2.0, epochTimeout)
.should('be.visible');
cy.get(totalStake, epochTimeout).should('contain.text', '2');
cy.get(stakeShare, epochTimeout).should('have.text', '100%');
cy.navigate_to('validators');
cy.validate_validator_list_total_stake_and_share(
'0',
'2.00',
'100.00%'
);
}
);
// 2001-STKE-045
it('Able to remove a full stake against a validator', function () {
cy.staking_page_associate_tokens('3');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('1');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
2.0,
txTimeout
);
cy.close_staking_dialog();
cy.navigate_to('validators');
cy.click_on_validator_from_list('0');
cy.staking_validator_page_remove_stake('1');
cy.get(stakeNextEpochValue, epochTimeout)
.contains(0.0, epochTimeout)
.should('be.visible');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get(stakeNextEpochValue, epochTimeout)
.contains(0.0, epochTimeout)
.should('be.visible');
cy.get(stakeThisEpochValue, epochTimeout)
.contains(0.0, epochTimeout)
.should('be.visible');
cy.get(vegaWalletStakedBalances, txTimeout).should(
'not.exist',
txTimeout
);
cy.navigate_to('validators');
cy.validate_validator_list_total_stake_and_share('0', '0.00', '0.00%');
});
it('Unable to remove a stake with a negative value for a validator', function () {
cy.staking_page_associate_tokens('3');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('2');
cy.get(stakeNextEpochValue, epochTimeout)
.contains(2.0, epochTimeout)
.should('be.visible');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
1.0,
txTimeout
);
cy.close_staking_dialog();
cy.navigate_to('validators');
cy.click_on_validator_from_list(0);
cy.get(stakeRemoveStakeRadioButton, txTimeout).click();
cy.get(stakeTokenAmountInputBox).type('-0.1');
cy.contains('Waiting for next epoch to start', epochTimeout);
cy.get(stakeTokenSubmitButton)
.should('be.disabled', epochTimeout)
.and('contain', `Remove -0.1 $VEGA tokens at the end of epoch`)
.and('be.visible');
});
it('Unable to remove a stake greater than staked amount next epoch for a validator', function () {
cy.staking_page_associate_tokens('3');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('2');
cy.get(stakeNextEpochValue, epochTimeout)
.contains(2.0, epochTimeout)
.should('be.visible');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
1.0,
txTimeout
);
cy.close_staking_dialog();
cy.navigate_to('validators');
cy.click_on_validator_from_list(0);
cy.get(stakeRemoveStakeRadioButton).click();
cy.get(stakeTokenAmountInputBox).type(4);
cy.contains('Waiting for next epoch to start', epochTimeout);
cy.get(stakeTokenSubmitButton)
.should('be.disabled', epochTimeout)
.and('contain', `Remove 4 $VEGA tokens at the end of epoch`)
.and('be.visible');
});
it('Disassociating all wallet tokens max - removes all staked tokens', function () {
cy.staking_page_associate_tokens('3');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list('1');
cy.staking_validator_page_add_stake('2');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
1.0,
txTimeout
);
cy.get(vegaWalletStakedBalances, txTimeout).should(
'contain',
2.0,
txTimeout
);
cy.close_staking_dialog();
cy.staking_page_disassociate_all_tokens('wallet');
cy.get(ethWalletContainer).within(() => {
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
});
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('0.0', txTimeout)
.should('be.visible');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'0.00'
);
});
cy.get(vegaWalletStakedBalances, txTimeout).should(
'not.exist',
txTimeout
);
cy.navigate_to('validators');
cy.validate_validator_list_total_stake_and_share('0', '0.00', '0.00%');
});
it('Disassociating all vesting contract tokens max - removes all staked tokens', function () {
cy.staking_page_associate_tokens('3', { type: 'contract' });
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list('1');
cy.staking_validator_page_add_stake('2');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
1.0,
txTimeout
);
cy.get(vegaWalletStakedBalances, txTimeout).should(
'contain',
2.0,
txTimeout
);
cy.close_staking_dialog();
cy.staking_page_disassociate_all_tokens('contract');
cy.get(ethWalletContainer).within(() => {
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
});
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('0.0', txTimeout)
.should('be.visible');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'0.00'
);
});
cy.get(vegaWalletStakedBalances, txTimeout).should(
'not.exist',
txTimeout
);
cy.navigate_to('validators');
cy.validate_validator_list_total_stake_and_share('0', '0.00', '0.00%');
});
it('Disassociating some tokens - prioritizes unstaked tokens', function () {
cy.staking_page_associate_tokens('3');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('2');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
1.0,
txTimeout
);
cy.get(vegaWalletStakedBalances, txTimeout).should(
'contain',
2.0,
txTimeout
);
cy.close_staking_dialog();
cy.staking_page_disassociate_tokens('1');
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('2.0', txTimeout)
.should('be.visible');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'2.00'
);
});
cy.get(vegaWalletStakedBalances, txTimeout)
.should('contain', 2.0, txTimeout)
.and('contain', partValidatorId);
cy.navigate_to('validators');
cy.validate_validator_list_total_stake_and_share(
'0',
'2.00',
'100.00%'
);
});
it('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () {
// 2001-STKE-004
cy.staking_page_associate_tokens('3');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('3');
cy.get(vegaWalletStakedBalances, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.close_staking_dialog();
cy.staking_page_associate_tokens('4');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
0.0,
txTimeout
);
cy.get(vegaWalletStakedBalances, txTimeout).should(
'contain',
7.0,
txTimeout
);
});
it('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () {
// 2001-STKE-004
cy.staking_page_associate_tokens('3', { type: 'contract' });
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('3');
cy.get(vegaWalletStakedBalances, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.close_staking_dialog();
cy.staking_page_associate_tokens('4', { type: 'contract' });
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
0.0,
txTimeout
);
cy.get(vegaWalletStakedBalances, txTimeout).should(
'contain',
7.0,
txTimeout
);
});
it('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () {
// 2001-STKE-004
cy.staking_page_associate_tokens('3', { type: 'wallet' });
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('3');
cy.get(vegaWalletStakedBalances, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.close_staking_dialog();
cy.staking_page_associate_tokens('4', { type: 'contract' });
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
0.0,
txTimeout
);
cy.get(vegaWalletStakedBalances, txTimeout).should(
'contain',
7.0,
txTimeout
);
});
it('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () {
// 2001-STKE-004
cy.staking_page_associate_tokens('6');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
6.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('2');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
0.0,
txTimeout
);
cy.close_staking_dialog();
cy.click_on_validator_from_list(1);
cy.staking_validator_page_add_stake('4');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
0.0,
txTimeout
);
cy.close_staking_dialog();
cy.staking_page_associate_tokens('6');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'12.00'
);
});
cy.get(vegaWalletStakedBalances, txTimeout)
.should('contain', '4.0', txTimeout)
.and('contain', partValidatorId);
cy.get(vegaWalletStakedBalances, txTimeout)
.should('contain', '8.0')
.and('contain', partValidatorId);
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
0.0,
txTimeout
);
});
it('Selecting use maximum where tokens are already staked - suggests the unstaked token amount', function () {
cy.staking_page_associate_tokens('3');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
3.0,
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('2');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
1.0,
txTimeout
);
cy.close_staking_dialog();
cy.click_on_validator_from_list(0);
cy.get(stakeAddStakeRadioButton).click();
cy.get(stakeMaximumTokens, { timeout: 60000 }).click();
cy.get(stakeTokenSubmitButton).should('contain', 'Add 1 $VEGA tokens');
});
after('teardown wallet', function () {
cy.vega_wallet_teardown();
});
});
}
);
@@ -0,0 +1,509 @@
/// <reference types="cypress" />
import {
verifyUnstakedBalance,
verifyStakedBalance,
verifyEthWalletTotalAssociatedBalance,
verifyEthWalletAssociatedBalance,
waitForSpinner,
navigateTo,
navigation,
} from '../../support/common.functions';
import {
clickOnValidatorFromList,
closeStakingDialog,
ensureSpecifiedUnstakedTokensAreAssociated,
stakingPageAssociateTokens,
stakingPageDisassociateAllTokens,
stakingPageDisassociateTokens,
stakingValidatorPageAddStake,
stakingValidatorPageRemoveStake,
validateValidatorListTotalStakeAndShare,
waitForBeginningOfEpoch,
} from '../../support/staking.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import {
vegaWalletSetSpecifiedApprovalAmount,
vegaWalletTeardown,
} from '../../support/wallet-teardown.functions';
const stakeValidatorListTotalStake = 'total-stake';
const stakeValidatorListTotalShare = 'total-stake-share';
const stakeValidatorListStakePercentage = 'stake-percentage';
const userStakeBtn = 'my-stake-btn';
const userStake = 'user-stake';
const userStakeShare = 'user-stake-share';
const viewAllValidatorsToggle = 'validators-view-toggle-all';
const viewStakedByMeToggle = 'validators-view-toggle-myStake';
const stakeRemoveStakeRadioButton = 'remove-stake-radio';
const stakeTokenAmountInputBox = 'token-amount-input';
const stakeTokenSubmitButton = 'token-input-submit-button';
const stakeAddStakeRadioButton = 'add-stake-radio';
const stakeMaximumTokens = 'token-amount-use-maximum';
const vegaWalletAssociatedBalance = 'currency-value';
const vegaWalletStakedBalances = 'vega-wallet-balance-staked-validators';
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.visit('/');
ethereumWalletConnect();
// this is a workaround for #2422 which can be removed once issue is resolved
cy.associateTokensToVegaWallet('4');
vegaWalletSetSpecifiedApprovalAmount('1000');
});
describe('Eth wallet - contains VEGA tokens', function () {
beforeEach(
'teardown wallet & drill into a specific validator',
function () {
cy.clearLocalStorage();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
ethereumWalletConnect();
navigateTo(navigation.validators);
}
);
it('Able to stake against a validator - using vega from wallet', function () {
ensureSpecifiedUnstakedTokensAreAssociated('3');
verifyUnstakedBalance(3.0);
verifyEthWalletTotalAssociatedBalance('3.0');
verifyEthWalletAssociatedBalance('3.0');
cy.get('button').contains('Select a validator to nominate').click();
// 2001-STKE-031
clickOnValidatorFromList(0);
// 2001-STKE-033, 2001-STKE-034, 2001-STKE-037
stakingValidatorPageAddStake('2');
verifyUnstakedBalance(1.0);
// 2001-STKE-039
verifyStakedBalance(2.0);
verifyNextEpochValue(2.0); // 2001-STKE-016 2001-STKE-038
verifyThisEpochValue(2.0); // 2001-STKE-013
closeStakingDialog();
navigateTo(navigation.validators);
// 2002-SINC-007
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
});
it('Able to view validators staked by me', function () {
ensureSpecifiedUnstakedTokensAreAssociated('4');
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('2');
closeStakingDialog();
navigateTo(navigation.validators);
cy.getByTestId(userStake, epochTimeout)
.first()
.should('have.text', '2.00');
cy.getByTestId('total-stake').first().realHover();
cy.getByTestId('staked-by-user-tooltip')
.first()
.should('have.text', 'Staked by me: 2.00');
cy.getByTestId('total-pending-stake').first().realHover();
cy.getByTestId('pending-user-stake-tooltip')
.first()
.should('have.text', 'My pending stake: 0.00');
cy.getByTestId(userStakeShare).invoke('text').should('not.be.empty'); // Adjust when #3286 is resolved
cy.getByTestId(userStakeBtn).should('exist').click();
verifyThisEpochValue(2.0);
navigateTo(navigation.validators);
cy.getByTestId(viewStakedByMeToggle).click();
cy.getByTestId(userStakeBtn).should('have.length', 1);
cy.getByTestId(viewAllValidatorsToggle).click();
clickOnValidatorFromList(1);
stakingValidatorPageAddStake('2');
closeStakingDialog();
navigateTo(navigation.validators);
cy.getByTestId(viewStakedByMeToggle).click();
cy.getByTestId(userStakeBtn).should('have.length', 2);
});
it('Able to stake against a validator - using vega from vesting contract', function () {
stakingPageAssociateTokens('3', { type: 'contract' });
verifyUnstakedBalance(3.0);
verifyEthWalletTotalAssociatedBalance('3.0');
verifyEthWalletAssociatedBalance('3.0');
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('2');
verifyUnstakedBalance(1.0);
verifyStakedBalance(2.0);
verifyNextEpochValue(2.0);
verifyThisEpochValue(2.0);
closeStakingDialog();
navigateTo(navigation.validators);
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
});
it('Able to stake against a validator - using vega from both wallet and vesting contract', function () {
vegaWalletTeardown();
stakingPageAssociateTokens('3', { type: 'contract' });
navigateTo(navigation.validators);
stakingPageAssociateTokens('4', { type: 'wallet' });
verifyUnstakedBalance(7.0);
verifyEthWalletTotalAssociatedBalance('3.0');
verifyEthWalletTotalAssociatedBalance('4.0');
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('6');
verifyUnstakedBalance(1.0);
verifyStakedBalance(6.0);
verifyNextEpochValue(6.0);
verifyThisEpochValue(6.0);
closeStakingDialog();
navigateTo(navigation.validators);
validateValidatorListTotalStakeAndShare('0', '6.00', '100.00%');
});
it('Able to stake against multiple validators', function () {
stakingPageAssociateTokens('5');
verifyUnstakedBalance(5.0);
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('2');
verifyUnstakedBalance(3.0);
cy.getByTestId(vegaWalletStakedBalances, txTimeout)
.parent()
.should('contain', 2.0, txTimeout);
closeStakingDialog();
navigateTo(navigation.validators);
clickOnValidatorFromList(1);
stakingValidatorPageAddStake('1');
verifyUnstakedBalance(2.0);
cy.getByTestId(vegaWalletStakedBalances, txTimeout)
.should('have.length', 4, txTimeout)
.eq(0)
.should('contain', 2.0, txTimeout);
cy.getByTestId(vegaWalletStakedBalances, txTimeout)
.eq(1)
.should('contain', 1.0, txTimeout);
closeStakingDialog();
navigateTo(navigation.validators);
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
it(
'Able to remove part of a stake against a validator',
{ tags: '@smoke' },
function () {
ensureSpecifiedUnstakedTokensAreAssociated('4');
navigateTo(navigation.validators);
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('3');
verifyNextEpochValue(3.0);
verifyUnstakedBalance(1.0);
closeStakingDialog();
navigateTo(navigation.validators);
// 2001-STKE-040
clickOnValidatorFromList(0);
// 2001-STKE-044, 2001-STKE-048
stakingValidatorPageRemoveStake('1');
// 2001-STKE-049
verifyNextEpochValue(2.0);
verifyUnstakedBalance(2.0);
verifyStakedBalance(2.0);
verifyNextEpochValue(2.0);
verifyThisEpochValue(2.0);
cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should(
'contain.text',
'2'
);
waitForBeginningOfEpoch();
cy.getByTestId(stakeValidatorListStakePercentage).should(
'have.text',
'100%'
);
navigateTo(navigation.validators);
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
}
);
// 2001-STKE-045
it('Able to remove a full stake against a validator', function () {
stakingPageAssociateTokens('3');
verifyUnstakedBalance(3.0);
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('1');
verifyUnstakedBalance(2.0);
closeStakingDialog();
navigateTo(navigation.validators);
clickOnValidatorFromList(0);
stakingValidatorPageRemoveStake('1');
verifyNextEpochValue(0.0);
verifyUnstakedBalance(3.0);
verifyNextEpochValue(0.0);
verifyThisEpochValue(0.0);
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
'not.exist',
txTimeout
);
navigateTo(navigation.validators);
validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%');
cy.getByTestId(userStakeBtn).should('not.exist');
cy.getByTestId(userStake).should('not.exist');
cy.getByTestId(userStakeShare).should('not.exist');
});
it('Unable to remove a stake with a negative value for a validator', function () {
stakingPageAssociateTokens('3');
verifyUnstakedBalance(3.0);
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('2');
verifyNextEpochValue(2.0);
verifyUnstakedBalance(1.0);
closeStakingDialog();
navigateTo(navigation.validators);
clickOnValidatorFromList(0);
cy.getByTestId(stakeRemoveStakeRadioButton, txTimeout).click();
cy.getByTestId(stakeTokenAmountInputBox).type('-0.1');
cy.contains('Waiting for next epoch to start', epochTimeout);
cy.getByTestId(stakeTokenSubmitButton)
.should('be.disabled', epochTimeout)
.and('contain', `Remove -0.1 $VEGA tokens at the end of epoch`)
.and('be.visible');
});
it('Unable to remove a stake greater than staked amount next epoch for a validator', function () {
stakingPageAssociateTokens('3');
verifyUnstakedBalance(3.0);
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('2');
verifyNextEpochValue(2.0);
verifyUnstakedBalance(3.0);
closeStakingDialog();
navigateTo(navigation.validators);
clickOnValidatorFromList(0);
cy.getByTestId(stakeRemoveStakeRadioButton).click();
cy.getByTestId(stakeTokenAmountInputBox).type('4');
cy.contains('Waiting for next epoch to start', epochTimeout);
cy.getByTestId(stakeTokenSubmitButton)
.should('be.disabled', epochTimeout)
.and('contain', `Remove 4 $VEGA tokens at the end of epoch`)
.and('be.visible');
});
it('Disassociating all wallet tokens max - removes all staked tokens', function () {
stakingPageAssociateTokens('3');
verifyUnstakedBalance(3.0);
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(1);
stakingValidatorPageAddStake('2');
verifyUnstakedBalance(3.0);
verifyStakedBalance(2.0);
closeStakingDialog();
stakingPageDisassociateAllTokens();
getEthereumWallet().within(() => {
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
});
verifyEthWalletTotalAssociatedBalance('0.0');
getVegaWallet().within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'0.00'
);
});
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
'not.exist',
txTimeout
);
navigateTo(navigation.validators);
validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%');
});
it('Disassociating all vesting contract tokens max - removes all staked tokens', function () {
stakingPageAssociateTokens('3', { type: 'contract' });
verifyUnstakedBalance(3.0);
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(1);
stakingValidatorPageAddStake('2');
verifyUnstakedBalance(1.0);
verifyStakedBalance(2.0);
closeStakingDialog();
stakingPageDisassociateAllTokens('contract');
getEthereumWallet().within(() => {
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
});
verifyEthWalletTotalAssociatedBalance('0.0');
getVegaWallet().within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'0.00'
);
});
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
'not.exist',
txTimeout
);
navigateTo(navigation.validators);
validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%');
});
it('Disassociating some tokens - prioritizes unstaked tokens', function () {
stakingPageAssociateTokens('3');
verifyUnstakedBalance(3.0);
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('2');
verifyUnstakedBalance(1.0);
verifyStakedBalance(2.0);
closeStakingDialog();
stakingPageDisassociateTokens('1');
verifyEthWalletTotalAssociatedBalance('2.0');
getVegaWallet().within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'2.00'
);
});
verifyStakedBalance(2.0);
navigateTo(navigation.validators);
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
});
it('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () {
// 2001-STKE-004
stakingPageAssociateTokens('3');
verifyUnstakedBalance(3.0);
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('3');
verifyStakedBalance(3.0);
closeStakingDialog();
stakingPageAssociateTokens('4');
verifyUnstakedBalance(0.0);
verifyStakedBalance(7.0);
});
it('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () {
// 2001-STKE-004
stakingPageAssociateTokens('3', { type: 'contract' });
verifyUnstakedBalance(3.0);
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('3');
verifyStakedBalance(3.0);
closeStakingDialog();
stakingPageAssociateTokens('4', { type: 'contract' });
verifyUnstakedBalance(0.0);
verifyStakedBalance(7.0);
});
it('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () {
// 2001-STKE-004
stakingPageAssociateTokens('3', { type: 'wallet' });
verifyUnstakedBalance(3.0);
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('3');
verifyStakedBalance(3.0);
closeStakingDialog();
stakingPageAssociateTokens('4', { type: 'contract' });
verifyUnstakedBalance(0.0);
verifyStakedBalance(7.0);
});
it('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () {
// 2001-STKE-004
stakingPageAssociateTokens('6');
verifyUnstakedBalance(6.0);
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('2');
verifyUnstakedBalance(0.0);
closeStakingDialog();
clickOnValidatorFromList(1);
stakingValidatorPageAddStake('4');
verifyUnstakedBalance(0.0);
closeStakingDialog();
stakingPageAssociateTokens('6');
getVegaWallet().within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'12.00'
);
});
verifyStakedBalance(4.0);
verifyStakedBalance(8.0);
verifyUnstakedBalance(0.0);
});
it('Selecting use maximum where tokens are already staked - suggests the unstaked token amount', function () {
stakingPageAssociateTokens('3');
verifyUnstakedBalance(3.0);
cy.get('button').contains('Select a validator to nominate').click();
clickOnValidatorFromList(0);
stakingValidatorPageAddStake('2');
verifyUnstakedBalance(1.0);
closeStakingDialog();
clickOnValidatorFromList(0);
cy.getByTestId(stakeAddStakeRadioButton).click();
cy.getByTestId(stakeMaximumTokens, { timeout: 60000 }).click();
cy.getByTestId(stakeTokenSubmitButton).should(
'contain',
'Add 1 $VEGA tokens'
);
});
afterEach('Teardown Wallet', function () {
vegaWalletTeardown();
});
function verifyNextEpochValue(amount: number) {
cy.getByTestId('stake-next-epoch', epochTimeout)
.contains(amount, epochTimeout)
.should('be.visible');
}
function verifyThisEpochValue(amount: number) {
cy.getByTestId('stake-this-epoch', epochTimeout) // 2001-STKE-013
.contains(amount, epochTimeout)
.should('be.visible');
}
});
}
);
@@ -1,388 +0,0 @@
const ethWalletContainer = '[data-testid="ethereum-wallet"]';
const ethWalletAssociatedBalances =
'[data-testid="eth-wallet-associated-balances"]';
const ethWalletTotalAssociatedBalance = '[data-testid="currency-locked"]';
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
const vegaWalletUnstakedBalance =
'[data-testid="vega-wallet-balance-unstaked"]';
const txTimeout = Cypress.env('txTimeout');
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
const ethWalletAssociateButton = '[href="/token/associate"]';
const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
const ethWalletDissociateButton = '[href="/token/disassociate"]';
const vestingContractSection = '[data-testid="vega-in-vesting-contract"]';
const vegaInWalletSection = '[data-testid="vega-in-wallet"]';
const connectedVegaKey = '[data-testid="connected-vega-key"]';
const associatedKey = '[data-testid="associated-key"]';
const associatedAmount = '[data-testid="associated-amount"]';
const associateCompleteText = '[data-testid="transaction-complete-body"]';
const disassociationWarning = '[data-testid="disassociation-warning"]';
const vegaWallet = '[data-testid="vega-wallet"]';
context(
'Token association flow - with eth and vega wallets connected',
{ tags: '@slow' },
function () {
before('visit staking tab and connect vega wallet', function () {
cy.visit('/');
// 0005-ETXN-001
cy.vega_wallet_set_specified_approval_amount('1000');
});
describe('Eth wallet - contains VEGA tokens', function () {
beforeEach(
'teardown wallet & drill into a specific validator',
function () {
cy.reload();
cy.wait_for_spinner();
cy.ethereum_wallet_connect();
cy.connectVegaWallet();
cy.vega_wallet_teardown();
cy.navigate_to('validators');
}
);
it('Able to associate tokens - from wallet', function () {
//1004-ASSO-003
//1004-ASSO-005
//1004-ASSO-009
//1004-ASSO-030
//1004-ASSO-012
//1004-ASSO-013
//1004-ASSO-014
//1004-ASSO-015
//1004-ASSO-030
//0005-ETXN-006
//0005-ETXN-003
//0005-ETXN-005
cy.staking_page_associate_tokens('2', { skipConfirmation: true });
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
3
);
cy.validate_wallet_currency('Associated', '0.00');
cy.validate_wallet_currency('Pending association', '2.00');
cy.validate_wallet_currency('Total associated after pending', '2.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
// 0005-ETXN-002
cy.get(ethWalletAssociatedBalances, txTimeout)
.contains(vegaWalletPublicKeyShort)
.parent(txTimeout)
.should('contain', 2.0);
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('2.0', txTimeout)
.should('be.visible');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
});
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
});
it('Able to disassociate all associated tokens - manually', function () {
// 1004-ASSO-025
// 1004-ASSO-027
// 1004-ASSO-028
// 1004-ASSO-029
// 1004-ASSO-031
cy.staking_page_associate_tokens('2');
cy.get(ethWalletAssociatedBalances, txTimeout)
.contains(vegaWalletPublicKeyShort)
.parent(txTimeout)
.should('contain', 2.0);
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('2.0', txTimeout)
.should('be.visible');
cy.get('button').contains('Select a validator to nominate').click();
cy.staking_page_disassociate_tokens('2');
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
3
);
cy.validate_wallet_currency('Associated', '2.00');
cy.validate_wallet_currency('Pending association', '2.00');
cy.validate_wallet_currency('Total associated after pending', '0.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
cy.get(ethWalletAssociatedBalances, txTimeout).should('not.exist');
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('0.00', txTimeout)
.should('be.visible');
});
it('Able to associate more tokens than the approved amount of 1000 - requires re-approval', function () {
//1004-ASSO-011
cy.staking_page_associate_tokens('1001', { approve: true });
cy.get(ethWalletAssociatedBalances, txTimeout)
.contains(vegaWalletPublicKeyShort)
.parent()
.should('contain', '1,001.00', txTimeout);
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('1,001.00', txTimeout)
.should('be.visible');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'1,001.00'
);
});
});
it('Able to disassociate a partial amount of tokens currently associated', function () {
cy.staking_page_associate_tokens('2');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
});
cy.get('button').contains('Select a validator to nominate').click();
cy.staking_page_disassociate_tokens('1');
cy.get(ethWalletAssociatedBalances, txTimeout)
.contains(vegaWalletPublicKeyShort)
.parent(txTimeout)
.should('contain', 1.0);
cy.get(ethWalletAssociatedBalances, txTimeout)
.contains(vegaWalletPublicKeyShort)
.parent(txTimeout)
.should('contain', 1.0);
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 1.0);
});
});
it('Able to disassociate all tokens - using max', function () {
// 1004-ASSO-026
const warningText =
'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.';
cy.staking_page_associate_tokens('2');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
});
cy.get('button').contains('Select a validator to nominate').click();
cy.get(ethWalletDissociateButton).click();
cy.get(disassociationWarning).should('contain', warningText);
cy.staking_page_disassociate_all_tokens();
cy.get(ethWalletContainer).within(() => {
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
'not.exist'
);
});
cy.get(ethWalletContainer).within(() => {
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
'not.exist'
);
});
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 0.0);
});
});
it('Able to associate and disassociate vesting contract tokens', function () {
// 1004-ASSO-006
// 1004-ASSO-007
// 1004-ASSO-018
// 1004-ASSO-024
// 1004-ASSO-023
cy.staking_page_associate_tokens('2', {
type: 'contract',
skipConfirmation: true,
});
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
3
);
cy.validate_wallet_currency('Associated', '0.00');
cy.validate_wallet_currency('Pending association', '2.00');
cy.validate_wallet_currency('Total associated after pending', '2.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
cy.get(ethWalletAssociatedBalances, txTimeout)
.contains(vegaWalletPublicKeyShort)
.parent(txTimeout)
.should('contain', 2.0);
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('2.0', txTimeout)
.should('be.visible');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
});
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
cy.staking_page_disassociate_tokens('1', {
type: 'contract',
skipConfirmation: true,
});
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
3
);
cy.validate_wallet_currency('Associated', '2.00');
cy.validate_wallet_currency('Pending association', '1.00');
cy.validate_wallet_currency('Total associated after pending', '1.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
cy.get(ethWalletAssociatedBalances, txTimeout)
.contains(vegaWalletPublicKeyShort)
.parent(txTimeout)
.should('contain', 1.0);
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
.contains('1.0', txTimeout)
.should('be.visible');
});
it('Able to associate & disassociate both wallet and vesting contract tokens', function () {
// 1004-ASSO-019
// 1004-ASSO-020
// 1004-ASSO-021
// 1004-ASSO-022
cy.staking_page_associate_tokens('21', { type: 'wallet' });
cy.get('button').contains('Select a validator to nominate').click();
cy.staking_page_associate_tokens('37', { type: 'contract' });
cy.get(vestingContractSection).within(() => {
cy.get(associatedKey).should(
'contain',
Cypress.env('vegaWalletPublicKeyShort')
);
cy.get(associatedAmount, txTimeout).should('contain', 37);
});
cy.get(vegaInWalletSection).within(() => {
cy.get(associatedKey).should(
'contain',
Cypress.env('vegaWalletPublicKeyShort')
);
cy.get(associatedAmount, txTimeout).should('contain', 21);
});
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 58);
});
cy.staking_page_disassociate_tokens('6', { type: 'contract' });
cy.get(vestingContractSection).within(() => {
cy.get(associatedAmount, txTimeout).should('contain', 31);
});
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 52);
});
cy.navigate_to('validators');
cy.staking_page_disassociate_tokens('9', { type: 'wallet' });
cy.get(vegaInWalletSection).within(() => {
cy.get(associatedAmount, txTimeout).should('contain', 12);
});
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 43);
});
});
it('Not able to associate more tokens than owned', function () {
// 1004-ASSO-008
// 1004-ASSO-010
// No warning visible as described in AC, but the button is disabled
cy.get(ethWalletAssociateButton).first().click();
cy.get(associateWalletRadioButton, { timeout: 30000 }).click();
cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
cy.get(tokenAmountInputBox, { timeout: 10000 }).type(6500000);
cy.get(tokenSubmitButton, txTimeout).should('be.disabled');
});
// 1004-ASSO-004
it('Pending association outside of app is shown', function () {
cy.vega_wallet_associate('2');
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
3
);
cy.validate_wallet_currency('Associated', '0.00');
cy.validate_wallet_currency('Pending association', '2.00');
cy.validate_wallet_currency('Total associated after pending', '2.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
cy.validate_wallet_currency('Associated', '2.00');
});
it('Disassociation outside of app is shown', function () {
cy.staking_page_associate_tokens('2');
cy.validate_wallet_currency('Associated', '2.00');
cy.vega_wallet_disassociate('2');
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
3
);
cy.validate_wallet_currency('Associated', '2.00');
cy.validate_wallet_currency('Pending association', '2.00');
cy.validate_wallet_currency('Total associated after pending', '0.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
cy.validate_wallet_currency('Associated', '0.00');
});
it('Able to associate tokens to different public key of connected vega wallet', function () {
cy.get(ethWalletAssociateButton).first().click();
cy.get(associateWalletRadioButton).click();
cy.get(connectedVegaKey).should(
'have.text',
Cypress.env('vegaWalletPublicKey')
);
cy.get('[data-testid="manage-vega-wallet"]').click();
cy.get('[data-testid="select-keypair-button"]').eq(0).click();
cy.get(connectedVegaKey).should(
'have.text',
Cypress.env('vegaWalletPublicKey2')
);
cy.staking_page_associate_tokens('2');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
});
cy.get(associateCompleteText).should(
'have.text',
`Vega key ${Cypress.env(
'vegaWalletPublicKey2Short'
)} can now participate in governance and nominate a validator with your associated $VEGA.`
);
cy.staking_page_disassociate_all_tokens();
});
});
}
);
@@ -0,0 +1,399 @@
import {
verifyEthWalletTotalAssociatedBalance,
verifyEthWalletAssociatedBalance,
waitForSpinner,
navigateTo,
navigation,
} from '../../support/common.functions';
import {
stakingPageAssociateTokens,
stakingPageDisassociateAllTokens,
stakingPageDisassociateTokens,
validateWalletCurrency,
} from '../../support/staking.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import {
vegaWalletAssociate,
vegaWalletDisassociate,
vegaWalletSetSpecifiedApprovalAmount,
vegaWalletTeardown,
} from '../../support/wallet-teardown.functions';
const ethWalletContainer = '[data-testid="ethereum-wallet"]';
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
const vegaWalletUnstakedBalance =
'[data-testid="vega-wallet-balance-unstaked"]';
const txTimeout = Cypress.env('txTimeout');
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
const ethWalletAssociateButton = '[data-testid="associate-btn"]:visible';
const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
const ethWalletDissociateButton = '[href="/token/disassociate"]:visible';
const vestingContractSection = '[data-testid="vega-in-vesting-contract"]';
const vegaInWalletSection = '[data-testid="vega-in-wallet"]';
const connectedVegaKey = '[data-testid="connected-vega-key"]';
const associatedKey = '[data-testid="associated-key"]';
const associatedAmount = '[data-testid="associated-amount"]';
const associateCompleteText = '[data-testid="transaction-complete-body"]';
const disassociationWarning = '[data-testid="disassociation-warning"]';
const vegaWallet = '[data-testid="vega-wallet"]';
context(
'Token association flow - with eth and vega wallets connected',
{ tags: '@slow' },
function () {
before('visit staking tab and connect vega wallet', function () {
cy.visit('/');
// 0005-ETXN-001
vegaWalletSetSpecifiedApprovalAmount('1000');
});
describe('Eth wallet - contains VEGA tokens', function () {
beforeEach(
'teardown wallet & drill into a specific validator',
function () {
cy.clearLocalStorage();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
ethereumWalletConnect();
vegaWalletTeardown();
}
);
it('Able to associate tokens - from wallet', function () {
//1004-ASSO-003
//1004-ASSO-005
//1004-ASSO-009
//1004-ASSO-030
//1004-ASSO-012
//1004-ASSO-013
//1004-ASSO-014
//1004-ASSO-015
//1004-ASSO-030
//0005-ETXN-006
//0005-ETXN-003
//0005-ETXN-005
stakingPageAssociateTokens('2', { skipConfirmation: true });
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
6
);
validateWalletCurrency('Associated', '0.00');
validateWalletCurrency('Pending association', '2.00');
validateWalletCurrency('Total associated after pending', '2.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
// 0005-ETXN-002
verifyEthWalletAssociatedBalance('2.0');
verifyEthWalletTotalAssociatedBalance('2.0');
cy.get(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
});
it('Able to disassociate all associated tokens - manually', function () {
// 1004-ASSO-025
// 1004-ASSO-027
// 1004-ASSO-028
// 1004-ASSO-029
// 1004-ASSO-031
stakingPageAssociateTokens('2');
verifyEthWalletAssociatedBalance('2.0');
verifyEthWalletTotalAssociatedBalance('2.0');
cy.get('button').contains('Select a validator to nominate').click();
stakingPageDisassociateTokens('2');
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
6
);
validateWalletCurrency('Associated', '2.00');
validateWalletCurrency('Pending association', '2.00');
validateWalletCurrency('Total associated after pending', '0.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
cy.getByTestId('eth-wallet-associated-balances', txTimeout).should(
'not.exist'
);
verifyEthWalletTotalAssociatedBalance('0.00');
});
it('Able to associate more tokens than the approved amount of 1000 - requires re-approval', function () {
//1004-ASSO-011
stakingPageAssociateTokens('1001', { approve: true });
verifyEthWalletAssociatedBalance('1,001.00');
verifyEthWalletTotalAssociatedBalance('1,001.00');
cy.get(vegaWallet)
.last()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'1,001.00'
);
});
});
it('Able to disassociate a partial amount of tokens currently associated', function () {
stakingPageAssociateTokens('2');
cy.get(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get('button').contains('Select a validator to nominate').click();
stakingPageDisassociateTokens('1');
verifyEthWalletAssociatedBalance('1.0');
cy.get(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
1.0
);
});
});
it('Able to disassociate all tokens - using max', function () {
// 1004-ASSO-026
const warningText =
'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.';
stakingPageAssociateTokens('2');
cy.get(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get('button').contains('Select a validator to nominate').click();
cy.get(ethWalletDissociateButton).click();
cy.get(disassociationWarning).should('contain', warningText);
stakingPageDisassociateAllTokens();
cy.get(ethWalletContainer)
.first()
.within(() => {
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
'not.exist'
);
});
cy.get(ethWalletContainer)
.first()
.within(() => {
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
'not.exist'
);
});
cy.get(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
0.0
);
});
});
it('Able to associate and disassociate vesting contract tokens', function () {
// 1004-ASSO-006
// 1004-ASSO-007
// 1004-ASSO-018
// 1004-ASSO-024
// 1004-ASSO-023
// 1004-ASSO-032
stakingPageAssociateTokens('2', {
type: 'contract',
skipConfirmation: true,
});
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
6
);
validateWalletCurrency('Associated', '0.00');
validateWalletCurrency('Pending association', '2.00');
validateWalletCurrency('Total associated after pending', '2.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
verifyEthWalletAssociatedBalance('2.0');
verifyEthWalletTotalAssociatedBalance('2.0');
cy.get(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
stakingPageDisassociateTokens('1', {
type: 'contract',
skipConfirmation: true,
});
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
6
);
validateWalletCurrency('Associated', '2.00');
validateWalletCurrency('Pending association', '1.00');
validateWalletCurrency('Total associated after pending', '1.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
verifyEthWalletAssociatedBalance('1.0');
verifyEthWalletTotalAssociatedBalance('1.0');
});
it('Able to associate & disassociate both wallet and vesting contract tokens', function () {
// 1004-ASSO-019
// 1004-ASSO-020
// 1004-ASSO-021
// 1004-ASSO-022
stakingPageAssociateTokens('21', { type: 'wallet' });
cy.get('button').contains('Select a validator to nominate').click();
stakingPageAssociateTokens('37', { type: 'contract' });
cy.get(vestingContractSection)
.first()
.within(() => {
cy.get(associatedKey).should(
'contain',
Cypress.env('vegaWalletPublicKeyShort')
);
cy.get(associatedAmount, txTimeout).should('contain', 37);
});
cy.get(vegaInWalletSection)
.first()
.within(() => {
cy.get(associatedKey).should(
'contain',
Cypress.env('vegaWalletPublicKeyShort')
);
cy.get(associatedAmount, txTimeout).should('contain', 21);
});
cy.get(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
58
);
});
stakingPageDisassociateTokens('6', { type: 'contract' });
cy.get(vestingContractSection)
.first()
.within(() => {
cy.get(associatedAmount, txTimeout).should('contain', 31);
});
cy.get(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
52
);
});
navigateTo(navigation.validators);
stakingPageDisassociateTokens('9', { type: 'wallet' });
cy.get(vegaInWalletSection)
.first()
.within(() => {
cy.get(associatedAmount, txTimeout).should('contain', 12);
});
cy.get(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
43
);
});
});
it('Not able to associate more tokens than owned', function () {
// 1004-ASSO-008
// 1004-ASSO-010
// No warning visible as described in AC, but the button is disabled
cy.get(ethWalletAssociateButton).click();
cy.get(associateWalletRadioButton, { timeout: 30000 }).click();
cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
cy.get(tokenAmountInputBox, { timeout: 10000 }).type('6500000');
cy.get(tokenSubmitButton, txTimeout).should('be.disabled');
});
// 1004-ASSO-004
it('Pending association outside of app is shown', function () {
vegaWalletAssociate('2');
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
6
);
validateWalletCurrency('Associated', '0.00');
validateWalletCurrency('Pending association', '2.00');
validateWalletCurrency('Total associated after pending', '2.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
validateWalletCurrency('Associated', '2.00');
});
it('Disassociation outside of app is shown', function () {
stakingPageAssociateTokens('2');
cy.wrap(validateWalletCurrency('Associated', '2.00')).then(() => {
vegaWalletDisassociate('2');
});
cy.getByTestId('currency-title', txTimeout).should(
'have.length.above',
6
);
validateWalletCurrency('Associated', '2.00');
validateWalletCurrency('Pending association', '2.00');
validateWalletCurrency('Total associated after pending', '0.00');
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
validateWalletCurrency('Associated', '0.00');
});
it('Able to associate tokens to different public key of connected vega wallet', function () {
cy.get(ethWalletAssociateButton).click();
cy.get(associateWalletRadioButton).click();
cy.get(connectedVegaKey).should(
'have.text',
Cypress.env('vegaWalletPublicKey')
);
cy.get('[data-testid="manage-vega-wallet"]:visible').click();
cy.get('[data-testid="select-keypair-button"]').eq(0).click();
cy.get(connectedVegaKey).should(
'have.text',
Cypress.env('vegaWalletPublicKey2')
);
stakingPageAssociateTokens('2');
cy.get(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get(associateCompleteText).should(
'have.text',
`Vega key ${Cypress.env(
'vegaWalletPublicKey2Short'
)} can now participate in governance and nominate a validator with your associated $VEGA.`
);
stakingPageDisassociateAllTokens();
});
});
}
);
@@ -1,198 +0,0 @@
const withdraw = 'withdraw';
const selectAsset = 'select-asset';
const ethAddressInput = 'eth-address-input';
const amountInput = 'amount-input';
const balanceAvailable = 'BALANCE_AVAILABLE_value';
const withdrawalThreshold = 'WITHDRAWAL_THRESHOLD_value';
const delayTime = 'DELAY_TIME_value';
const submitWithdrawalButton = 'submit-withdrawal';
const dialogTitle = 'dialog-title';
const dialogClose = 'dialog-close';
const txExplorerLink = 'tx-block-explorer';
const withdrawalAssetSymbol = 'withdrawal-asset-symbol';
const withdrawalAmount = 'withdrawal-amount';
const withdrawalRecipient = 'withdrawal-recipient';
const withdrawFundsButton = 'withdraw-funds';
const completeWithdrawalButton = 'complete-withdrawal';
const usdtName = 'USDC (local)';
const usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0';
const usdcSymbol = 'tUSDC';
const truncatedWithdrawalEthAddress = '0xEe7D…22d94F';
const formValidationError = 'input-error-text';
const txTimeout = Cypress.env('txTimeout');
context(
'Withdrawals - with eth and vega wallet connected',
{ tags: '@slow' },
function () {
before('visit withdrawals and connect vega wallet', function () {
cy.updateCapsuleMultiSig(); // When running tests locally, will fail if run without restarting capsule
cy.deposit_asset(usdcEthAddress, '100000000000000000000');
});
beforeEach('Navigate to withdrawal page', function () {
cy.reload();
cy.visit('/');
cy.wait_for_spinner();
cy.navigate_to('withdraw');
cy.connectVegaWallet();
cy.ethereum_wallet_connect();
cy.vega_wallet_teardown();
});
it('Able to open withdrawal form with vega wallet connected', function () {
// needs to reload page for withdrawal form to be displayed in ci - not reproducible outside of ci
cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(selectAsset)
.find('option')
.should('have.length.at.least', 2);
cy.getByTestId(ethAddressInput).should('be.visible');
cy.getByTestId(amountInput).should('be.visible');
});
it('Unable to submit withdrawal with invalid fields', function () {
cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(selectAsset).select(usdtName);
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
cy.getByTestId(submitWithdrawalButton).click();
cy.getByTestId(formValidationError).should('have.length', 1);
cy.getByTestId(amountInput).clear().click().type('0.0000001');
cy.getByTestId(submitWithdrawalButton).click();
cy.getByTestId(formValidationError).should(
'have.text',
'Value is below minimum'
);
cy.getByTestId(amountInput).clear().click().type('10');
cy.getByTestId(ethAddressInput).click().type('123');
cy.getByTestId(submitWithdrawalButton).click();
cy.getByTestId(formValidationError).should(
'have.text',
'Invalid Ethereum address'
);
});
it('Able to withdraw asset: -eth wallet connected -withdraw funds button', function () {
// fill in withdrawal form
cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(selectAsset).select(usdtName);
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
cy.getByTestId(withdrawalThreshold).should('have.text', '100,000.00000T');
cy.getByTestId(delayTime).should('have.text', 'None');
cy.getByTestId(amountInput).click().type('100');
cy.getByTestId(submitWithdrawalButton).click();
cy.contains('Awaiting network confirmation').should('be.visible');
// assert withdrawal request
cy.getByTestId(dialogTitle, txTimeout).should(
'have.text',
'Transaction complete'
);
cy.getByTestId(txExplorerLink)
.should('have.attr', 'href')
.and('contain', '/txs/');
cy.getByTestId(withdrawalAssetSymbol).should('have.text', usdcSymbol);
cy.getByTestId(withdrawalAmount).should('have.text', '100.00');
cy.getByTestId(withdrawalRecipient)
.should('have.text', truncatedWithdrawalEthAddress)
.and('have.attr', 'href')
.and('contain', `/address/${Cypress.env('ethWalletPublicKey')}`);
cy.getByTestId(withdrawFundsButton).click();
// withdrawal complete
cy.getByTestId(dialogTitle, txTimeout).should(
'have.text',
'Withdraw asset complete'
);
cy.getByTestId(dialogClose).click();
// need to reload page to see withdrawal history complete
cy.reload();
waitForAssetsDisplayed(usdtName);
// withdrawal history for complete withdrawal displayed
cy.get('[col-id="txHash"]', txTimeout)
.should('have.length.above', 1)
.eq(1)
.parent()
.within(() => {
cy.get('[col-id="asset.symbol"]').should('have.text', usdcSymbol);
cy.get('[col-id="amount"]').should('have.text', '100.00');
cy.get('[col-id="details.receiverAddress"]')
.find('a')
.should('have.attr', 'href')
.and('contain', 'https://sepolia.etherscan.io/address/');
cy.get('[col-id="withdrawnTimestamp"]').should('not.be.empty');
cy.get('[col-id="status"]').should('have.text', 'Completed');
cy.get('[col-id="txHash"]')
.find('a')
.should('have.attr', 'href')
.and('contain', 'https://sepolia.etherscan.io/tx/');
});
});
// Skipping because of bug #1857
it.skip('Able to withdraw asset: -eth wallet not connected', function () {
const ethWalletAddress = Cypress.env('ethWalletPublicKey');
cy.reload();
waitForAssetsDisplayed(usdtName);
// fill in withdrawal form
cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(selectAsset).select(usdtName);
cy.getByTestId(ethAddressInput).should('be.empty');
cy.getByTestId(amountInput).click().type('100');
cy.getByTestId(submitWithdrawalButton).click();
// Need eth address to submit withdrawal
cy.getByTestId(formValidationError).should('have.length', 1);
cy.getByTestId(ethAddressInput).click().type(ethWalletAddress);
cy.getByTestId(submitWithdrawalButton).click();
cy.contains('Awaiting network confirmation').should('be.visible');
// assert withdrawal request
cy.getByTestId(dialogTitle, txTimeout).should(
'have.text',
'Transaction complete'
);
cy.getByTestId(dialogClose).click();
cy.getByTestId(completeWithdrawalButton)
.eq(0)
.parent()
.parent()
.within(() => {
cy.get('[col-id="asset.symbol"]').should('have.text', usdcSymbol);
cy.get('[col-id="amount"]').should('have.text', '100.00');
cy.get('[col-id="details.receiverAddress"]')
.find('a')
.should('have.attr', 'href')
.and('contain', 'https://sepolia.etherscan.io/address/');
cy.get('[col-id="createdTimestamp"]').should('not.be.empty');
cy.getByTestId(completeWithdrawalButton).click();
});
});
it('Unable to withdraw asset on pub key view', function () {
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey');
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
// Disconnect vega wallet
cy.getByTestId('manage-vega-wallet').click();
cy.getByTestId('disconnect').click();
cy.connectPublicKey(vegaWalletPubKey);
cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(selectAsset).select(usdtName);
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
cy.getByTestId(amountInput).click().type('100');
cy.getByTestId(submitWithdrawalButton).click();
cy.getByTestId('dialog-content').within(() => {
cy.get('h1').should('have.text', 'Transaction failed');
cy.getByTestId('Error').should('have.text', expectedErrorTxt);
});
});
function waitForAssetsDisplayed(expectedAsset) {
cy.contains(expectedAsset, txTimeout).should('be.visible');
}
}
);
@@ -0,0 +1,224 @@
import {
navigateTo,
navigation,
waitForSpinner,
} from '../../support/common.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { depositAsset } from '../../support/wallet-teardown.functions';
const withdraw = 'withdraw';
const withdrawalForm = 'withdraw-form';
const ethAddressInput = 'eth-address-input';
const amountInput = 'amount-input';
const balanceAvailable = 'BALANCE_AVAILABLE_value';
const withdrawalThreshold = 'WITHDRAWAL_THRESHOLD_value';
const delayTime = 'DELAY_TIME_value';
const submitWithdrawalButton = 'submit-withdrawal';
const dialogTitle = 'dialog-title';
const dialogClose = 'dialog-close';
const txExplorerLink = 'tx-block-explorer';
const withdrawalAssetSymbol = 'withdrawal-asset-symbol';
const withdrawalAmount = 'withdrawal-amount';
const withdrawalRecipient = 'withdrawal-recipient';
const withdrawFundsButton = 'withdraw-funds';
const completeWithdrawalButton = 'complete-withdrawal';
const tableTxHash = '[col-id="txHash"]';
const tableAssetSymbol = '[col-id="asset.symbol"]';
const tableAmount = '[col-id="amount"]';
const tableReceiverAddress = '[col-id="details.receiverAddress"]';
const tableWithdrawnTimeStamp = '[col-id="withdrawnTimestamp"]';
const tableWithdrawnStatus = '[col-id="status"]';
const tableCreatedTimeStamp = '[col-id="createdTimestamp"]';
const usdtName = 'USDC (local)';
const usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0';
const usdcSymbol = 'tUSDC';
const usdtSelectValue =
'993ed98f4f770d91a796faab1738551193ba45c62341d20597df70fea6704ede';
const truncatedWithdrawalEthAddress = '0xEe7D…22d94F';
const formValidationError = 'input-error-text';
const txTimeout = Cypress.env('txTimeout');
context(
'Withdrawals - with eth and vega wallet connected',
{ tags: '@slow' },
function () {
before('visit withdrawals and connect vega wallet', function () {
cy.visit('/');
// When running tests locally, will fail if run without restarting capsule
cy.updateCapsuleMultiSig().then(() => {
ethereumWalletConnect();
depositAsset(usdcEthAddress, '1000', 5);
});
});
beforeEach('Navigate to withdrawal page', function () {
cy.clearLocalStorage();
cy.reload();
waitForSpinner();
navigateTo(navigation.withdraw);
cy.connectVegaWallet();
ethereumWalletConnect();
});
it('Able to open withdrawal form with vega wallet connected', function () {
cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
cy.get('select').find('option').should('have.length.at.least', 2);
cy.getByTestId(ethAddressInput).should('be.visible');
cy.getByTestId(amountInput).should('be.visible');
});
});
it('Unable to submit withdrawal with invalid fields', function () {
cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
cy.get('select').select(usdtSelectValue, { force: true });
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
cy.getByTestId(submitWithdrawalButton).click();
cy.getByTestId(formValidationError).should('have.length', 1);
cy.getByTestId(amountInput).clear().click().type('0.0000001');
cy.getByTestId(submitWithdrawalButton).click();
cy.getByTestId(formValidationError).should(
'have.text',
'Value is below minimum'
);
cy.getByTestId(amountInput).clear().click().type('10');
cy.getByTestId(ethAddressInput).click().type('123');
cy.getByTestId(submitWithdrawalButton).click();
cy.getByTestId(formValidationError).should(
'have.text',
'Invalid Ethereum address'
);
});
});
it('Able to withdraw asset: -eth wallet connected -withdraw funds button', function () {
// fill in withdrawal form
cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
cy.get('select').select(usdtSelectValue, { force: true });
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
cy.getByTestId(withdrawalThreshold).should(
'have.text',
'100,000.00000T'
);
cy.getByTestId(delayTime).should('have.text', 'None');
cy.getByTestId(amountInput).click().type('120');
cy.getByTestId(submitWithdrawalButton).click();
});
cy.contains('Awaiting network confirmation').should('be.visible');
// assert withdrawal request
cy.getByTestId(dialogTitle, txTimeout).should(
'have.text',
'Transaction complete'
);
cy.getByTestId(txExplorerLink)
.should('have.attr', 'href')
.and('contain', '/txs/');
cy.getByTestId(withdrawalAssetSymbol).should('have.text', usdcSymbol);
cy.getByTestId(withdrawalAmount).should('have.text', '120.00');
cy.getByTestId(withdrawalRecipient)
.should('have.text', truncatedWithdrawalEthAddress)
.and('have.attr', 'href')
.and('contain', `/address/${Cypress.env('ethWalletPublicKey')}`);
cy.getByTestId(withdrawFundsButton).click();
// withdrawal complete
cy.getByTestId(dialogTitle, txTimeout).should(
'have.text',
'Withdraw asset complete'
);
cy.getByTestId(dialogClose).click();
// withdrawal history for complete withdrawal displayed
cy.get(tableWithdrawnStatus)
.eq(1, txTimeout)
.should('have.text', 'Completed')
.parent()
.within(() => {
cy.get(tableAssetSymbol).should('have.text', usdcSymbol);
cy.get(tableAmount).should('have.text', '120.00');
cy.get(tableReceiverAddress)
.find('a')
.should('have.attr', 'href')
.and('contain', 'https://sepolia.etherscan.io/address/');
cy.get(tableWithdrawnTimeStamp).should('not.be.empty');
cy.get(tableTxHash)
.find('a')
.should('have.attr', 'href')
.and('contain', 'https://sepolia.etherscan.io/tx/');
});
});
// Skipping because of bug #1857
it('Able to withdraw asset: -eth wallet not connected', function () {
const ethWalletAddress = Cypress.env('ethWalletPublicKey');
cy.reload();
waitForAssetsDisplayed(usdtName);
// fill in withdrawal form
cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
cy.get('select').select(usdtSelectValue, { force: true });
cy.getByTestId(ethAddressInput).should('be.empty');
cy.getByTestId(amountInput).click().type('110');
cy.getByTestId(submitWithdrawalButton).click();
// Need eth address to submit withdrawal
cy.getByTestId(formValidationError).should('have.length', 1);
cy.getByTestId(ethAddressInput).click().type(ethWalletAddress);
cy.getByTestId(submitWithdrawalButton).click();
});
cy.contains('Awaiting network confirmation').should('be.visible');
// assert withdrawal request
cy.getByTestId(dialogTitle, txTimeout).should(
'have.text',
'Transaction complete'
);
cy.getByTestId(dialogClose).click();
cy.get(tableTxHash)
.eq(1)
.should('have.text', 'Complete withdrawal')
.parent()
.within(() => {
cy.get(tableAssetSymbol).should('have.text', usdcSymbol);
cy.get(tableAmount).should('have.text', '110.00');
cy.get(tableReceiverAddress)
.find('a')
.should('have.attr', 'href')
.and('contain', 'https://sepolia.etherscan.io/address/');
cy.get(tableCreatedTimeStamp).should('not.be.empty');
cy.getByTestId(completeWithdrawalButton).click();
// Unable to complete withdrawal in Capsule
});
});
it('Unable to withdraw asset on pub key view', function () {
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey');
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
// Disconnect vega wallet
cy.getByTestId('manage-vega-wallet').last().click();
cy.getByTestId('disconnect').click();
cy.connectPublicKey(vegaWalletPubKey);
cy.getByTestId(withdraw).should('be.visible').click();
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
cy.get('select').select(usdtSelectValue, { force: true });
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
cy.getByTestId(amountInput).click().type('100');
cy.getByTestId(submitWithdrawalButton).click();
});
cy.getByTestId('dialog-content')
.last()
.within(() => {
cy.get('h1').should('have.text', 'Transaction failed');
cy.getByTestId('Error').should('have.text', expectedErrorTxt);
});
});
function waitForAssetsDisplayed(expectedAsset: string) {
cy.getByTestId('currency-title').should('contain.text', expectedAsset);
}
}
);
@@ -1,111 +0,0 @@
context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
before('visit token home page', function () {
cy.visit('/');
cy.get('nav', { timeout: 10000 }).should('be.visible');
});
describe('with wallets disconnected', function () {
describe('Links and buttons', function () {
it('should have link for proposal page', function () {
cy.getByTestId('home-proposals').within(() => {
cy.get('[href="/proposals"]')
.should('exist')
.and('have.text', 'Browse, vote, and propose');
});
});
it('should show open or enacted proposals with proposal summary', function () {
cy.get('body').then(($body) => {
if (!$body.find('[data-testid="proposals-list-item"]').length) {
cy.createMarket();
cy.reload();
cy.wait_for_spinner();
}
});
cy.getByTestId('proposals-list-item')
.should('have.length.at.least', 1)
.first()
.within(() => {
cy.getByTestId('proposal-title')
.invoke('text')
.should('not.be.empty');
cy.getByTestId('proposal-type')
.invoke('text')
.should('not.be.empty');
cy.getByTestId('proposal-description')
.invoke('text')
.should('not.be.empty');
cy.getByTestId('proposal-details')
.invoke('text')
.should('not.be.empty');
cy.getByTestId('proposal-status')
.invoke('text')
.should('not.be.empty');
cy.getByTestId('vote-details')
.invoke('text')
.should('not.be.empty');
cy.getByTestId('view-proposal-btn').should('be.visible');
});
});
it('should have external link for governance', function () {
cy.getByTestId('home-proposals').within(() => {
cy.getByTestId('external-link')
.should('have.attr', 'href')
.and('contain', 'https://vega.xyz/governance');
});
});
it('should have link for validator page', function () {
cy.getByTestId('home-validators').within(() => {
cy.get('[href="/validators"]')
.first()
.should('exist')
.and('have.text', 'Browse, and stake');
});
});
it('should have external link for validators', function () {
cy.getByTestId('home-validators').within(() => {
cy.getByTestId('external-link')
.should('have.attr', 'href')
.and(
'contain',
'https://community.vega.xyz/c/mainnet-validator-candidates'
);
});
});
it('should have information on active nodes', function () {
cy.getByTestId('node-information')
.first()
.should('contain.text', '2')
.and('contain.text', 'active nodes');
});
it('should have information on consensus nodes', function () {
cy.getByTestId('node-information')
.last()
.should('contain.text', '2')
.and('contain.text', 'consensus nodes');
});
it('should contain link to specific validators', function () {
cy.getByTestId('validators')
.should('have.length', '2')
.each(($validator) => {
cy.wrap($validator).find('a').should('have.attr', 'href');
});
});
it('should have link for rewards page', function () {
cy.getByTestId('home-rewards').within(() => {
cy.get('[href="/rewards"]')
.first()
.should('exist')
.and('have.text', 'See rewards');
});
});
it('should have link for withdrawal page', function () {
cy.getByTestId('home-vega-token').within(() => {
cy.get('[href="/token/withdraw"]')
.first()
.should('exist')
.and('have.text', 'Manage tokens');
});
});
});
});
});
@@ -0,0 +1,204 @@
import { waitForSpinner } from '../../support/common.functions';
context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
before('visit token home page', function () {
cy.visit('/');
cy.get('nav', { timeout: 10000 }).should('be.visible');
});
describe('Links and buttons', function () {
it('should have link for proposal page', function () {
cy.getByTestId('home-proposals').within(() => {
cy.get('[href="/proposals"]')
.should('exist')
.and('have.text', 'Browse, vote, and propose');
});
});
it('should display announcement banner', function () {
cy.getByTestId('app-announcement')
.should('contain.text', 'TEST ANNOUNCEMENT!')
.within(() => {
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');
});
it('should show open or enacted proposals without proposal summary', function () {
cy.get('body').then(($body) => {
if (!$body.find('[data-testid="proposals-list-item"]').length) {
cy.createMarket();
cy.reload();
waitForSpinner();
}
});
cy.getByTestId('proposals-list-item')
.should('have.length.at.least', 1)
.first()
.within(() => {
cy.getByTestId('proposal-title')
.invoke('text')
.should('not.be.empty');
cy.getByTestId('proposal-type').invoke('text').should('not.be.empty');
cy.getByTestId('proposal-status')
.invoke('text')
.should('not.be.empty');
cy.getByTestId('vote-details').invoke('text').should('not.be.empty');
cy.getByTestId('view-proposal-btn').should('be.visible');
});
});
it('should have external link for governance', function () {
cy.getByTestId('home-proposals').within(() => {
cy.getByTestId('external-link')
.should('have.attr', 'href')
.and('contain', 'https://vega.xyz/governance');
});
});
it('should have link for validator page', function () {
cy.getByTestId('home-validators').within(() => {
cy.get('[href="/validators"]')
.first()
.should('exist')
.and('have.text', 'Browse, and stake');
});
});
it('should have external link for validators', function () {
cy.getByTestId('home-validators').within(() => {
cy.getByTestId('external-link')
.should('have.attr', 'href')
.and(
'contain',
'https://community.vega.xyz/c/mainnet-validator-candidates'
);
});
});
it('should have information on active nodes', function () {
cy.getByTestId('node-information')
.first()
.should('contain.text', '2')
.and('contain.text', 'active nodes');
});
it('should have information on consensus nodes', function () {
cy.getByTestId('node-information')
.last()
.should('contain.text', '2')
.and('contain.text', 'consensus nodes');
});
it('should contain link to specific validators', function () {
cy.getByTestId('validators')
.should('have.length', '2')
.each(($validator) => {
cy.wrap($validator).find('a').should('have.attr', 'href');
});
});
it('should have link for rewards page', function () {
cy.getByTestId('home-rewards').within(() => {
cy.get('[href="/rewards"]')
.first()
.should('exist')
.and('have.text', 'See rewards');
});
});
it('should have link for withdrawal page', function () {
cy.getByTestId('home-vega-token').within(() => {
cy.get('[href="/token/withdraw"]')
.first()
.should('exist')
.and('have.text', 'Manage tokens');
});
});
it('should display network data', function () {
cy.getByTestId('git-network-data')
.should('contain.text', 'Reading network data from')
.within(() => {
cy.get('span')
.first()
.should('have.text', 'http://localhost:3008/graphql');
cy.getByTestId('link').should('exist');
});
});
it('should display eth data', function () {
cy.getByTestId('git-eth-data')
.should('contain.text', 'Reading Ethereum data from')
.within(() => {
cy.get('span').should('have.text', 'http://localhost:8545');
});
});
it('should contain link for known issues on Github', function () {
cy.getByTestId('git-info').within(() => {
cy.contains('Known issues and feedback on')
.find('[data-testid="link"]')
.should(
'have.attr',
'href',
'https://github.com/vegaprotocol/feedback/discussions'
);
});
});
});
describe('Mobile view - navigation bar', function () {
before('Change to mobile resolution', function () {
cy.viewport('iphone-xr');
});
it('should have burger button', () => {
cy.getByTestId('button-menu-drawer').should('be.visible').click();
cy.getByTestId('menu-drawer').should('be.visible');
});
it('should have link for proposal page', function () {
cy.getByTestId('menu-drawer').within(() => {
cy.get('[href="/proposals"]')
.should('exist')
.and('have.text', 'Proposals');
});
});
it('should have link for validator page', function () {
cy.getByTestId('menu-drawer').within(() => {
cy.get('[href="/validators"]')
.first()
.should('exist')
.and('have.text', 'Validators');
});
});
it('should have link for rewards page', function () {
cy.getByTestId('menu-drawer').within(() => {
cy.get('[href="/rewards"]')
.first()
.should('exist')
.and('have.text', 'Rewards');
});
});
it('should have link for withdrawal page', function () {
cy.getByTestId('menu-drawer').within(() => {
cy.get('[href="/token/withdraw"]')
.first()
.should('exist')
.and('have.text', 'Withdraw');
});
});
after(function () {
cy.viewport(
Cypress.config('viewportWidth'),
Cypress.config('viewportHeight')
);
});
});
});
@@ -1,284 +0,0 @@
context(
'Landing pages - verifies required elements',
{ tags: '@smoke' },
() => {
const navbar = 'nav .navbar';
const mobileNav = '[data-testid="menu-drawer"]';
const topLevelLinks = [
{
name: 'Proposals',
selector: '[href="/proposals"]',
tests: () => {
it('should be able to see a working link for - find out more about Vega governance', function () {
const governanceDocsUrl = 'https://vega.xyz/governance';
const proposalDocumentationLink =
'[data-testid="proposal-documentation-link"]';
// 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
const newProposalLink = '[data-testid="new-proposal-link"]';
cy.get(newProposalLink)
.should('be.visible')
.and('have.text', 'New proposal')
.and('have.attr', 'href')
.and('equal', '/proposals/propose');
});
},
},
{
name: 'Validators',
selector: '[href="/validators"]',
tests: () => {
it('Should have Staking Guide link visible', function () {
// 2001-STKE-003
cy.get('[data-testid="staking-guide-link"]')
.should('be.visible')
.and('have.text', 'Read more about staking on Vega')
.and(
'have.attr',
'href',
'https://docs.vega.xyz/mainnet/concepts/vega-chain/#staking-on-vega'
);
});
},
},
{
name: 'Rewards',
selector: '[href="/rewards"]',
header: 'Rewards and fees',
tests: () => {
it('should have epoch warning', () => {
cy.get('[data-testid="callout"]')
.should('be.visible')
.and(
'have.text',
'Rewards are credited less than a minute after the epoch ends.This delay is set by a network parameter'
);
});
it('should have toggle for seeing total vs individual rewards', () => {
cy.get('[data-testid="epoch-reward-view-toggle-total"]').should(
'be.visible'
);
});
},
},
];
const secondLevelLinks = [
{
trigger: true,
name: 'Token',
selector: '[data-testid="state-trigger"]',
},
{
name: 'Token',
selector: '[href="/token"]',
header: 'The $VEGA token',
},
{
name: 'Supply & Vesting',
selector: '[href="/token/tranches"]',
header: 'Vesting tranches',
},
{
name: 'Withdraw',
selector: '[href="/token/withdraw"]',
header: 'Withdrawals',
tests: () => {
it('should have connect Vega wallet button', function () {
cy.get('[data-testid="connect-to-vega-wallet-btn"]')
.should('be.visible')
.and('have.text', 'Connect Vega wallet');
});
},
},
{
name: 'Redeem',
selector: '[href="/token/redeem"]',
header: 'Vesting',
tests: () => {
// 1005-VEST-018
it('should have connect Eth wallet button', function () {
cy.get('[data-testid="connect-to-eth-btn"]')
.should('be.visible')
.and('have.text', 'Connect Ethereum wallet');
});
},
},
{
name: 'Associate',
selector: '[href="/token/associate"]',
header: 'Associate $VEGA tokens with Vega Key',
},
{
name: 'Disassociate',
selector: '[href="/token/disassociate"]',
header: 'Disassociate $VEGA tokens from a Vega key',
},
];
const expand = () => {
const trigger = secondLevelLinks.find((l) => l.trigger).selector;
cy.get(trigger).then((el) => {
if (el.attr('aria-expanded') === 'false') {
el.trigger('click');
}
});
};
const collapse = () => {
const trigger = secondLevelLinks.find((l) => l.trigger).selector;
cy.get(trigger).then((el) => {
if (el.attr('aria-expanded') === 'true') {
el.trigger('click');
}
});
};
const ensureHeader = (text) => {
cy.get('main header h1').should('have.text', text);
};
before(() => {
// goes to HOME
cy.visit('/');
// and waits for it to load
cy.get(navbar, { timeout: 10000 }).should('be.visible');
});
describe('Navigation (desktop)', () => {
for (const { name, selector } of topLevelLinks) {
it(`should have ${name} nav link`, () => {
cy.get(navbar).within(() => {
cy.get(selector).should('be.visible');
cy.get(selector).should('have.text', name);
});
});
}
for (const { name, selector, trigger } of secondLevelLinks) {
it(`should have ${name} ${
trigger ? 'as trigger button' : ''
} second level nav link`, () => {
cy.get(navbar).within(() => {
cy.get(selector).should('be.visible');
cy.get(selector).should('have.text', name);
if (trigger) cy.get(selector).click();
});
});
}
after(() => {
collapse();
});
});
describe('Navigation (mobile)', () => {
beforeEach(() => {
// iphone xr
cy.viewport(414, 896);
});
it('should have burger button', () => {
cy.get('[data-testid="button-menu-drawer"]').should('be.visible');
cy.get('[data-testid="button-menu-drawer"]').click();
cy.get(mobileNav).should('be.visible');
});
for (const { name, selector } of topLevelLinks) {
it(`should have ${name} nav link`, () => {
cy.get(mobileNav).within(() => {
cy.get(selector).should('be.visible');
cy.get(selector).should('have.text', name);
});
});
}
for (const { name, selector, trigger } of secondLevelLinks) {
it(`should have ${name} ${
trigger ? 'as trigger button' : ''
} second level nav link`, () => {
cy.get(mobileNav).within(() => {
cy.get(selector).should('be.visible');
cy.get(selector).should('have.text', name);
});
});
}
after(() => {
cy.get('[data-testid="button-menu-drawer"]').click();
cy.viewport(
Cypress.config('viewportWidth'),
Cypress.config('viewportHeight')
);
});
});
describe('Elements', () => {
for (const { name, selector, header, tests } of topLevelLinks) {
describe(`${name} page`, () => {
it(`navigates to ${name}`, () => {
cy.get(navbar).within(() => {
cy.log(`goes to ${name}`);
cy.get(selector).click();
cy.log(`ensures ${name} is highlighted`);
cy.get(selector).should('have.attr', 'aria-current');
});
});
it('displays header', () => {
ensureHeader(header || name);
});
if (tests) tests.apply(this);
});
}
for (const { name, selector, header, tests } of secondLevelLinks.filter(
(l) => !l.trigger
)) {
describe(`${name} page`, () => {
it(`navigates to ${name}`, () => {
cy.get(navbar).within(() => {
expand();
cy.log(`goes to ${name}`);
cy.get(selector).click();
expand();
cy.log(`ensures ${name} is highlighted`);
cy.get(selector).should('have.attr', 'aria-current');
});
});
it('displays header', () => {
ensureHeader(header || name);
});
if (tests) tests.apply(this);
});
}
after(() => {
collapse();
});
});
}
);
@@ -0,0 +1,164 @@
import {
navigateTo,
navigation,
verifyPageHeader,
verifyTabHighlighted,
} 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 newProposalLink = '[data-testid="new-proposal-link"]';
const governanceDocsUrl = 'https://vega.xyz/governance';
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
context(
'Governance Page - verify elements on page',
{ tags: '@smoke' },
function () {
before('navigate to governance page', function () {
cy.visit('/');
navigateTo(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 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 tag: v1'
);
cy.getByTestId('protocol-upgrade-proposal-block-height').should(
'have.text',
'Upgrade block height: 2015942'
);
cy.getByTestId('protocol-upgrade-proposal-status').should(
'have.text',
'Approved '
);
});
});
cy.getByTestId('closed-proposals').within(() => {
cy.getByTestId('protocol-upgrade-proposals-list-item').should(
'have.length',
1
);
});
});
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', '%');
}
);
});
});
}
);
@@ -1,47 +1,61 @@
/// <reference types="cypress" />
import {
navigateTo,
navigation,
waitForSpinner,
} from '../../support/common.functions';
import {
enterUniqueFreeFormProposalBody,
goToMakeNewProposal,
} from '../../support/governance.functions';
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions';
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey2');
const vegaPubkeyTruncated = Cypress.env('vegaWalletPublicKey2Short');
const banner = 'view-banner';
context('View functionality with public key', { tags: '@smoke' }, function () {
before('send asset to wallet', function () {
cy.vega_wallet_faucet_assets_without_check(
'fUSDC',
vegaWalletFaucetAssetsWithoutCheck(
'816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc',
'1000000',
vegaWalletPubKey
);
});
beforeEach('visit home page', function () {
cy.clearLocalStorage();
cy.visit('/');
cy.wait_for_spinner();
waitForSpinner();
cy.connectPublicKey(vegaWalletPubKey);
});
it('Able to connect public key via wallet', function () {
verifyConnectedToPubKey();
cy.getByTestId('currency-title', Cypress.env('epochTimeout')).should(
'contain.text',
'USDC (fake)'
);
});
it('Able to connect public key using url', function () {
cy.getByTestId('exit-view').click();
cy.visit(`/?address=${vegaWalletPubKey}`);
verifyConnectedToPubKey();
});
it('Able to connect public key via wallet and view assets in wallet', function () {
verifyConnectedToPubKey();
cy.getByTestId('currency-title', { timeout: 10000 })
.should('have.length.at.least', 4)
.and('contain.text', 'USDC (fake)');
});
it('Unable to submit proposal with public key', function () {
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
cy.navigate_to('proposals');
cy.go_to_make_new_proposal('Freeform');
cy.enter_unique_freeform_proposal_body('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);
});
navigateTo(navigation.proposals);
goToMakeNewProposal('Freeform');
enterUniqueFreeFormProposalBody('50', 'pub key proposal test');
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 () {
@@ -0,0 +1,79 @@
import {
navigateTo,
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"]';
context(
'Rewards Page - verify elements on page',
{ tags: '@regression' },
function () {
before('navigate to rewards page', function () {
cy.clearLocalStorage();
cy.visit('/');
navigateTo(navigation.rewards);
});
describe('with wallets disconnected', function () {
it('should have REWARDS tab highlighted', function () {
verifyPageHeader('Rewards and fees');
});
it('should have rewards header visible', function () {
verifyPageHeader('Rewards and fees');
});
it('should have epoch warning', function () {
cy.get(warning)
.should('be.visible')
.and(
'have.text',
'Rewards are credited less than a minute after the epoch ends.This delay is set by a network parameter'
);
});
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');
});
});
}
);

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