Compare commits

...
Author SHA1 Message Date
Matthew Russell 239f5c7c2a chore: fix lint 2023-11-02 16:56:10 -07:00
Matthew Russell 5819421daa test: fix tests 2023-11-02 14:59:07 -07:00
Matthew Russell 228f468f69 fix: amount validation should use selected account, use max button 2023-11-02 14:23:47 -07:00
Matthew Russell 8625ab22e9 chore: rename toAddress for clarity 2023-11-02 13:46:50 -07:00
Matthew Russell 7812bd8fa9 fix: always show the key dropdown even if only single key 2023-11-02 13:44:48 -07:00
Edd 06cfd79415 feat(explorer): add timestamp to tx list (#5174) 2023-11-02 13:22:37 +00:00
Edd 443220283c fix(explorer): format new network params correctly (#5172) 2023-11-02 13:17:11 +00:00
Matthew Russell a642bf8ce4 chore(trading): misc changes to trades and transfer (#5175) 2023-11-01 15:57:38 -07:00
Matthew Russell 20233db706 fix(deal-ticket): fees breakdown rendering issues (#5173) 2023-11-01 13:32:51 -07:00
m.ray d4f50eb70c fix(trading): pagination limit for candles (#5169) 2023-11-01 12:21:36 -07:00
Matthew Russell e5d3f90d45 feat(trading): transfer to and from accounts on same key (#5161) 2023-11-01 11:11:17 +00:00
Bartłomiej Głownia 673c896e2f feat(deal-ticket): get discounts for estimation from previous epoch (#5163) 2023-11-01 10:09:56 +00:00
Matthew Russell deea63fa5e fix(trading): empty items loaded text (#5158) 2023-11-01 10:08:16 +00:00
Matthew Russell d31333538b chore(trading): ignore .next from lint (#5162) 2023-11-01 10:06:53 +00:00
Matthew Russell 4af9979a21 chore(trading): referrals stats tweaks (#5160) 2023-11-01 10:06:36 +00:00
m.ray 6421cf87c6 feat(trading): liquidity provision current and pending on update (#5152) 2023-10-31 11:24:18 +00:00
Matthew Russell 0ebfab64ff fix(ui-toolkit): sparkline appearing to go up when the price moved down (#5137) 2023-10-31 11:20:48 +00:00
Edd 142f08343b feat(governance): add update benefit tiers table (#5146) 2023-10-31 10:20:38 +00:00
m.ray 61aa45a9ed feat(trading): show fees paid across whole market (#5154) 2023-10-30 18:16:49 -07:00
Bartłomiej GłowniaandMatthew Russell 4c95db5fb3 feat(deal-ticket): calculate fees and discount base on volumeDiscountStats and referralSetStats (#5147)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-10-30 18:13:26 -07:00
ArtandMatthew Russell 3072b7824f fix(trading): referrer stats tiles (#5143)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-10-30 18:12:59 -07:00
Bartłomiej Głownia 0580e90171 feat(funding-payments): add load more button to the funding payments table (#5150) 2023-10-30 15:57:43 -07:00
Bartłomiej Głownia c440abc77d feat(trading): show full history of orders, fills and trades (#5105) 2023-10-27 14:21:26 +01:00
Matthew Russell fbafc726a4 feat(candles-chart): combine overlays and studies into indicators dropdown (#5129) 2023-10-27 14:21:14 +01:00
Joe Tsang dd1890d8c6 chore(cypress): fix failing assertions (#5132) 2023-10-27 14:21:02 +01:00
Matthew Russell c8e624eaba chore(trading): update fee factor with discount calculation (#5138) 2023-10-27 14:20:45 +01:00
Art cc6629ad27 fix(trading): referrals next tier tiles (#5139) 2023-10-27 13:48:43 +02:00
Art 9838efa00e feat(proposals): generic proposal toasts (#5134) 2023-10-27 13:17:51 +02:00
m.ray dac7142a98 feat(trading): add earmarked fees (#5123) 2023-10-27 13:09:01 +02:00
Matthew Russell 1397aafd25 fix(ui-toolkit): sparkline red shaded area color 2023-10-26 10:19:05 -07:00
Matthew Russell b192603e57 feat(ui-toolkit): sparkline shaded area (#5131) 2023-10-26 10:06:05 -07:00
Matthew Russell 8c2c8d987c feat(trading): add row click for fees table (#5130) 2023-10-26 08:38:52 -07:00
Matthew Russell 52c96794f7 feat(trading): fees page (#5055) 2023-10-25 14:59:30 -07:00
Ben 58ce016d4d chore(trading): suspend market test to console test (#5128) 2023-10-25 16:21:11 +01:00
Ben ac16eb06f5 chore(trading): delete fills cypress tests (#5122) 2023-10-25 14:02:43 +01:00
Ben 3319871617 chore(trading): delete dupe transfer tests (#5121) 2023-10-25 12:29:21 +00:00
Bartłomiej Głownia 37e850304a feat(trading): upgrade pennant@1.14.0 (#5120) 2023-10-25 12:44:23 +01:00
daro-maj 655131c744 test(trading): fix capsule test (#5116) 2023-10-25 12:39:18 +01:00
m.ray f1cb1b9408 fix(trading): quote base unit for size (#5124) 2023-10-25 12:36:57 +01:00
m.ray 891ac527a2 feat(trading): add tooltips for iceberg and post or reduce only (#5119) 2023-10-25 12:18:52 +01:00
Art 546087fb9f chore(trading): referrals with sidebar (#5117) 2023-10-25 11:14:00 +02:00
BenandMatthew Russell f7a82d33ba chore(trading): withdraw tests to jest (#5109)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-10-25 08:45:58 +01:00
Matthew Russell d85f413e41 chore(trading,positions): update estimatePosition query to use market decimals for liquidation price (#5005) 2023-10-24 17:30:17 -07:00
Edd c7d0025b4f feat(explorer): add determinsitic id to transfer tx (#5112) 2023-10-24 16:48:17 +01:00
Art 6c9272cd53 chore(trading): i18n-friendly referrals (#5113) 2023-10-24 17:43:33 +02:00
m.rayandasiaznik 82fb29d541 feat(trading): add liquidity provision new SLA parameters to liquidity tables (#5032)
Co-authored-by: asiaznik <artur@vegaprotocol.io>
2023-10-24 10:32:07 +01:00
Art 43cd170c77 feat(trading): referrals (Mk2), referrals stats, apply preview (#5021) 2023-10-23 16:57:18 +02:00
Edd 1d39f81dfc fix(governance): remove restricted route from navigation (#5106) 2023-10-23 14:16:07 +00:00
Bartłomiej Głownia f5868b6f1b feat(trading): show when a market may be closed through governance (#5057) 2023-10-23 13:42:37 +02:00
m.ray 20e1522088 chore(trading): use quantum for liquidity supplied (#5099) 2023-10-23 10:24:26 +01:00
Radosław Szpiech ae02b153f8 chore(trading): fix cancel all button and move trading orders tests (#5100) 2023-10-23 08:34:50 +02:00
Maciek fee5f862a7 chore(trading): remove account history tab (#5098) 2023-10-20 15:08:19 +02:00
Edd c25362b084 feat(governance): add restricted page (#5097) 2023-10-20 11:27:14 +00:00
Edd 7c105d2c6b feat(explorer): add restricted route (#5094) 2023-10-19 18:28:33 +00:00
Maciek 2dfcb02d1e chore(orders): 4970 add no rows and error info (#5076) 2023-10-19 14:45:55 +01:00
Sam Keen a98ab775c3 feat(governance): transfers destination field can fallback to type (#5092) 2023-10-19 11:16:00 +01:00
Maciek 097bf7c08c chore(trading): add button for copying asset id (#5075) 2023-10-18 17:02:34 +02:00
Bartłomiej Głowniaandbwallacee 236e35a92b feat(trading): show successor banner if market is settled or successor market exists (#5056)
Co-authored-by: bwallacee <ben@vega.xyz>
2023-10-18 14:48:52 +02:00
Maciek abf84b9d45 chore(ui-toolkit): 4970 async renderer - improve error handling (#5063) 2023-10-18 11:11:05 +02:00
m.ray 6d2a2ea0a0 chore(trading): update snap version to 0.3.1 (#5059) 2023-10-18 09:56:50 +01:00
Matthew Russell 6ac79e9f6d chore(trading,explorer,governance): update codeowners so dev team only is required for reviews 2023-10-17 20:14:48 -07:00
Matthew Russell 835ee64243 fix(trading): hydration error due to loader (#5043) 2023-10-17 20:05:53 -07:00
Matthew Russell e7c3b5054c fix(trading): market selector dropdown not updating (#5027) 2023-10-17 09:56:48 -07:00
Maciek 9dc9588a14 chore(ledger): 4895 refactor ledger csv extract (#5053) 2023-10-17 17:15:38 +02:00
Ben a0844d41bf chore(trading): move transfer test to jest (#5058) 2023-10-17 10:56:21 +01:00
m.ray 3d1aa74128 fix(trading): liquidation price tooltip link (#5050) 2023-10-17 10:44:49 +01:00
Ben 2376bfe58f chore(trading): deposit test to jest (#5036) 2023-10-16 11:44:37 -07:00
Matthew Russell 72ccf96523 fix(trading): remove additional page for closed markets (#5042) 2023-10-16 11:18:26 -07:00
Matthew Russell f416fa4a25 chore(trading,explorer,governance): adjust codeowners to require reviews from both teams (#5054) 2023-10-16 16:11:19 +01:00
Matthew Russell a24e3646cc fix(trading): glitchy waterfall loading (#5039) 2023-10-16 07:49:23 -07:00
Art 55b092b216 fix(trading): update referral program proposal changes (#5030) 2023-10-16 16:45:00 +02:00
Matthew Russell ef4cf6a87e chore(assets): add testnet deny list (#5044) 2023-10-16 07:41:31 -07:00
Sam Keen c9860a3412 fix(governance): governance initiated transfers fixes (#5025) 2023-10-16 12:02:06 +01:00
m.ray 127bd3faf3 chore(trading): code owners fix for two reviewers (#5046) 2023-10-16 12:00:20 +01:00
Bartłomiej Głownia 1791b3ca6a feat(trading): adjust layout for funding payments (#5034) 2023-10-16 11:19:08 +02:00
Matthew Russell 6044b86ff4 chore(trading): add background to sidebar and minor tweaks (#5037) 2023-10-13 11:30:04 -07:00
Matthew Russell 341d78e761 chore(trading): fix hydration errors and improve loading experience (#5038) 2023-10-13 16:02:33 +02:00
Joe Tsanganddaro-maj 58cc074538 test(governance): governance transfer proposal tests (#5011)
Co-authored-by: daro-maj <119658839+daro-maj@users.noreply.github.com>
2023-10-12 18:48:39 +02:00
Bartłomiej Głownia 852c9bb8f4 feat(trading): display fees discounts (#4800) 2023-10-12 16:58:57 +02:00
Maciek efe9b7a0e7 chore(trading): upgrade pennant version (#5023) 2023-10-12 13:18:17 +00:00
daro-maj 695a059dde test(trading): add funding spec (#5028) 2023-10-12 11:58:32 +01:00
Maciek 5d7e4d273a chore(trading): add timezone note to the ledger entries form (#5018) 2023-10-12 09:12:54 +00:00
Sam Keen b137e024c6 feat(governance): volume discount proposals (#5022) 2023-10-11 18:51:52 +00:00
Ben 6651ee52b4 chore(trading): oracle banner test (#5020) 2023-10-11 15:54:26 +01:00
m.rayandRado 0d14722c5d feat(trading): add risk factors leverage and update accordion panel (#5000)
Co-authored-by: Rado <szpiechrados@gmail.com>
2023-10-11 10:19:43 +01:00
Sam Keen 4968b537b8 feat(governance): referral proposals (#5013) 2023-10-11 09:11:35 +00:00
Bartłomiej Głownia 5f5c45f3b9 feat(trading): display empty values for funding and countdown if perp market is in auction (#4987) 2023-10-10 16:59:31 +01:00
MaciekandMatthew Russell 6b10df015d feat(trading): 4387 market terminate warning banner (#4912)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-10-10 17:50:49 +02:00
Ben 6d7e24732b chore(trading): transfer form test to jest (#5010) 2023-10-10 14:37:06 +01:00
Matthew Russell b33cf04e16 fix(trading): flickering of market loading (#5006) 2023-10-10 14:20:27 +01:00
Ben 66ebb26b0f chore(trading): deal ticket tif tests (#5009) 2023-10-10 13:05:02 +01:00
Ben 51c88d2fce chore(trading): move trades tests to jest (#5001) 2023-10-10 11:13:23 +01:00
daro-maj 2786a984b0 test(trading): remove portfolio test (#5007) 2023-10-10 10:02:09 +01:00
Maciek 39c53a7326 chore(trading): 4858 redesign market header (#4976) 2023-10-10 10:45:09 +02:00
Radosław Szpiech 3371e8e2cc Merge pull request #5004 from vegaprotocol/chore/fix-multiline-condition
chore(ci): merge main fixes to develop
2023-10-10 10:17:49 +02:00
Rado 5843a36851 Merge remote-tracking branch 'origin/main' into chore/fix-multiline-condition 2023-10-09 17:29:36 +02:00
Radosław Szpiech 68b4909dff chore(ci): fix badly written condition in workflow (#5002) 2023-10-09 17:24:18 +02:00
Bartłomiej Głownia da8e382454 feat(trading): add funding payment history (#4989) 2023-10-09 16:59:00 +02:00
81ebefc329 chore(trading): accounts test to jest (#4984)
Co-authored-by: daro-maj <119658839+daro-maj@users.noreply.github.com>
Co-authored-by: Bartłomiej Głownia <bglownia@gmail.com>
Co-authored-by: Mikołaj Młodzikowski <mikolaj.mlodzikowski@gmail.com>
2023-10-09 10:09:10 +01:00
Bartłomiej Głownia 1ed7d6fda2 feat(positions): add closed markets filter to positions in portfolio (#4982) 2023-10-09 08:28:21 +02:00
Radosław Szpiech a2e4f34b0d Merge pull request #4996 from vegaprotocol/chore/update-develop
chore(ci): merge main changes to develop
2023-10-06 16:43:05 +02:00
Rado 3a1bb855aa Merge remote-tracking branch 'origin/main' into chore/update-develop 2023-10-06 16:14:09 +02:00
Radosław Szpiech b4ca0a8390 chore(ci): run console-test on PR again (#4995) 2023-10-06 16:12:13 +02:00
Radosław Szpiech 349c790ecc Merge pull request #4993 from vegaprotocol/chore/update-develop-with-main
chore(ci,governance): update develop with latest main changes
2023-10-06 13:52:19 +02:00
Rado 4c8a15cc01 chore(governance): merge main 2023-10-06 12:57:32 +02:00
Radosław Szpiech f433a030ff chore(ci): separate export docker image job in console-test workflow (#4980) 2023-10-06 10:47:38 +00:00
Joe Tsang 63a6e4ecbd chore(governance): fix failing link test (#4990) 2023-10-06 12:00:21 +02:00
Joe Tsang 555f6e2a6d chore(explorer): fix failing market test (#4992) 2023-10-06 11:20:12 +02:00
Matthew Russell c116762865 fix(trading,wallet): set version for vega snap (#4991) 2023-10-05 14:18:40 -04:00
Joe Tsang b47bd49e83 test(governance): skip staking test (#4974) 2023-10-05 14:22:08 +00:00
Ben 4b942cfb7d chore(ci): add release label on release (#4985) 2023-10-05 13:28:24 +01:00
Mikołaj Młodzikowski c27443fc13 feat(ci): add workflow to clean up caches on closed PRs (#4988) 2023-10-05 12:46:22 +02:00
Bartłomiej Głownia 6dbde76c84 chore(wallet): remove dependency on apollo from wallet lib (#4814) 2023-10-05 11:25:54 +02:00
daro-maj f4abd7cef5 test(trading): remove account test (#4983) 2023-10-05 10:05:02 +02:00
Bartłomiej Głownia 3b978118dc feat(deal-ticket): fix margin and fees alignment (#4956) 2023-10-05 07:40:25 +02:00
Ben bb4cc1e51d chore(trading): set default sort order (#4978) 2023-10-05 00:12:47 +01:00
Bartłomiej Głownia 797db6ee93 feat(ui-toolkit): increase checkbox and radio clickable area (#4906) 2023-10-04 12:50:02 +02:00
Radosław Szpiech 6e7b87d9ef Merge pull request #4972 from vegaprotocol/chore/merge-main-pull-requests
chore(trading): merge main to develop
2023-10-04 12:02:11 +02:00
Madalina Raicu 6965bdf0ca chore: remove closed markets 2023-10-03 18:40:36 +01:00
Madalina Raicu f4d46efff5 Merge branch 'main' of github.com:vegaprotocol/frontend-monorepo into chore/merge-main-pull-requests 2023-10-03 18:21:10 +01:00
Art d510330c6b feat(governance): governance transfers (#4411) 2023-10-03 15:35:17 +00:00
Ben 5b5765ef63 chore(trading): add accounts jest test (#4962) 2023-10-03 15:16:24 +00:00
Bartłomiej Głownia 283f654a4c chore(trading): upgrade pennant (#4967) 2023-10-03 13:00:35 +01:00
Radosław Szpiech 6945514b49 chore(ci): quotes and double brackets change (#4965) 2023-10-03 12:57:17 +01:00
Maciek f74687d30c chore(trading): 4947 cant view settled market main (#4964) 2023-10-03 12:31:05 +01:00
m.ray 2a7574bd8e fix(governance): add wallet connect project ID (#4966) 2023-10-03 12:30:24 +01:00
Matthew RussellandMadalina Raicu 872f1d300f fix(wallet): dont show error state if user rejects connection (#4901)
Co-authored-by: Madalina Raicu <madalina@raygroup.uk>
2023-10-03 12:21:19 +01:00
Mikołaj Młodzikowski 600ea0eeab Revert "Update Jenkinsfile"
This reverts commit 7c3f7a7ab1.
2023-10-03 12:30:39 +02:00
Mikołaj Młodzikowski 7c3f7a7ab1 Update Jenkinsfile
feat(ci): check jenkins execution
2023-10-03 12:15:03 +02:00
Maciek 539abce8af chore(trading): cant view settled market (#4958) 2023-10-03 11:08:30 +01:00
Bartłomiej Głownia 60ca6c2eb6 feat(trading): show fills for all markets (#4951) 2023-10-03 11:00:26 +01:00
Art eeff4ffcd4 fix(trading): missing wallet connect button (#4960) 2023-10-03 10:53:32 +01:00
Radosław Szpiech 73ae00f12c chore(ci): add missing quote marks that may have caused some workflow fails (#4963) 2023-10-03 10:44:12 +01:00
Art ee73e4d5e2 fix(trading): missing wallet connect button (#4959) 2023-10-03 10:38:37 +01:00
Joe Tsang 14928d318d chore(governance): add e2e tests for market update proposals (#4945) 2023-10-02 20:50:47 +01:00
m.ray a19ea1c939 fix(trading): update filter for market selector to include suspended via governance (#4957) 2023-10-02 18:00:49 +01:00
m.rayandMatthew Russell c65c296db2 feat(trading): ethereum oracle spec in oracle panels (#4914)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-10-02 17:48:12 +01:00
Maciek 6c5cd85d96 fix(deal-ticket): prevent empty call estimate position (#4950) 2023-10-02 18:26:10 +02:00
m.ray 8efadda98c fix(trading): remove market value proxy and formatting (#4916) 2023-10-02 16:00:55 +01:00
Maciek 0872a14f44 feat(positions): close position with max possible size (#4940) 2023-10-02 16:38:22 +02:00
Radosław Szpiech 8b249e1917 chore(ci): fix some minor issues in workflows (#4953) 2023-10-02 16:12:24 +02:00
Ben 13817e4d57 chore(trading): delete duplicate asset details test (#4954) 2023-10-02 13:57:54 +00:00
Radosław Szpiech abb771e2f9 chore(ci): add conditions to run e2e tests (#4946) 2023-10-02 14:29:59 +02:00
Edd acf1d50d0f chore(explorer): ignore errors on oracle page (#4944) 2023-09-29 17:29:16 +01:00
Matthew Russell 9da704c117 Merge pull request #4943 from vegaprotocol/chore/merge-main
chore(ci): merge main to develop
2023-09-29 12:11:25 -04:00
Rado d262650258 chore: merge main to develop 2023-09-29 17:46:20 +02:00
Radosław Szpiech 30da1663eb chore(ci): add main develop merge condition to runner (#4941) 2023-09-29 17:36:18 +02:00
Radosław Szpiech 79cbe62774 chore(ci): add mainnet compatible runner to release mainnet branch push actions (#4939) 2023-09-29 11:00:20 -04:00
Matthew Russell df11401b69 Merge pull request #4932 from vegaprotocol/main
chore(ci,trading): update develop with mainnet fixes
2023-09-29 10:33:42 -04:00
Maciek 2f0be0bf34 chore(trading): 4774 put connect dialog inside onboarding dialog - main branch (#4920) 2023-09-29 15:07:18 +02:00
Radosław Szpiech 5b5802104e chore(ci): trigger lint-pr on repoened and sync (#4937) 2023-09-29 15:03:58 +02:00
Radosław Szpiech 3a149ddfb2 chore(ci): add mainnet compatible runner to release mainnet branch push actions (#4936) 2023-09-29 14:01:04 +02:00
Sam Keen 0e519f4d0e feat(governance): market state update proposals (#4935) 2023-09-29 10:11:02 +01:00
Maciek ff2e2574f6 chore(trading): add handle of autosizing selected columns - main branch (#4888) 2023-09-28 15:14:32 -04:00
Joe Tsang 9b52cecf21 chore(governance): remove explorer market diff test (#4928) 2023-09-28 17:24:05 +01:00
Radosław Szpiech 478cc9e753 chore(ci): publish main image in dockerhub (#4930) 2023-09-28 17:38:00 +02:00
Ben 18f1fbd56d chore(trading): deal ticket order tests move (#4927) 2023-09-28 17:16:00 +02:00
Matthew Russell ccb22f02c3 chore(ci): fix conflict in vegacapsule genesis file 2023-09-28 10:44:22 -04:00
Radosław Szpiech 015d8f51c0 chore(ci): sync main to develop (#4924) 2023-09-28 14:43:02 +02:00
Radosław Szpiech e2a72cb395 chore(ci): separate lint pr (main) (#4917) 2023-09-28 14:01:36 +02:00
Radosław Szpiech 0669696b6f chore(ci): fix node version (develop) (#4910) 2023-09-28 13:30:50 +02:00
Joe Tsang 56c662e5ba test(governance): perpetual market e2e test (#4892) 2023-09-28 11:35:46 +02:00
Radosław Szpiech 7fe269fad6 chore(ci): fix node version (main) (#4911) 2023-09-28 11:26:15 +02:00
Radosław Szpiech b761023069 chore(ci): add logic for choosing correct runner for cypress tests depending on base branch (#4918) 2023-09-28 11:25:44 +02:00
Radosław Szpiech 7453acd632 chore(trading): separate workflow for lint-pr (#4904) 2023-09-27 14:44:57 -04:00
Sam Keen 1f507facba feat(governance): show perp or future pills (#4863) 2023-09-27 14:55:43 +01:00
Radosław Szpiech 9d6b34963a chore(trading): add possibility to manualy trigger console-test (#4899) (#4908) 2023-09-27 15:46:49 +02:00
Radosław Szpiech 7ac3a68ac9 chore(trading): add possibility to manualy trigger console-test (#4899) 2023-09-27 15:18:32 +02:00
Radosław Szpiech 2640ccb20a chore(trading): change runner for mainnet compatible vega version (#4907) 2023-09-27 14:42:12 +02:00
Matthew Russell 77c0894501 Merge pull request #4905 from vegaprotocol/chore/update-develop-with-mainnet-fixes
chore(trading,deal-ticket,market-depth,ci): update develop with mainnet fixes
2023-09-26 16:30:10 -04:00
Matthew Russell 60d7cf3029 Merge branch 'main' into chore/update-develop-with-mainnet-fixes 2023-09-26 15:06:07 -04:00
Matthew Russell 2b8abde938 Merge pull request #4880 from vegaprotocol/chore/update-develop-with-mainnet-fixes
chore(trading,governance): update develop with mainnet fixes
2023-09-26 14:06:20 -04:00
Matthew Russell 2005f19d50 fix(trading): prevent deposit sidebar showing on corresponding standalone page (#4840) 2023-09-26 13:47:47 -04:00
Maciek d78de10855 chore(trading): remove underlines on tooltips (#4884) 2023-09-26 13:45:33 -04:00
Matthew Russell bb402c02f6 chore(trading): make volume bars color match candle color (#4881) 2023-09-26 12:08:12 -04:00
Bartłomiej Głownia 8a9b1c7874 feat(deal-ticket): amend fee estimates for postOnly orders and when market is in auction (#4843) 2023-09-26 11:57:47 -04:00
Matthew Russell a7e8b0eb01 fix(market-depth): ensure scroll bar doesn't show on orderbook (#4882) 2023-09-26 11:54:42 -04:00
Bartłomiej Głownia 89b3c06107 feat(deal-ticket): show worst case instead of ranges in estimated values (#4870) 2023-09-26 11:53:45 -04:00
Radosław Szpiech cd5c73d3fd chore(trading): temporary disable console-test to unblock CI queue (#4885) 2023-09-26 10:45:27 +01:00
Joe Tsang b3a5ab022d chore(ci): update genesis file (#4887) 2023-09-26 10:44:55 +01:00
Matthew Russell ba438549bc Merge branch 'main' into chore/update-develop-with-mainnet-fixes 2023-09-25 21:30:40 -04:00
Mikołaj Młodzikowski 496d1f5c68 feat(ci): parse if there are any changes 2023-09-25 18:10:01 -04:00
Mikołaj Młodzikowski e914e7bb70 fix(ci): provide proper ipfs process 2023-09-25 18:09:31 -04:00
Matthew Russell 71a36c2382 fix(trading): remove upgrade banner [main] (#4877) 2023-09-25 17:27:01 -04:00
Matthew Russell 1c6a307bcd fix(wallet): reduce time to check for wallet running [main] (#4876) 2023-09-25 17:26:40 -04:00
Matthew Russell ef4a740b91 fix(trading): allotment breaking [main] (#4875) 2023-09-25 17:26:06 -04:00
a6303456c5 feat(trading): liquidity SLA in market info (#4649)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
Co-authored-by: Bartłomiej Głownia <bglownia@gmail.com>
Co-authored-by: Joe Tsang <30622993+jtsang586@users.noreply.github.com>
Co-authored-by: Joe <joe@vega.xyz>
2023-09-25 14:44:55 +01:00
Sam Keen 2d4be5fcb3 fix(governance): mainnet rewards query looping (#4865) 2023-09-25 09:59:38 +00:00
Sam Keen 9cbd6baccd fix(governance): removed loop caused by rewards epoch refresh (#4864) 2023-09-25 09:34:47 +00:00
Maciek 525773773a chore(trading): 4811 make market table columns resizable (#4856) 2023-09-25 10:14:18 +02:00
Ben 45d6f43e74 chore(trading): deal ticket test to jest (#4842) 2023-09-22 15:25:50 +01:00
Art 41760f2956 chore(trading): disable apply code when applied (#4855) 2023-09-22 12:06:02 +01:00
Maciek 3d2b171de7 chore(trading): 4774 put connect dialog inside onboarding dialog (#4845) 2023-09-22 11:04:02 +02:00
Joe Tsang 39a041332b chore(governance): fix failing proposal submission (#4835) 2023-09-22 09:40:35 +01:00
Bartłomiej Głownia 4c0d05844e feat(trading): improve funding rate formatting (#4847) 2023-09-22 09:39:56 +01:00
Matthew Russell bf8480fed4 chore(trading): remove upgrade banner (#4852) 2023-09-22 09:39:26 +01:00
ArtandMatthew Russell 44434a7d39 feat(trading): referrals (Mk1) (#4816)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-09-21 14:25:19 +01:00
m.ray b818e9b2a1 fix(trading): ignore conditions list empty (#4848) 2023-09-21 14:24:21 +01:00
Radosław Szpiech 775835c667 chore(trading): disable console-test run until CI fixed (#4846) 2023-09-21 14:32:17 +02:00
Matthew Russell 3e30f053ff chore(trading): routing and link changes (#4738) 2023-09-20 13:28:34 -07:00
Bartłomiej GłowniaandMatthew Russell 5db3453ba5 fix(accounts): hide no rows label when there is only pinned row (#4833)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-09-20 20:03:07 +00:00
Matthew Russell 0b1987d4ce chore(trading,governance,explorer): prevent jobs if PR is in draft (#4827) 2023-09-20 11:13:43 -07:00
290b7ae856 feat(trading): browse perpetuals [stagnet1] (#4590)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
Co-authored-by: Bartłomiej Głownia <bglownia@gmail.com>
Co-authored-by: Joe Tsang <30622993+jtsang586@users.noreply.github.com>
Co-authored-by: Joe <joe@vega.xyz>
2023-09-20 10:11:03 +01:00
m.rayandMatthew Russell 835f2b793f chore(trading): remove static assets console coming from vega.xyz (#4825)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-09-19 23:54:07 -07:00
Mikołaj Młodzikowski e1557f51ce feat(ci): parse if there are any changes 2023-09-19 10:05:00 +02:00
Mikołaj Młodzikowski c98e53a984 fix(ci): provide proper ipfs process 2023-09-19 09:55:21 +02:00
MaciekandMatthew Russell 95a51fd152 chore(withdraws): standalone pages for withdraw and transfer (#4728)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-09-19 08:15:36 +02:00
Matthew Russell d50b988b4a Merge branch 'release/mainnet-trading' of github.com:vegaprotocol/frontend-monorepo into release/mainnet-trading 2023-09-18 09:03:44 -07:00
m.ray 76ee58e473 chore(trading): update tag metamask snaps to true (#4815) 2023-09-18 15:19:48 +01:00
Madalina Raicu a6aec899c8 chore: update tag metamask snaps to true 2023-09-18 15:08:46 +01:00
649 changed files with 22191 additions and 9216 deletions
@@ -82,3 +82,38 @@ jobs:
https://${{ env.IPFS_V1 }}.ipfs.dweb.link/ https://${{ env.IPFS_V1 }}.ipfs.dweb.link/
https://${{ env.IPFS_V1 }}.ipfs.cf-ipfs.com/ https://${{ env.IPFS_V1 }}.ipfs.cf-ipfs.com/
ipfs://${{ env.IPFS_V0 }}/ ipfs://${{ env.IPFS_V0 }}/
- name: Ensure 'Released' label exists
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
REPO="${{ github.repository }}"
LABEL_EXIST=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/$REPO/labels/Released")
if [[ "$LABEL_EXIST" == *"Not Found"* ]]; then
curl -s -H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-X POST "https://api.github.com/repos/$REPO/labels" \
-d '{"name": "Released", "color": "FFFFFF"}'
fi
- name: Extract issues from release notes
id: extract-issues
run: |
ISSUES=$(echo "${{ github.event.release.body }}" | grep -o -E '#[0-9]+' | tr -d '#' | jq -R . | jq -cs .)
echo "Issues to label: $ISSUES"
echo "::set-output name=issue_numbers::$ISSUES"
- name: Add 'Released' label to issues
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
ISSUE_NUMBERS="${{ steps.extract-issues.outputs.issue_numbers }}"
REPO="${{ github.repository }}"
for ISSUE in $(echo "$ISSUE_NUMBERS" | jq -r '.[]'); do
curl -s -H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-X POST "https://api.github.com/repos/$REPO/issues/$ISSUE/labels" \
-d '{"labels": ["Released"]}'
done
+35 -17
View File
@@ -5,15 +5,17 @@ on:
branches: branches:
- release/* - release/*
- develop - develop
- main
pull_request: pull_request:
types: types:
- opened - opened
- ready_for_review - ready_for_review
- reopened - reopened
- edited
- synchronize - synchronize
jobs: jobs:
node-modules: node-modules:
# All jobs depend on node_modules, so none should run if the PR is in draft
if: github.event.pull_request.draft == false
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
name: 'Cache yarn modules' name: 'Cache yarn modules'
steps: steps:
@@ -42,13 +44,6 @@ jobs:
if: steps.cache.outputs.cache-hit != 'true' if: steps.cache.outputs.cache-hit != 'true'
run: yarn install --pure-lockfile 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-format: lint-format:
timeout-minutes: 20 timeout-minutes: 20
needs: node-modules needs: node-modules
@@ -175,25 +170,48 @@ jobs:
preview_explorer: ${{ env.PREVIEW_EXPLORER }} preview_explorer: ${{ env.PREVIEW_EXPLORER }}
preview_tools: ${{ env.PREVIEW_TOOLS }} preview_tools: ${{ env.PREVIEW_TOOLS }}
console-e2e: check-e2e-needed:
runs-on: ubuntu-latest
needs: build-sources needs: build-sources
name: '(CI) console python' name: '(CI) check if e2e needed'
uses: ./.github/workflows/console-test-run.yml outputs:
secrets: inherit run-tests: ${{ steps.check-test.outputs.e2e-needed }}
if: ${{ contains(fromJSON(needs.build-sources.outputs.projects), 'trading') && github.event_name == 'pull_request' }} steps:
with: - name: Check branch
github-sha: ${{ github.event.pull_request.head.sha || github.sha }} id: check-test
run: |
if [[ "${{ github.base_ref }}" == "develop" ]]; then
echo "e2e-needed=true" >> $GITHUB_OUTPUT
elif [[ "${{ github.base_ref }}" == "main" ]]; then
echo "e2e-needed=true" >> $GITHUB_OUTPUT
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/"* ]]; then
echo "e2e-needed=true" >> $GITHUB_OUTPUT
else
echo "e2e-needed=false" >> $GITHUB_OUTPUT
fi
- name: Print result
run: |
echo "e2e-needed: ${{ steps.check-test.outputs.e2e-needed }}"
cypress: cypress:
needs: build-sources needs: [build-sources, check-e2e-needed]
name: '(CI) cypress' name: '(CI) cypress'
# if: ${{ needs.build-sources.outputs.projects-e2e != '[]' }} if: ${{ needs.check-e2e-needed.outputs.run-tests == 'true' }}
uses: ./.github/workflows/cypress-run.yml uses: ./.github/workflows/cypress-run.yml
secrets: inherit secrets: inherit
with: with:
projects: ${{ needs.build-sources.outputs.projects-e2e }} projects: ${{ needs.build-sources.outputs.projects-e2e }}
tags: '@smoke' tags: '@smoke'
console-e2e:
needs: [build-sources, check-e2e-needed]
name: '(CI) console python'
uses: ./.github/workflows/console-test-run.yml
secrets: inherit
if: needs.check-e2e-needed.outputs.run-tests == 'true' && contains(needs.build-sources.outputs.projects, 'trading')
with:
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
publish-dist: publish-dist:
needs: build-sources needs: build-sources
name: '(CD) publish dist' name: '(CD) publish dist'
+29
View File
@@ -0,0 +1,29 @@
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#managing-caches
name: cleanup caches by a branch
on:
pull_request:
types:
- closed
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Cleanup
run: |
gh extension install actions/gh-actions-cache
echo "Fetching list of cache key"
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
+156 -50
View File
@@ -1,31 +1,42 @@
name: (CI) Console tests name: (CI) Console tests
env:
VEGA_VERSION: v0.72.14
on: on:
workflow_call: workflow_call:
inputs: inputs:
github-sha: github-sha:
required: true required: true
type: string type: string
workflow_dispatch:
inputs:
console-test-branch:
type: choice
description: 'main: v0.72.14, develop: v0.73.0-preview7'
options:
- main
- develop
jobs: jobs:
run-tests: create-docker-image:
name: run-tests name: Create docker image for console-test
runs-on: console-test runs-on: ubuntu-22.04
timeout-minutes: 40 timeout-minutes: 20
steps: steps:
#---------------------------------------------- #----------------------------------------------
# check-out frontend-monorepo # check-out frontend-monorepo
#---------------------------------------------- #----------------------------------------------
- name: Checkout console test repo - name: Checkout frontend-monorepo
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
ref: ${{ inputs.github-sha }} ref: ${{ inputs.github-sha || github.sha }}
#---------------------------------------------- #----------------------------------------------
# cache node modules # cache node modules
#---------------------------------------------- #----------------------------------------------
- name: setup node
uses: actions/setup-node@v3
with:
node-version: '16'
cache: yarn
- name: Cache node modules - name: Cache node modules
id: cache id: cache
uses: actions/cache@v3 uses: actions/cache@v3
@@ -44,23 +55,105 @@ jobs:
#---------------------------------------------- #----------------------------------------------
# build trading # build trading
#---------------------------------------------- #----------------------------------------------
- name: Build affected spec - name: Build trading app
run: | run: |
yarn env-cmd -f ./apps/trading/.env.stagnet1 yarn nx export trading yarn env-cmd -f ./apps/trading/.env.stagnet1 yarn nx export trading
DIST_LOCATION=dist/apps/trading/exported
mv $DIST_LOCATION dist-result
tree dist-result
#---------------------------------------------- #----------------------------------------------
# run trading server # export trading app docker image
#---------------------------------------------- #----------------------------------------------
- name: Run trading server
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and export to local Docker
id: docker_build
uses: docker/build-push-action@v5
with:
context: .
file: docker/node-outside-docker.Dockerfile
load: true
build-args: |
APP=trading
ENV_NAME=stagnet1
tags: ci/trading:local
outputs: type=docker,dest=/tmp/console-image.tar
- name: Verify docker image created
run: | run: |
docker run -d -p 80:4200 -v $PWD/docker/nginx.conf:/etc/nginx/conf.d/default.conf -v $PWD/dist/apps/trading/exported:/usr/share/nginx/html nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629 echo ${{ steps.docker_build.outputs.digest }}
sleep 5 echo ${{ steps.docker_build.outputs.imageid }}
docker ps
#---------------------------------------------- - name: Upload docker image for console-test usage
# check if container persists between runs uses: actions/upload-artifact@v3
#---------------------------------------------- with:
- name: Check server name: console-image
path: /tmp/console-image.tar
console-test-branch:
name: Choose console-test branch to run on
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
console-branch: ${{ steps.output-step.outputs.branch }}
steps:
- name: Workflow dispatch input
id: dispatch-step
if: github.event_name == 'workflow_dispatch'
run: echo "branch=${{ inputs.console-test-branch }}" >> $GITHUB_OUTPUT
- name: Print Workflow dispatch input
if: github.event_name == 'workflow_dispatch'
run: echo ${{ steps.dispatch-step.outputs.branch }}
- name: Workflow_call input
id: workflow_call-step
if: github.event_name != 'workflow_dispatch'
run: | run: |
docker ps if [[ "${{ github.base_ref }}" == "main" ]]; then
echo "branch=main" >> $GITHUB_OUTPUT
elif [[ "${{ github.base_ref }}" == "develop" && "${{ github.ref_name }}" == "main" ]]; then
echo "branch=main" >> $GITHUB_OUTPUT
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/mainnet"* ]]; then
echo "branch=main" >> $GITHUB_OUTPUT
else
echo "branch=develop" >> $GITHUB_OUTPUT
fi
- name: Print Workflow_call input
if: github.event_name != 'workflow_dispatch'
run: echo ${{ steps.workflow_call-step.outputs.branch }}
- name: Set output
id: output-step
run: echo "branch=${{ steps.dispatch-step.outputs.branch || steps.workflow_call-step.outputs.branch }}" >> $GITHUB_OUTPUT
- name: Print final output
run: echo ${{ steps.output-step.outputs.branch }}
run-tests:
name: run-tests
runs-on: 8-cores
needs: [create-docker-image, console-test-branch]
timeout-minutes: 20
steps:
#----------------------------------------------
# load docker image
#----------------------------------------------
- name: Download docker image from previous job
uses: actions/download-artifact@v3
with:
name: console-image
path: /tmp
- name: Load Docker image
run: |
docker load --input /tmp/console-image.tar
docker image ls -a
#---------------------------------------------- #----------------------------------------------
# check-out tests repo # check-out tests repo
#---------------------------------------------- #----------------------------------------------
@@ -68,52 +161,55 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
repository: vegaprotocol/console-test repository: vegaprotocol/console-test
path: './console-test' ref: ${{ needs.console-test-branch.outputs.console-branch }}
- name: Load console test envs
id: console-test-env
uses: falti/dotenv-action@v1.0.4
with:
path: '.env.${{ needs.console-test-branch.outputs.console-branch }}'
export-variables: true
keys-case: upper
log-variables: true
#---------------------------------------------- #----------------------------------------------
# install dependencies # ----- Setup python -----
#----------------------------------------------
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
#----------------------------------------------
# ----- install & configure poetry -----
#----------------------------------------------
- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-create: true
virtualenvs-in-project: true
virtualenvs-path: .venv
#----------------------------------------------
# install python dependencies
#---------------------------------------------- #----------------------------------------------
- name: Install dependencies - name: Install dependencies
working-directory: ./console-test
run: poetry install --no-interaction --no-root run: poetry install --no-interaction --no-root
#---------------------------------------------- #----------------------------------------------
# find vega binaries path # install vega binaries
#----------------------------------------------
- name: Find vega binaries path
id: vega_bin_path
working-directory: ./console-test
run: echo path=$(poetry run python -c "import vega_sim; print(vega_sim.vega_bin_path)") >> $GITHUB_OUTPUT
#----------------------------------------------
# vega binaries cache
#----------------------------------------------
- name: Vega binaries cache
uses: actions/cache@v3
id: vega_binaries_cache
with:
path: ${{ steps.vega_bin_path.outputs.path }}
key: ${{ runner.os }}-vega-binaries-${{ env.VEGA_VERSION }}
#----------------------------------------------
# install vega binaries
#---------------------------------------------- #----------------------------------------------
- name: Install vega binaries - name: Install vega binaries
working-directory: ./console-test run: poetry run python -m vega_sim.tools.load_binaries --force --version ${{ env.VEGA_VERSION }}
if: steps.vega_binaries_cache.outputs.cache-hit != 'true'
run: poetry run python -m vega_sim.tools.load_binaries --force --version $VEGA_VERSION
#---------------------------------------------- #----------------------------------------------
# install playwright # install playwright
#---------------------------------------------- #----------------------------------------------
- name: install playwright - name: install playwright
run: poetry run playwright install --with-deps chromium run: poetry run playwright install --with-deps chromium
working-directory: ./console-test
#---------------------------------------------- #----------------------------------------------
# run tests # run tests
#---------------------------------------------- #----------------------------------------------
- name: Run tests - name: Run tests
working-directory: ./console-test run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 4 --dist loadfile --durations=15
run: poetry run pytest -v -s --numprocesses 2 --dist loadfile --durations=20
- name: Check files
run: |
ls -al .
ls -al console-test
#---------------------------------------------- #----------------------------------------------
# upload traces # upload traces
#---------------------------------------------- #----------------------------------------------
@@ -124,3 +220,13 @@ jobs:
name: playwright-trace name: playwright-trace
path: ./traces/ path: ./traces/
retention-days: 15 retention-days: 15
#----------------------------------------------
# ----- upload logs -----
#----------------------------------------------
- name: Upload worker logs
uses: actions/upload-artifact@v3
if: always()
with:
name: worker-logs
path: ./logs/
retention-days: 15
+24 -1
View File
@@ -13,13 +13,35 @@ on:
type: string type: string
jobs: jobs:
runner-choice:
runs-on: ubuntu-latest
outputs:
runner: ${{ steps.step.outputs.runner }}
steps:
- name: Check branch
id: step
run: |
if [[ "${{ github.base_ref }}" == "main" ]]; then
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
elif [[ "${{ github.base_ref }}" == "develop" && "${{ github.ref_name }}" == "main" ]]; then
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/mainnet"* ]]; then
echo "runner=mainnet-compatible-runner" >> $GITHUB_OUTPUT
else
echo "runner=self-hosted-runner" >> $GITHUB_OUTPUT
fi
- name: Print runner
run: echo ${{ steps.step.outputs.runner }}
e2e: e2e:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
project: ${{ fromJSON(inputs.projects) }} project: ${{ fromJSON(inputs.projects) }}
name: ${{ matrix.project }} name: ${{ matrix.project }}
runs-on: self-hosted-runner needs: runner-choice
runs-on: ${{ needs.runner-choice.outputs.runner }}
timeout-minutes: 120 timeout-minutes: 120
steps: steps:
# Checks if skip cache was requested # Checks if skip cache was requested
@@ -63,6 +85,7 @@ jobs:
- name: Run Vegacapsule network and Vega wallet - name: Run Vegacapsule network and Vega wallet
id: setup-vega id: setup-vega
uses: ./frontend-monorepo/.github/actions/run-vegacapsule uses: ./frontend-monorepo/.github/actions/run-vegacapsule
timeout-minutes: 10
###### ######
## Run some tests ## Run some tests
+11 -11
View File
@@ -2,7 +2,12 @@
name: Verify PR title name: Verify PR title
on: on:
workflow_call: pull_request:
types:
- opened
- edited
- reopened
- synchronize
jobs: jobs:
lint_pr: lint_pr:
@@ -11,21 +16,16 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Setup node - name: Setup node
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version-file: '.nvmrc' node-version: 16
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
cache: yarn
- name: Cache node modules - name: Install dependencies
uses: actions/cache@v3 run: |
with: rm package.json
path: node_modules npm install --no-save @commitlint/cli @commitlint/config-conventional @commitlint/config-nx-scopes nx
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
- name: Check PR title - name: Check PR title
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
+20 -12
View File
@@ -30,12 +30,18 @@ jobs:
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
echo IS_S3_RELEASE=false >> $GITHUB_ENV echo IS_S3_RELEASE=false >> $GITHUB_ENV
echo IS_DEV_IMAGE=false >> $GITHUB_ENV echo IS_DEV_IMAGE=false >> $GITHUB_ENV
echo IS_MAIN_IMAGE=false >> $GITHUB_ENV
- name: Is dev image - name: Is dev image
if: ${{ contains(github.ref, 'develop') && github.event_name == 'push' && matrix.app == 'trading' }} if: ${{ github.ref_name == 'develop' && github.event_name == 'push' && matrix.app == 'trading' }}
run: | run: |
echo IS_DEV_IMAGE=true >> $GITHUB_ENV echo IS_DEV_IMAGE=true >> $GITHUB_ENV
- name: Is main image
if: ${{ github.ref_name == 'main' && github.event_name == 'push' && matrix.app == 'trading' }}
run: |
echo IS_MAIN_IMAGE=true >> $GITHUB_ENV
- name: Is PR - name: Is PR
if: ${{ github.event_name == 'pull_request' }} if: ${{ github.event_name == 'pull_request' }}
run: | run: |
@@ -57,7 +63,7 @@ jobs:
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
- name: Is S3 Release - name: Is S3 Release
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' }} if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' && github.ref_name != 'main'}}
run: | run: |
echo IS_S3_RELEASE=true >> $GITHUB_ENV echo IS_S3_RELEASE=true >> $GITHUB_ENV
@@ -81,7 +87,7 @@ jobs:
- name: Log in to the Container registry (docker hub) - name: Log in to the Container registry (docker hub)
uses: docker/login-action@v2 uses: docker/login-action@v2
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }} if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' || env.IS_MAIN_IMAGE == 'true' }}
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -155,10 +161,10 @@ jobs:
- name: Sanity check docker image - name: Sanity check docker image
run: | run: |
echo "Check ipfs-hash" echo "Check ipfs-hash"
docker run --rm --entrypoint /bin/sh ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local -c 'cat /ipfs-hash' docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash'
docker run --rm --entrypoint /bin/sh ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local -c 'cat /ipfs-hash' > ${{ matrix.app }}-ipfs-hash docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash' > ${{ matrix.app }}-ipfs-hash
echo "List html directory" echo "List html directory"
docker run --rm --entrypoint /bin/sh ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local -c 'apk add --update tree; tree /usr/share/nginx/html' docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'apk add --update tree; tree /usr/share/nginx/html'
- name: Publish dist as docker image (ghcr) - name: Publish dist as docker image (ghcr)
uses: docker/build-push-action@v3 uses: docker/build-push-action@v3
@@ -179,7 +185,7 @@ jobs:
uses: docker/build-push-action@v3 uses: docker/build-push-action@v3
continue-on-error: true continue-on-error: true
id: dockerhub-push id: dockerhub-push
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }} if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' || env.IS_MAIN_IMAGE == 'true' }}
with: with:
context: . context: .
file: docker/node-outside-docker.Dockerfile file: docker/node-outside-docker.Dockerfile
@@ -189,7 +195,7 @@ jobs:
ENV_NAME=${{ env.ENV_NAME }} ENV_NAME=${{ env.ENV_NAME }}
tags: | tags: |
vegaprotocol/${{ matrix.app }}:${{ github.sha }} vegaprotocol/${{ matrix.app }}:${{ github.sha }}
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || '' }} vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || env.IS_MAIN_IMAGE == 'true' && 'main' || '' }}
- name: Publish dist as docker image (ghcr - retry) - name: Publish dist as docker image (ghcr - retry)
uses: docker/build-push-action@v3 uses: docker/build-push-action@v3
@@ -216,7 +222,7 @@ jobs:
ENV_NAME=${{ env.ENV_NAME }} ENV_NAME=${{ env.ENV_NAME }}
tags: | tags: |
vegaprotocol/${{ matrix.app }}:${{ github.sha }} vegaprotocol/${{ matrix.app }}:${{ github.sha }}
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }} vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || env.IS_MAIN_IMAGE == 'true' && 'main' || '' }}
# bucket creation in github.com/vegaprotocol/terraform//frontend # bucket creation in github.com/vegaprotocol/terraform//frontend
- name: Publish dist to s3 - name: Publish dist to s3
@@ -329,7 +335,9 @@ jobs:
fi fi
# create commit # create commit
commit_msg="Automated hash update from ${{ github.ref }}" if ! git diff --cached --exit-code; then
git commit -m "$commit_msg" commit_msg="Automated hash update from ${{ github.ref }}"
git push -u origin "main" git commit -m "$commit_msg"
git push -u origin "main"
fi
) )
-1
View File
@@ -1,3 +1,2 @@
* @vegaprotocol/frontend * @vegaprotocol/frontend
* @vegaprotocol/frontend-qa
*.graphql @vegaprotocol/core *.graphql @vegaprotocol/core
+1 -1
View File
@@ -118,7 +118,7 @@ On top of that there are two possible scenarios for running docker image - using
to run ipfs on port 3000: to run ipfs on port 3000:
```bash ```bash
docker run -p 3000:80 [TAG] ipfs docker run -p 3000:80 [TAG] /run-ipfs.sh
``` ```
to run nginx on port 3000: to run nginx on port 3000:
@@ -36,10 +36,9 @@ context('Market page', { tags: '@regression' }, function () {
it('Able to go to market details page', function () { it('Able to go to market details page', function () {
cy.navigate_to('markets'); cy.navigate_to('markets');
cy.get_element_by_col_id('actions').eq(1).click(); cy.contains('Test market 1').click();
cy.getByTestId(marketHeaders).should('have.text', 'Test market 1'); cy.getByTestId(marketHeaders).should('have.text', 'Test market 1');
cy.validate_element_from_table('Name', 'Test market 1'); cy.validate_element_from_table('Name', 'Test market 1');
cy.validate_element_from_table('Market ID', this.createdMarketId);
cy.validate_element_from_table('Trading Mode', 'Opening auction'); cy.validate_element_from_table('Trading Mode', 'Opening auction');
cy.validate_element_from_table('Market Decimal Places', '5'); cy.validate_element_from_table('Market Decimal Places', '5');
cy.validate_element_from_table('Position Decimal Places', '5'); cy.validate_element_from_table('Position Decimal Places', '5');
@@ -87,15 +86,13 @@ context('Market page', { tags: '@regression' }, function () {
// Liquidity // Liquidity
cy.validate_element_from_table('Target Stake', '0.00 fUSDC'); cy.validate_element_from_table('Target Stake', '0.00 fUSDC');
cy.validate_element_from_table('Supplied Stake', '0.00 fUSDC'); cy.validate_element_from_table('Supplied Stake', '0.00 fUSDC');
cy.validate_element_from_table('Market Value Proxy', '0.00 fUSDC');
// Liquidity price range // Liquidity price range
cy.validate_element_from_table( cy.validate_element_from_table(
'Liquidity Price Range', 'Liquidity Price Range',
'1,000.00% of mid price' '95.00% of mid price'
); );
cy.validate_element_from_table('Lowest Price', '0.00 fUSDC'); cy.validate_element_from_table('Lowest Price', '0.00 fUSDC');
cy.validate_element_from_table('Highest Price', '0.00 fUSDC'); cy.validate_element_from_table('Highest Price', '0.00 fUSDC');
cy.getByTestId('oracle-spec-links') cy.getByTestId('oracle-spec-links')
.should('have.attr', 'href') .should('have.attr', 'href')
.and( .and(
@@ -144,11 +141,8 @@ context('Market page', { tags: '@regression' }, function () {
.as('successorMarketId'); .as('successorMarketId');
cy.contains('Token test market').click(); cy.contains('Token test market').click();
cy.getByTestId(marketHeaders).should('have.text', 'Token test market'); cy.getByTestId(marketHeaders).should('have.text', 'Token test market');
cy.validate_proposal_change_type('Triggering Ratio', 'Added');
cy.validate_element_from_table('Triggering Ratio', '0.7'); cy.validate_element_from_table('Triggering Ratio', '0.7');
cy.validate_proposal_change_type('Time Window', 'Added');
cy.validate_element_from_table('Time Window', '3,600'); cy.validate_element_from_table('Time Window', '3,600');
cy.validate_proposal_change_type('Scaling Factor', 'Added');
cy.validate_element_from_table('Scaling Factor', '10'); cy.validate_element_from_table('Scaling Factor', '10');
cy.getByTestId(successionLineItem) cy.getByTestId(successionLineItem)
@@ -40,7 +40,7 @@ context.skip('Node switcher', { tags: '@regression' }, function () {
const errorTypeTxt = 'Error: invalid url'; const errorTypeTxt = 'Error: invalid url';
const nodeErrorTxt = 'fakeUrl is not a valid url.'; const nodeErrorTxt = 'fakeUrl is not a valid url.';
cy.getByTestId('node-url-custom').click(); cy.getByTestId('node-url-custom').click({ force: true });
cy.getByTestId(customNodeBtn).within(() => { cy.getByTestId(customNodeBtn).within(() => {
cy.get('input').clear().type('fakeUrl'); cy.get('input').clear().type('fakeUrl');
@@ -26,7 +26,6 @@ function getSuccessorTxBody(parentMarketId) {
positionDecimalPlaces: '5', positionDecimalPlaces: '5',
linearSlippageFactor: '0.001', linearSlippageFactor: '0.001',
quadraticSlippageFactor: '0', quadraticSlippageFactor: '0',
lpPriceRange: '10',
instrument: { instrument: {
name: 'Token test market', name: 'Token test market',
code: 'TEST.24h', code: 'TEST.24h',
@@ -130,6 +129,12 @@ function getSuccessorTxBody(parentMarketId) {
parentMarketId: parentMarketId, parentMarketId: parentMarketId,
insurancePoolFraction: '0.75', insurancePoolFraction: '0.75',
}, },
liquiditySlaParameters: {
priceRange: '0.95',
commitmentMinTimeFraction: '0.5',
performanceHysteresisEpochs: 2,
slaCompetitionFactor: '0.75',
},
}, },
}, },
closingTimestamp, closingTimestamp,
+2 -2
View File
@@ -1,6 +1,6 @@
import { import {
AppFailure,
NetworkLoader, NetworkLoader,
NodeFailure,
NodeGuard, NodeGuard,
NodeSwitcherDialog, NodeSwitcherDialog,
useEnvironment, useEnvironment,
@@ -31,7 +31,7 @@ function App() {
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}> <NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
<NodeGuard <NodeGuard
skeleton={<div>{t('Loading')}</div>} skeleton={<div>{t('Loading')}</div>}
failure={<AppFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />} failure={<NodeFailure title={t(`Node: ${VEGA_URL} is unsuitable`)} />}
> >
<Suspense fallback={splashLoading}> <Suspense fallback={splashLoading}>
<RouterProvider router={router} fallbackElement={splashLoading} /> <RouterProvider router={router} fallbackElement={splashLoading} />
@@ -4,7 +4,7 @@ import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { ButtonLink } from '@vegaprotocol/ui-toolkit'; import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import { AgGrid } from '@vegaprotocol/datagrid';
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid'; import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
import { useRef, useLayoutEffect } from 'react'; import { useRef, useLayoutEffect } from 'react';
import { BREAKPOINT_MD } from '../../config/breakpoints'; import { BREAKPOINT_MD } from '../../config/breakpoints';
@@ -13,6 +13,12 @@ query ExplorerMarket($id: ID!) {
decimals decimals
} }
} }
... on Perpetual {
quoteName
settlementAsset {
decimals
}
}
} }
} }
} }
@@ -8,7 +8,7 @@ export type ExplorerMarketQueryVariables = Types.Exact<{
}>; }>;
export type ExplorerMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } } } } | null }; export type ExplorerMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } | { __typename?: 'Perpetual', quoteName: string, settlementAsset: { __typename?: 'Asset', decimals: number } } | { __typename?: 'Spot' } } } } | null };
export const ExplorerMarketDocument = gql` export const ExplorerMarketDocument = gql`
@@ -27,6 +27,12 @@ export const ExplorerMarketDocument = gql`
decimals decimals
} }
} }
... on Perpetual {
quoteName
settlementAsset {
decimals
}
}
} }
} }
} }
@@ -61,6 +61,7 @@ describe('Market link component', () => {
instrument: { instrument: {
name: 'test-label', name: 'test-label',
product: { product: {
__typename: 'Future',
quoteName: 'dai', quoteName: 'dai',
}, },
}, },
@@ -1,37 +1,41 @@
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import type { MarketInfoWithData } from '@vegaprotocol/markets'; import type { MarketInfoWithData } from '@vegaprotocol/markets';
import { import {
LiquidityPriceRangeInfoPanel,
LiquiditySLAParametersInfoPanel,
MarginScalingFactorsPanel,
PriceMonitoringBoundsInfoPanel, PriceMonitoringBoundsInfoPanel,
SuccessionLineInfoPanel, SuccessionLineInfoPanel,
getDataSourceSpecForSettlementData,
getDataSourceSpecForTradingTermination,
} from '@vegaprotocol/markets'; } from '@vegaprotocol/markets';
import { import {
LiquidityInfoPanel, LiquidityInfoPanel,
LiquidityMonitoringParametersInfoPanel, LiquidityMonitoringParametersInfoPanel,
InstrumentInfoPanel, InstrumentInfoPanel,
KeyDetailsInfoPanel, KeyDetailsInfoPanel,
LiquidityPriceRangeInfoPanel,
MetadataInfoPanel, MetadataInfoPanel,
OracleInfoPanel, OracleInfoPanel,
RiskFactorsInfoPanel, RiskFactorsInfoPanel,
RiskModelInfoPanel, RiskModelInfoPanel,
RiskParametersInfoPanel,
SettlementAssetInfoPanel, SettlementAssetInfoPanel,
} from '@vegaprotocol/markets'; } from '@vegaprotocol/markets';
import { MarketInfoTable } from '@vegaprotocol/markets'; import { MarketInfoTable } from '@vegaprotocol/markets';
import type { DataSourceDefinition } from '@vegaprotocol/types'; import type { DataSourceFragment } from '@vegaprotocol/markets';
import isEqual from 'lodash/isEqual'; import isEqual from 'lodash/isEqual';
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => { export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
if (!market) return null; if (!market) return null;
const { product } = market.tradableInstrument.instrument;
const settlementDataSource = getDataSourceSpecForSettlementData(product);
const terminationDataSource = getDataSourceSpecForTradingTermination(product);
const settlementData = market.tradableInstrument.instrument.product const getSigners = ({ data }: DataSourceFragment) => {
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
const terminationData = market.tradableInstrument.instrument.product
.dataSourceSpecForTradingTermination.data as DataSourceDefinition;
const getSigners = (data: DataSourceDefinition) => {
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') { if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
const signers = data.sourceType.sourceType.signers || []; const signers =
('signers' in data.sourceType.sourceType &&
data.sourceType.sourceType.signers) ||
[];
return signers.map(({ signer }, i) => { return signers.map(({ signer }, i) => {
return ( return (
@@ -43,10 +47,13 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
return []; return [];
}; };
const showTwoOracles = isEqual( const showTwoOracles =
getSigners(settlementData), settlementDataSource &&
getSigners(terminationData) terminationDataSource &&
); isEqual(
getSigners(settlementDataSource),
getSigners(terminationDataSource)
);
const headerClassName = 'font-alpha calt text-xl mt-4 border-b-2 pb-2'; const headerClassName = 'font-alpha calt text-xl mt-4 border-b-2 pb-2';
@@ -62,8 +69,8 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
<MetadataInfoPanel market={market} /> <MetadataInfoPanel market={market} />
<h2 className={headerClassName}>{t('Risk model')}</h2> <h2 className={headerClassName}>{t('Risk model')}</h2>
<RiskModelInfoPanel market={market} /> <RiskModelInfoPanel market={market} />
<h2 className={headerClassName}>{t('Risk parameters')}</h2> <h2 className={headerClassName}>{t('Margin scaling factors')}</h2>
<RiskParametersInfoPanel market={market} /> <MarginScalingFactorsPanel market={market} />
<h2 className={headerClassName}>{t('Risk factors')}</h2> <h2 className={headerClassName}>{t('Risk factors')}</h2>
<RiskFactorsInfoPanel market={market} /> <RiskFactorsInfoPanel market={market} />
{(market.data?.priceMonitoringBounds || []).map((trigger, i) => ( {(market.data?.priceMonitoringBounds || []).map((trigger, i) => (
@@ -89,10 +96,12 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
)} )}
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2> <h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
<LiquidityMonitoringParametersInfoPanel market={market} /> <LiquidityMonitoringParametersInfoPanel market={market} />
<h2 className={headerClassName}>{t('Liquidity')}</h2>
<LiquidityInfoPanel market={market} />
<h2 className={headerClassName}>{t('Liquidity price range')}</h2> <h2 className={headerClassName}>{t('Liquidity price range')}</h2>
<LiquidityPriceRangeInfoPanel market={market} /> <LiquidityPriceRangeInfoPanel market={market} />
<h2 className={headerClassName}>{t('Liquidity SLA protocol')}</h2>
<LiquiditySLAParametersInfoPanel market={market} />
<h2 className={headerClassName}>{t('Liquidity')}</h2>
<LiquidityInfoPanel market={market} />
{showTwoOracles ? ( {showTwoOracles ? (
<> <>
<h2 className={headerClassName}>{t('Settlement oracle')}</h2> <h2 className={headerClassName}>{t('Settlement oracle')}</h2>
@@ -1,10 +1,10 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import type { MarketFieldsFragment } from '@vegaprotocol/markets'; import { getAsset, type MarketFieldsFragment } from '@vegaprotocol/markets';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { ButtonLink } from '@vegaprotocol/ui-toolkit'; import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import type { ColDef } from 'ag-grid-community'; import type { ColDef } from 'ag-grid-community';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import { AgGrid } from '@vegaprotocol/datagrid';
import type { import type {
VegaICellRendererParams, VegaICellRendererParams,
VegaValueGetterParams, VegaValueGetterParams,
@@ -73,8 +73,7 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
MarketFieldsFragment, MarketFieldsFragment,
'tradableInstrument.instrument.product.settlementAsset.symbol' 'tradableInstrument.instrument.product.settlementAsset.symbol'
>) => { >) => {
const value = const value = data && getAsset(data);
data?.tradableInstrument.instrument.product.settlementAsset;
return value ? ( return value ? (
<ButtonLink <ButtonLink
onClick={(e) => { onClick={(e) => {
@@ -31,6 +31,9 @@ fragment ExplorerDeterministicOrderFields on Order {
... on Future { ... on Future {
quoteName quoteName
} }
... on Perpetual {
quoteName
}
} }
} }
} }
@@ -3,7 +3,7 @@ import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client'; import * as Apollo from '@apollo/client';
const defaultOptions = {} as const; const defaultOptions = {} as const;
export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } }; export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } | { __typename?: 'Perpetual', quoteName: string } | { __typename?: 'Spot' } } } } };
export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{ export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
orderId: Types.Scalars['ID']; orderId: Types.Scalars['ID'];
@@ -11,7 +11,7 @@ export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
}>; }>;
export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } } }; export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } | { __typename?: 'Perpetual', quoteName: string } | { __typename?: 'Spot' } } } } } };
export const ExplorerDeterministicOrderFieldsFragmentDoc = gql` export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
fragment ExplorerDeterministicOrderFields on Order { fragment ExplorerDeterministicOrderFields on Order {
@@ -47,6 +47,9 @@ export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
... on Future { ... on Future {
quoteName quoteName
} }
... on Perpetual {
quoteName
}
} }
} }
} }
@@ -150,6 +150,7 @@ function renderExistingAmend(
instrument: { instrument: {
name: 'test-label', name: 'test-label',
product: { product: {
__typename: 'Future',
quoteName: 'dai', quoteName: 'dai',
}, },
}, },
@@ -33,6 +33,8 @@ const PriceInMarket = ({
label = addDecimalsFormatNumber(price, data.market.decimalPlaces); label = addDecimalsFormatNumber(price, data.market.decimalPlaces);
} else if ( } else if (
decimalSource === 'SETTLEMENT_ASSET' && decimalSource === 'SETTLEMENT_ASSET' &&
data.market &&
'settlementAsset' in data.market.tradableInstrument.instrument.product &&
data.market?.tradableInstrument.instrument.product.settlementAsset data.market?.tradableInstrument.instrument.product.settlementAsset
) { ) {
label = addDecimalsFormatNumber( label = addDecimalsFormatNumber(
@@ -2,7 +2,7 @@ import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
import { VoteProgress } from '@vegaprotocol/proposals'; import { VoteProgress } from '@vegaprotocol/proposals';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import { ExternalLink } from '@vegaprotocol/ui-toolkit'; import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import { AgGrid } from '@vegaprotocol/datagrid';
import type { import type {
VegaICellRendererParams, VegaICellRendererParams,
VegaValueFormatterParams, VegaValueFormatterParams,
@@ -105,7 +105,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
? new BigNumber(0) ? new BigNumber(0)
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted); : yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
return ( return (
<div className="uppercase flex h-full items-center justify-center pt-2"> <div className="flex items-center justify-center h-full pt-2 uppercase">
<VoteProgress <VoteProgress
threshold={requiredMajorityPercentage} threshold={requiredMajorityPercentage}
progress={yesPercentage} progress={yesPercentage}
@@ -12,6 +12,7 @@ import {
SPECIAL_CASE_NETWORK, SPECIAL_CASE_NETWORK,
SPECIAL_CASE_NETWORK_ID, SPECIAL_CASE_NETWORK_ID,
} from '../../links/party-link/party-link'; } from '../../links/party-link/party-link';
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
type Transfer = components['schemas']['commandsv1Transfer']; type Transfer = components['schemas']['commandsv1Transfer'];
@@ -63,10 +64,16 @@ export const TxDetailsTransfer = ({
return ( return (
<> <>
<TableWithTbody className="mb-8" allowWrap={true}> <TableWithTbody className="mb-8" allowWrap={true}>
<TableRow modifier="bordered"> <TableRow modifier="bordered" data-testid="type">
<TableCell {...sharedHeaderProps}>{t('Type')}</TableCell> <TableCell {...sharedHeaderProps}>{t('Type')}</TableCell>
<TableCell>{getTypeLabelForTransfer(transfer)}</TableCell> <TableCell>{getTypeLabelForTransfer(transfer)}</TableCell>
</TableRow> </TableRow>
<TableRow modifier="bordered" data-testid="id">
<TableCell {...sharedHeaderProps}>{t('Transfer ID')}</TableCell>
<TableCell>
{txSignatureToDeterministicId(txData.signature.value)}
</TableCell>
</TableRow>
<TxDetailsShared <TxDetailsShared
txData={txData} txData={txData}
pubKey={pubKey} pubKey={pubKey}
@@ -74,7 +81,7 @@ export const TxDetailsTransfer = ({
hideTypeRow={true} hideTypeRow={true}
/> />
{from ? ( {from ? (
<TableRow modifier="bordered"> <TableRow modifier="bordered" data-testid="from">
<TableCell>{t('From')}</TableCell> <TableCell>{t('From')}</TableCell>
<TableCell> <TableCell>
<PartyLink id={from} /> <PartyLink id={from} />
@@ -82,7 +89,7 @@ export const TxDetailsTransfer = ({
</TableRow> </TableRow>
) : null} ) : null}
{transfer.to ? ( {transfer.to ? (
<TableRow modifier="bordered"> <TableRow modifier="bordered" data-testid="to">
<TableCell>{t('To')}</TableCell> <TableCell>{t('To')}</TableCell>
<TableCell> <TableCell>
<PartyLink id={transfer.to} /> <PartyLink id={transfer.to} />
@@ -90,7 +97,7 @@ export const TxDetailsTransfer = ({
</TableRow> </TableRow>
) : null} ) : null}
{transfer.asset && transfer.amount ? ( {transfer.asset && transfer.amount ? (
<TableRow modifier="bordered"> <TableRow modifier="bordered" data-testid="amount">
<TableCell>{t('Amount')}</TableCell> <TableCell>{t('Amount')}</TableCell>
<TableCell> <TableCell>
<SizeInAsset assetId={transfer.asset} size={transfer.amount} /> <SizeInAsset assetId={transfer.asset} size={transfer.amount} />
@@ -1,6 +1,15 @@
import { getTypeLabelForTransfer } from './details/tx-transfer'; import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
import type { TendermintBlocksResponse } from '../../routes/blocks/tendermint-blocks-response';
import type { components } from '../../../types/explorer'; import type { components } from '../../../types/explorer';
import {
TxDetailsTransfer,
getTypeLabelForTransfer,
} from './details/tx-transfer';
import { MockedProvider } from '@apollo/client/testing';
import { MemoryRouter } from 'react-router-dom';
import { render } from '@testing-library/react';
type Transfer = components['schemas']['commandsv1Transfer']; type Transfer = components['schemas']['commandsv1Transfer'];
describe('TX: Transfer: getLabelForTransfer', () => { describe('TX: Transfer: getLabelForTransfer', () => {
@@ -56,3 +65,70 @@ describe('TX: Transfer: getLabelForTransfer', () => {
expect(getTypeLabelForTransfer(mock)).toEqual('Transfer'); expect(getTypeLabelForTransfer(mock)).toEqual('Transfer');
}); });
}); });
describe('TxDetailsTransfer', () => {
const mockBlockData = {
result: {
block: {
header: {
height: '123',
},
},
},
};
const mockTxData: Partial<BlockExplorerTransactionResult> = {
hash: 'test',
submitter:
'e1943eea46fed576cf2be42972f3c5515ad3d0ac7ac013f56677c12a53a1b3ed',
command: {
nonce: '5188810881378065222',
blockHeight: '14951513',
transfer: {
fromAccountType: 'ACCOUNT_TYPE_GENERAL',
to: '78432a2808f20b18a46ccc6a917bdc4d63c2b9e7007f777bdcab5a9f462c5ba6',
toAccountType: 'ACCOUNT_TYPE_GENERAL',
asset:
'dd20590509d30d20bdbbe64dc1090c1140c7690121a9b9940bc66f62dfa2e599',
amount: '4800000000',
reference: '',
oneOff: {
deliverOn: '0',
},
},
},
signature: {
value:
'610c2e196a7d4fed4413b9e82af267b1ff3e30e943df3a3d28096fd60604d430d752fbaf6dd4f84d496be78885bb6118f40560bff7832c06bd7a3d67b718b700',
},
};
it('renders basic transfer details', () => {
const { getByTestId } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsTransfer
txData={mockTxData as BlockExplorerTransactionResult}
pubKey={mockTxData.command.submitter}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
const id = getByTestId('id');
expect(id.children[0].textContent).toEqual('Transfer ID');
expect(id.children[1].textContent).toEqual(
'51f3bab5eb2637651012507a64d497790a734248792c16e5cf36df8984074fbd'
);
const type = getByTestId('type');
expect(type.children[1].textContent).toEqual('Transfer');
const from = getByTestId('from');
expect(from.children[1].textContent).toEqual(mockTxData.submitter);
const to = getByTestId('to');
expect(to.children[1].textContent).toEqual(mockTxData.command.transfer.to);
});
});
@@ -82,7 +82,7 @@ describe('Txs infinite list item', () => {
expect(screen.getByText('Missing vital data')).toBeInTheDocument(); expect(screen.getByText('Missing vital data')).toBeInTheDocument();
}); });
it('renders data correctly', () => { it('renders data even with missing time', () => {
render( render(
<MockedProvider> <MockedProvider>
<MemoryRouter> <MemoryRouter>
@@ -105,5 +105,33 @@ describe('Txs infinite list item', () => {
expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey'); expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey');
expect(screen.getByTestId('tx-type')).toHaveTextContent('testType'); expect(screen.getByTestId('tx-type')).toHaveTextContent('testType');
expect(screen.getByTestId('tx-block')).toHaveTextContent('1'); expect(screen.getByTestId('tx-block')).toHaveTextContent('1');
expect(screen.getByTestId('tx-time')).toHaveTextContent('-');
});
it('renders data correctly', () => {
render(
<MockedProvider>
<MemoryRouter>
<table>
<tbody>
<TxsInfiniteListItem
type="testType"
submitter="testPubKey"
hash="testTxHash"
block="1"
code={0}
command={{}}
createdAt="1970-11-01T18:07:15Z"
/>
</tbody>
</table>
</MemoryRouter>
</MockedProvider>
);
expect(screen.getByTestId('tx-hash')).toHaveTextContent('testTxHash');
expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey');
expect(screen.getByTestId('tx-type')).toHaveTextContent('testType');
expect(screen.getByTestId('tx-block')).toHaveTextContent('1');
expect(screen.getByTestId('tx-time').textContent).toMatch(/years ago/);
}); });
}); });
@@ -9,6 +9,7 @@ import { PartyLink } from '../links';
import { useScreenDimensions } from '@vegaprotocol/react-helpers'; import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import type { Screen } from '@vegaprotocol/react-helpers'; import type { Screen } from '@vegaprotocol/react-helpers';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { TimeAgo } from '../time-ago';
const DEFAULT_TRUNCATE_LENGTH = 7; const DEFAULT_TRUNCATE_LENGTH = 7;
@@ -32,6 +33,7 @@ export const TxsInfiniteListItem = ({
type, type,
block, block,
command, command,
createdAt,
}: Partial<BlockExplorerTransactionResult>) => { }: Partial<BlockExplorerTransactionResult>) => {
const { screenSize } = useScreenDimensions(); const { screenSize } = useScreenDimensions();
const idTruncateLength = useMemo( const idTruncateLength = useMemo(
@@ -85,6 +87,11 @@ export const TxsInfiniteListItem = ({
endChars={5} endChars={5}
/> />
</td> </td>
{['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize) && (
<td className="text-sm items-center font-mono" data-testid="tx-time">
{createdAt ? <TimeAgo date={createdAt} /> : '-'}
</td>
)}
</tr> </tr>
); );
}; };
@@ -3,6 +3,7 @@ import { TxsInfiniteListItem } from './txs-infinite-list-item';
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response'; import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
import EmptyList from '../empty-list/empty-list'; import EmptyList from '../empty-list/empty-list';
import { Loader } from '@vegaprotocol/ui-toolkit'; import { Loader } from '@vegaprotocol/ui-toolkit';
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
interface TxsInfiniteListProps { interface TxsInfiniteListProps {
hasMoreTxs: boolean; hasMoreTxs: boolean;
@@ -19,7 +20,16 @@ interface ItemProps {
} }
const Item = ({ tx }: ItemProps) => { const Item = ({ tx }: ItemProps) => {
const { hash, submitter, type, command, block, code, index: blockIndex } = tx; const {
hash,
submitter,
type,
command,
block,
code,
createdAt,
index: blockIndex,
} = tx;
return ( return (
<TxsInfiniteListItem <TxsInfiniteListItem
type={type} type={type}
@@ -29,6 +39,7 @@ const Item = ({ tx }: ItemProps) => {
hash={hash} hash={hash}
block={block} block={block}
index={blockIndex} index={blockIndex}
createdAt={createdAt}
/> />
); );
}; };
@@ -39,6 +50,7 @@ export const TxsInfiniteList = ({
className, className,
hasFilters = false, hasFilters = false,
}: TxsInfiniteListProps) => { }: TxsInfiniteListProps) => {
const { screenSize } = useScreenDimensions();
if (!txs || txs.length === 0) { if (!txs || txs.length === 0) {
if (!areTxsLoading) { if (!areTxsLoading) {
return ( return (
@@ -66,6 +78,9 @@ export const TxsInfiniteList = ({
<th>{t('Type')}</th> <th>{t('Type')}</th>
<th className="text-left">{t('From')}</th> <th className="text-left">{t('From')}</th>
<th>{t('Block')}</th> <th>{t('Block')}</th>
{['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize) && (
<th>{t('Time')}</th>
)}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
+1 -1
View File
@@ -133,7 +133,7 @@ export const ErrorBoundary = () => {
); );
}; };
const GHOST = ( export const GHOST = (
<svg <svg
width="56" width="56"
height="85" height="85"
@@ -36,30 +36,50 @@ const PERCENTAGE_PARAMS = [
'governance.proposal.updateNetParam.requiredMajority', 'governance.proposal.updateNetParam.requiredMajority',
'governance.proposal.updateNetParam.requiredParticipation', 'governance.proposal.updateNetParam.requiredParticipation',
'governance.proposal.updateMarket.minProposerEquityLikeShare', 'governance.proposal.updateMarket.minProposerEquityLikeShare',
'governance.proposal.VolumeDiscountProgram.requiredMajority',
'governance.proposal.VolumeDiscountProgram.requiredParticipation',
'governance.proposal.referralProgram.requiredMajority',
'governance.proposal.transfer.requiredMajority',
'governance.proposal.updateAsset.requiredMajority',
'governance.proposal.updateAsset.requiredParticipation',
'governance.proposal.transfer.requiredParticipation',
'governance.proposal.referralProgram.requiredParticipation',
'network.validators.ersatz.rewardFactor',
'network.validators.ersatz.multipleOfTendermintValidators',
'validators.vote.required', 'validators.vote.required',
]; 'referralProgram.maxReferralRewardFactor',
'referralProgram.maxReferralDiscountFactor',
'referralProgram.maxReferralRewardProportion',
].map((p) => p.toLowerCase());
const BIG_NUMBER_PARAMS = [ const BIG_NUMBER_PARAMS = [
'spam.protection.delegation.min.tokens', 'spam.protection.delegation.min.tokens',
'validators.delegation.minAmount', 'validators.delegation.minAmount',
'governance.proposal.transfer.maxAmount',
'reward.staking.delegation.minimumValidatorStake', 'reward.staking.delegation.minimumValidatorStake',
'reward.staking.delegation.maxPayoutPerParticipant', 'reward.staking.delegation.maxPayoutPerParticipant',
'reward.staking.delegation.maxPayoutPerEpoch', 'reward.staking.delegation.maxPayoutPerEpoch',
'spam.protection.voting.min.tokens', 'spam.protection.voting.min.tokens',
'spam.protection.proposal.min.tokens',
'governance.proposal.transfer.minVoterBalance',
'governance.proposal.freeform.minProposerBalance', 'governance.proposal.freeform.minProposerBalance',
'governance.proposal.updateNetParam.minVoterBalance', 'governance.proposal.updateNetParam.minVoterBalance',
'governance.proposal.updateMarket.minVoterBalance', 'governance.proposal.updateMarket.minVoterBalance',
'governance.proposal.asset.minVoterBalance', 'governance.proposal.asset.minVoterBalance',
'governance.proposal.updateNetParam.minProposerBalance', 'governance.proposal.updateNetParam.minProposerBalance',
'governance.proposal.freeform.minVoterBalance', 'governance.proposal.freeform.minVoterBalance',
'spam.protection.proposal.min.tokens',
'governance.proposal.updateMarket.minProposerBalance', 'governance.proposal.updateMarket.minProposerBalance',
'governance.proposal.asset.minProposerBalance', 'governance.proposal.asset.minProposerBalance',
'governance.proposal.transfer.minProposerBalance',
'governance.proposal.market.minProposerBalance', 'governance.proposal.market.minProposerBalance',
'governance.proposal.market.minVoterBalance', 'governance.proposal.market.minVoterBalance',
'governance.proposal.updateAsset.minProposerBalance', 'governance.proposal.updateAsset.minProposerBalance',
'governance.proposal.updateAsset.minVoterBalance', 'governance.proposal.updateAsset.minVoterBalance',
]; 'governance.proposal.referralProgram.minProposerBalance',
'governance.proposal.referralProgram.minVoterBalance',
'governance.proposal.VolumeDiscountProgram.minProposerBalance',
'governance.proposal.VolumeDiscountProgram.minVoterBalance',
].map((p) => p.toLowerCase());
export const renderGroupedParams = ( export const renderGroupedParams = (
group: GroupedParams, group: GroupedParams,
@@ -131,12 +151,12 @@ export const NetworkParameterRow = ({
<div className="pb-2"> <div className="pb-2">
<SyntaxHighlighter data={JSON.parse(value)} /> <SyntaxHighlighter data={JSON.parse(value)} />
</div> </div>
) : BIG_NUMBER_PARAMS.includes(key.toLowerCase()) ? (
addDecimalsFormatNumber(Number(value), 18)
) : PERCENTAGE_PARAMS.includes(key.toLowerCase()) ? (
`${formatNumber(Number(value) * 100, 0)}%`
) : isNaN(Number(value)) ? ( ) : isNaN(Number(value)) ? (
value value
) : BIG_NUMBER_PARAMS.includes(key) ? (
addDecimalsFormatNumber(Number(value), 18)
) : PERCENTAGE_PARAMS.includes(key) ? (
`${formatNumber(Number(value) * 100, 0)}%`
) : ( ) : (
formatNumber(Number(value), 4) formatNumber(Number(value), 4)
)} )}
@@ -49,6 +49,37 @@ fragment ExplorerOracleDataSource on OracleSpec {
} }
... on DataSourceDefinitionExternal { ... on DataSourceDefinitionExternal {
sourceType { sourceType {
... on EthCallSpec {
abi
args
method
requiredConfirmations
address
normalisers {
name
expression
}
trigger {
trigger {
... on EthTimeTrigger {
initial
every
until
}
}
}
filters {
key {
name
type
numberDecimalPlaces
}
conditions {
value
operator
}
}
}
... on DataSourceSpecConfiguration { ... on DataSourceSpecConfiguration {
signers { signers {
signer { signer {
@@ -11,6 +11,14 @@ fragment ExplorerOracleForMarketsMarket on Market {
id id
} }
} }
... on Perpetual {
dataSourceSpecForSettlementData {
id
}
dataSourceSpecForSettlementSchedule {
id
}
}
} }
} }
} }
+34 -3
View File
@@ -5,19 +5,19 @@ import * as Apollo from '@apollo/client';
const defaultOptions = {} as const; const defaultOptions = {} as const;
export type ExplorerOracleDataConnectionFragment = { __typename?: 'OracleSpec', dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } }; export type ExplorerOracleDataConnectionFragment = { __typename?: 'OracleSpec', dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } };
export type ExplorerOracleDataSourceFragment = { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } }; export type ExplorerOracleDataSourceFragment = { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } | { __typename?: 'EthCallSpec', abi?: Array<string> | null, args?: Array<string> | null, method: string, requiredConfirmations: number, address: string, normalisers?: Array<{ __typename?: 'Normaliser', name: string, expression: string }> | null, trigger: { __typename?: 'EthCallTrigger', trigger: { __typename?: 'EthTimeTrigger', initial?: any | null, every?: number | null, until?: any | null } }, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } };
export type ExplorerOracleSpecsQueryVariables = Types.Exact<{ [key: string]: never; }>; export type ExplorerOracleSpecsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type ExplorerOracleSpecsQuery = { __typename?: 'Query', oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean }, edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null }; export type ExplorerOracleSpecsQuery = { __typename?: 'Query', oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean }, edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } | { __typename?: 'EthCallSpec', abi?: Array<string> | null, args?: Array<string> | null, method: string, requiredConfirmations: number, address: string, normalisers?: Array<{ __typename?: 'Normaliser', name: string, expression: string }> | null, trigger: { __typename?: 'EthCallTrigger', trigger: { __typename?: 'EthTimeTrigger', initial?: any | null, every?: number | null, until?: any | null } }, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
export type ExplorerOracleSpecByIdQueryVariables = Types.Exact<{ export type ExplorerOracleSpecByIdQueryVariables = Types.Exact<{
id: Types.Scalars['ID']; id: Types.Scalars['ID'];
}>; }>;
export type ExplorerOracleSpecByIdQuery = { __typename?: 'Query', oracleSpec?: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } | null }; export type ExplorerOracleSpecByIdQuery = { __typename?: 'Query', oracleSpec?: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } | { __typename?: 'EthCallSpec', abi?: Array<string> | null, args?: Array<string> | null, method: string, requiredConfirmations: number, address: string, normalisers?: Array<{ __typename?: 'Normaliser', name: string, expression: string }> | null, trigger: { __typename?: 'EthCallTrigger', trigger: { __typename?: 'EthTimeTrigger', initial?: any | null, every?: number | null, until?: any | null } }, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } | null };
export const ExplorerOracleDataConnectionFragmentDoc = gql` export const ExplorerOracleDataConnectionFragmentDoc = gql`
fragment ExplorerOracleDataConnection on OracleSpec { fragment ExplorerOracleDataConnection on OracleSpec {
@@ -72,6 +72,37 @@ export const ExplorerOracleDataSourceFragmentDoc = gql`
} }
... on DataSourceDefinitionExternal { ... on DataSourceDefinitionExternal {
sourceType { sourceType {
... on EthCallSpec {
abi
args
method
requiredConfirmations
address
normalisers {
name
expression
}
trigger {
trigger {
... on EthTimeTrigger {
initial
every
until
}
}
}
filters {
key {
name
type
numberDecimalPlaces
}
conditions {
value
operator
}
}
}
... on DataSourceSpecConfiguration { ... on DataSourceSpecConfiguration {
signers { signers {
signer { signer {
@@ -3,12 +3,12 @@ import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client'; import * as Apollo from '@apollo/client';
const defaultOptions = {} as const; const defaultOptions = {} as const;
export type ExplorerOracleForMarketsMarketFragment = { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string } } } } }; export type ExplorerOracleForMarketsMarketFragment = { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string } } | { __typename?: 'Spot' } } } };
export type ExplorerOracleFormMarketsQueryVariables = Types.Exact<{ [key: string]: never; }>; export type ExplorerOracleFormMarketsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type ExplorerOracleFormMarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string } } } } } }> } | null }; export type ExplorerOracleFormMarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string } } | { __typename?: 'Spot' } } } } }> } | null };
export const ExplorerOracleForMarketsMarketFragmentDoc = gql` export const ExplorerOracleForMarketsMarketFragmentDoc = gql`
fragment ExplorerOracleForMarketsMarket on Market { fragment ExplorerOracleForMarketsMarket on Market {
@@ -24,6 +24,14 @@ export const ExplorerOracleForMarketsMarketFragmentDoc = gql`
id id
} }
} }
... on Perpetual {
dataSourceSpecForSettlementData {
id
}
dataSourceSpecForSettlementSchedule {
id
}
}
} }
} }
} }
@@ -10,7 +10,7 @@ interface OracleMarketsProps {
} }
/** /**
* Slightly misleadlingly names, OracleMarkets lists the market (almost always singular) * Slightly misleading names, OracleMarkets lists the market (almost always singular)
* to which an oracle is attached. It also checks what it triggers, by checking on the * to which an oracle is attached. It also checks what it triggers, by checking on the
* market whether it is attached to the dataSourceSpecForSettlementData or ..TradingTermination * market whether it is attached to the dataSourceSpecForSettlementData or ..TradingTermination
*/ */
@@ -27,8 +27,10 @@ export function OracleMarkets({ id }: OracleMarketsProps) {
const m = markets.find((m) => { const m = markets.find((m) => {
const p = m.tradableInstrument.instrument.product; const p = m.tradableInstrument.instrument.product;
if ( if (
p?.dataSourceSpecForSettlementData?.id === id || ((p.__typename === 'Future' || p.__typename === 'Perpetual') &&
p?.dataSourceSpecForTradingTermination?.id === id p.dataSourceSpecForSettlementData.id === id) ||
('dataSourceSpecForTradingTermination' in p &&
p.dataSourceSpecForTradingTermination.id === id)
) { ) {
return true; return true;
} }
@@ -61,8 +63,32 @@ export function getLabel(
m: ExplorerOracleForMarketsMarketFragment | null m: ExplorerOracleForMarketsMarketFragment | null
): string { ): string {
const settlementId = const settlementId =
m?.tradableInstrument?.instrument?.product?.dataSourceSpecForSettlementData ((m?.tradableInstrument?.instrument?.product?.__typename === 'Future' ||
?.id || null; m?.tradableInstrument?.instrument?.product?.__typename === 'Perpetual') &&
m?.tradableInstrument?.instrument?.product
?.dataSourceSpecForSettlementData?.id) ||
null;
return id === settlementId ? 'Settlement for' : 'Termination for'; const terminationId =
(m?.tradableInstrument?.instrument?.product?.__typename === 'Future' &&
m?.tradableInstrument?.instrument?.product
?.dataSourceSpecForTradingTermination?.id) ||
null;
const settlementScheduleId =
(m?.tradableInstrument?.instrument?.product?.__typename === 'Perpetual' &&
m?.tradableInstrument?.instrument?.product
?.dataSourceSpecForSettlementSchedule?.id) ||
null;
switch (id) {
case settlementId:
return 'Settlement for';
case terminationId:
return 'Termination for';
case settlementScheduleId:
return 'Settlement schedule for';
default:
return 'Unknown';
}
} }
@@ -67,6 +67,9 @@ export function OracleSigners({ sourceType }: OracleDetailsSignersProps) {
if (sourceType.__typename !== 'DataSourceDefinitionExternal') { if (sourceType.__typename !== 'DataSourceDefinitionExternal') {
return null; return null;
} }
if (!('signers' in sourceType.sourceType)) {
return null;
}
const signers = sourceType.sourceType.signers; const signers = sourceType.sourceType.signers;
if (!signers || signers.length === 0) { if (!signers || signers.length === 0) {
@@ -8,7 +8,9 @@ import { useScrollToLocation } from '../../../hooks/scroll-to-location';
import filter from 'recursive-key-filter'; import filter from 'recursive-key-filter';
const Oracles = () => { const Oracles = () => {
const { data, loading, error } = useExplorerOracleSpecsQuery(); const { data, loading, error } = useExplorerOracleSpecsQuery({
errorPolicy: 'ignore',
});
useDocumentTitle(['Oracles']); useDocumentTitle(['Oracles']);
useScrollToLocation(); useScrollToLocation();
@@ -23,6 +23,9 @@ fragment ExplorerPartyAssetsAccounts on AccountBalance {
... on Future { ... on Future {
quoteName quoteName
} }
... on Perpetual {
quoteName
}
} }
} }
} }
@@ -3,14 +3,14 @@ import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client'; import * as Apollo from '@apollo/client';
const defaultOptions = {} as const; const defaultOptions = {} as const;
export type ExplorerPartyAssetsAccountsFragment = { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, decimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } | null }; export type ExplorerPartyAssetsAccountsFragment = { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, decimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } | { __typename?: 'Perpetual', quoteName: string } | { __typename?: 'Spot' } } } } | null };
export type ExplorerPartyAssetsQueryVariables = Types.Exact<{ export type ExplorerPartyAssetsQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID']; partyId: Types.Scalars['ID'];
}>; }>;
export type ExplorerPartyAssetsQuery = { __typename?: 'Query', partiesConnection?: { __typename?: 'PartyConnection', edges: Array<{ __typename?: 'PartyEdge', node: { __typename?: 'Party', id: string, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string, name: string } } } | null> | null } | null, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string, linkings: { __typename?: 'StakesConnection', edges?: Array<{ __typename?: 'StakeLinkingEdge', node: { __typename?: 'StakeLinking', type: Types.StakeLinkingType, status: Types.StakeLinkingStatus, amount: string } } | null> | null } }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, decimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } | null } } | null> | null } | null } }> } | null }; export type ExplorerPartyAssetsQuery = { __typename?: 'Query', partiesConnection?: { __typename?: 'PartyConnection', edges: Array<{ __typename?: 'PartyEdge', node: { __typename?: 'Party', id: string, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string, name: string } } } | null> | null } | null, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string, linkings: { __typename?: 'StakesConnection', edges?: Array<{ __typename?: 'StakeLinkingEdge', node: { __typename?: 'StakeLinking', type: Types.StakeLinkingType, status: Types.StakeLinkingStatus, amount: string } } | null> | null } }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', name: string, id: string, decimals: number, symbol: string, source: { __typename: 'BuiltinAsset' } | { __typename: 'ERC20', contractAddress: string } }, market?: { __typename?: 'Market', id: string, decimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } | { __typename?: 'Perpetual', quoteName: string } | { __typename?: 'Spot' } } } } | null } } | null> | null } | null } }> } | null };
export const ExplorerPartyAssetsAccountsFragmentDoc = gql` export const ExplorerPartyAssetsAccountsFragmentDoc = gql`
fragment ExplorerPartyAssetsAccounts on AccountBalance { fragment ExplorerPartyAssetsAccounts on AccountBalance {
@@ -38,6 +38,9 @@ export const ExplorerPartyAssetsAccountsFragmentDoc = gql`
... on Future { ... on Future {
quoteName quoteName
} }
... on Perpetual {
quoteName
}
} }
} }
} }
@@ -0,0 +1,108 @@
import { BackgroundVideo } from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames';
const RestrictedPage = () => {
const errorTitle = '451 Unavailable';
const errorMessage =
'Due to uncertainty about the legal and regulatory status of the content hosted on this site, it is not available to visitors in your jurisdiction.';
return (
<div>
<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 font-mono">
{errorMessage}
</div>
</div>
</div>
);
};
const GHOST = (
<svg
width="56"
height="85"
viewBox="0 0 150 234"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.43 93.6821L0 104.097V172.435H5.13793V106.2L14.0779 97.3247L10.43 93.6821Z"
fill="black"
/>
<path d="M105.328 18.521H7.70703V172.435H105.328V18.521Z" fill="white" />
<path d="M38.5364 64.6953H33.3984V69.8258H38.5364V64.6953Z" fill="black" />
<path d="M43.6731 69.8257H38.5352V74.9561H43.6731V69.8257Z" fill="black" />
<path d="M48.8098 74.9561H43.6719V80.0865H48.8098V74.9561Z" fill="black" />
<path d="M38.5364 74.9561H33.3984V80.0865H38.5364V74.9561Z" fill="black" />
<path d="M48.8098 64.6953H43.6719V69.8258H48.8098V64.6953Z" fill="black" />
<path d="M69.3606 64.6953H64.2227V69.8258H69.3606V64.6953Z" fill="black" />
<path d="M74.5012 69.8257H69.3633V74.9561H74.5012V69.8257Z" fill="black" />
<path d="M79.6379 74.9561H74.5V80.0865H79.6379V74.9561Z" fill="black" />
<path d="M69.3606 74.9561H64.2227V80.0865H69.3606V74.9561Z" fill="black" />
<path d="M79.6379 64.6953H74.5V69.8258H79.6379V64.6953Z" fill="black" />
<path d="M79.6398 90.3477H33.3984V95.4781H79.6398V90.3477Z" fill="black" />
<path d="M48.8098 172.435H43.6719V234H48.8098V172.435Z" fill="black" />
<path d="M69.3606 172.435H64.2227V234H69.3606V172.435Z" fill="black" />
<path
d="M129.87 0.00408026L92.0273 14.3682L111.195 64.7203L149.038 50.3562L129.87 0.00408026Z"
fill="#FF0081"
/>
<path
d="M108.565 21.7836L103.762 23.6064L105.587 28.4024L110.39 26.5795L108.565 21.7836Z"
fill="white"
/>
<path
d="M115.189 24.7596L110.387 26.583L112.213 31.3785L117.015 29.5551L115.189 24.7596Z"
fill="white"
/>
<path
d="M121.826 27.7348L117.023 29.5576L118.849 34.3536L123.652 32.5307L121.826 27.7348Z"
fill="white"
/>
<path
d="M128.447 30.7059L123.645 32.5293L125.471 37.3247L130.273 35.5014L128.447 30.7059Z"
fill="white"
/>
<path
d="M135.084 33.6854L130.281 35.5083L132.107 40.3043L136.91 38.4814L135.084 33.6854Z"
fill="white"
/>
<path
d="M124.799 21.1156L119.996 22.939L121.822 27.7344L126.625 25.911L124.799 21.1156Z"
fill="white"
/>
<path
d="M127.775 14.492L122.973 16.3154L124.799 21.1109L129.601 19.2875L127.775 14.492Z"
fill="white"
/>
<path
d="M118.838 34.3499L114.035 36.1733L115.861 40.9688L120.664 39.1454L118.838 34.3499Z"
fill="white"
/>
<path
d="M115.857 40.9691L111.055 42.7925L112.881 47.5879L117.683 45.7645L115.857 40.9691Z"
fill="white"
/>
<path
d="M129.938 52.3822L139.906 91.5276L100.703 101.429L101.988 106.406L146.174 95.2215L134.922 51.0996L129.938 52.3822Z"
fill="black"
/>
</svg>
);
export default RestrictedPage;
@@ -1,5 +1,6 @@
export const Routes = { export const Routes = {
HOME: '/', HOME: '/',
RESTRICTED: '/restricted',
TX: 'txs', TX: 'txs',
BLOCKS: 'blocks', BLOCKS: 'blocks',
PARTIES: 'parties', PARTIES: 'parties',
@@ -30,6 +30,7 @@ import { remove0x } from '@vegaprotocol/utils';
import { PartyAccountsByAsset } from './parties/id/accounts'; import { PartyAccountsByAsset } from './parties/id/accounts';
import { Disclaimer } from './pages/disclaimer'; import { Disclaimer } from './pages/disclaimer';
import { FLAGS } from '@vegaprotocol/environment'; import { FLAGS } from '@vegaprotocol/environment';
import RestrictedPage from './restricted';
export type Navigable = { export type Navigable = {
path: string; path: string;
@@ -356,6 +357,14 @@ export const routerConfig: Route[] = [
...validators, ...validators,
], ],
}, },
{
path: Routes.RESTRICTED,
element: <RestrictedPage />,
handle: {
name: t('Restricted'),
text: t('Restricted'),
},
},
]; ];
export const router = createBrowserRouter(routerConfig); export const router = createBrowserRouter(routerConfig);
@@ -14,6 +14,10 @@ export interface BlockExplorerTransactionResult {
value: string; value: string;
}; };
error?: string; error?: string;
// These aren't strictly optional but are new in 0.73.0 so we need to make them optional
createdAt?: string;
version?: string;
pow?: string;
} }
export interface BlockExplorerTransactions { export interface BlockExplorerTransactions {
-10
View File
@@ -1453,11 +1453,6 @@ export interface components {
readonly liquidityMonitoringParameters?: components['schemas']['vegaLiquidityMonitoringParameters']; readonly liquidityMonitoringParameters?: components['schemas']['vegaLiquidityMonitoringParameters'];
/** @description Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected. */ /** @description Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected. */
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel']; readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
/**
* @description Percentage move up and down from the mid price which specifies the range of
* price levels over which automated liquidity provision orders will be deployed.
*/
readonly lpPriceRange?: string;
/** @description Optional new futures market metadata, tags. */ /** @description Optional new futures market metadata, tags. */
readonly metadata?: readonly string[]; readonly metadata?: readonly string[];
/** /**
@@ -1853,11 +1848,6 @@ export interface components {
readonly liquidityMonitoringParameters?: components['schemas']['vegaLiquidityMonitoringParameters']; readonly liquidityMonitoringParameters?: components['schemas']['vegaLiquidityMonitoringParameters'];
/** @description Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected. */ /** @description Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected. */
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel']; readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
/**
* @description Percentage move up and down from the mid price which specifies the range of
* price levels over which automated liquidity provision orders will be deployed.
*/
readonly lpPriceRange?: string;
/** @description Optional futures market metadata, tags. */ /** @description Optional futures market metadata, tags. */
readonly metadata?: readonly string[]; readonly metadata?: readonly string[];
/** @description Price monitoring parameters. */ /** @description Price monitoring parameters. */
+6
View File
@@ -21,6 +21,12 @@ NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72 NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
NX_VEGA_REST_URL=http://localhost:3008/api/v2/ NX_VEGA_REST_URL=http://localhost:3008/api/v2/
NX_SUCCESSOR_MARKETS=true NX_SUCCESSOR_MARKETS=true
NX_PRODUCT_PERPETUALS=true
NX_REFERRALS=true
NX_UPDATE_MARKET_STATE=true
NX_GOVERNANCE_TRANSFERS=true
NX_VOLUME_DISCOUNTS=true
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
+4
View File
@@ -4,3 +4,7 @@ NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_VOLUME_DISCOUNTS=true
+4
View File
@@ -4,3 +4,7 @@ NX_VEGA_URL=https://api.vega.community/graphql
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://etherscan.io NX_ETHERSCAN_URL=https://etherscan.io
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
NX_PRODUCT_PERPETUALS=false
NX_UPDATE_MARKET_STATE=false
NX_REFERRALS=false
NX_VOLUME_DISCOUNTS=false
+4
View File
@@ -4,3 +4,7 @@ NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_VOLUME_DISCOUNTS=true
@@ -1,21 +0,0 @@
{
"rationale": {
"title": "Add USDT Coin (USDT)",
"description": "Proposal to add USDT Coin (USDT) as an asset"
},
"terms": {
"newAsset": {
"changes": {
"name": "USDT Coin",
"symbol": "USDT",
"decimals": "18",
"quantum": "1",
"erc20": {
"contractAddress": "0xb404c51bbc10dcbe948077f18a4b8e553d160084"
}
}
},
"closingTimestamp": 1662374250,
"enactmentTimestamp": 1662460650
}
}
@@ -0,0 +1,15 @@
{
"rationale": {
"title": "Governance cancel transfer proposal",
"description": "Rejected cancel transfer proposal"
},
"terms": {
"cancelTransfer": {
"changes": {
"transferId": "invalid transfer id"
}
},
"closingTimestamp": 0,
"enactmentTimestamp": 0
}
}
@@ -0,0 +1,138 @@
{
"rationale": {
"description": "## Summary\n\nThis proposal requests to list BTC PERPS Incentive as a market with USD-P as a settlement asset on the Vega Network as discussed in: https://community.vega.xyz/.\n\n## Rationale\n\n- BTC is the largest Crypto asset with the highest volume and Marketcap.\n- Given the price, 1 decimal places will be used for price due to the number of valid digits in asset price. \n- Position decimal places will be set to 4 considering the value per contract\n- USDT is chosen as settlement asset due to its stability.",
"title": "perpetual market proposal"
},
"terms": {
"closingTimestamp": 0,
"enactmentTimestamp": 0,
"newMarket": {
"changes": {
"instrument": {
"name": "Token test market",
"code": "TEST.24h",
"perpetual": {
"clampLowerBound": "0",
"clampUpperBound": "0",
"interestRate": "0",
"marginFundingFactor": "0.1",
"settlementAsset": "73174a6fb1d5802ba0ac7bd7ab79e0a3a4837b262de0a4e80815a55442692bd0",
"quoteName": "fBTC",
"dataSourceSpecForSettlementData": {
"external": {
"ethOracle": {
"address": "0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43",
"abi": "[{\"inputs\":[],\"name\":\"latestAnswer\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
"method": "latestAnswer",
"normalisers": [
{
"name": "btc.price",
"expression": "$[0]"
}
],
"requiredConfirmations": 3,
"trigger": {
"timeTrigger": {
"every": 30
}
},
"filters": [
{
"key": {
"name": "btc.price",
"type": "TYPE_INTEGER",
"numberDecimalPlaces": 8
},
"conditions": [
{
"operator": "OPERATOR_GREATER_THAN_OR_EQUAL",
"value": "0"
}
]
}
]
}
}
},
"dataSourceSpecForSettlementSchedule": {
"internal": {
"timeTrigger": {
"conditions": [
{
"operator": "OPERATOR_GREATER_THAN_OR_EQUAL",
"value": "0"
}
],
"triggers": [
{
"every": 1800
}
]
}
}
},
"dataSourceSpecBinding": {
"settlementDataProperty": "btc.price",
"settlementScheduleProperty": "vegaprotocol.builtin.timetrigger"
}
}
},
"metadata": [
"base:BTC",
"quote:USD-P",
"class:fx/crypto",
"quarterly",
"sector:defi",
"enactment:2023-06-15T14:00:00Z",
"settlement:2023-09-30T08:00:00Z"
],
"priceMonitoringParameters": {
"triggers": [
{
"horizon": "3600",
"probability": "0.9999",
"auctionExtension": "120"
},
{
"horizon": "14400",
"probability": "0.9999",
"auctionExtension": "180"
},
{
"horizon": "43200",
"probability": "0.9999",
"auctionExtension": "300"
}
]
},
"liquidityMonitoringParameters": {
"targetStakeParameters": {
"timeWindow": "3600",
"scalingFactor": 1
},
"triggeringRatio": "0.7",
"auctionExtension": "1"
},
"liquiditySlaParameters": {
"priceRange": "0.05",
"commitmentMinTimeFraction": "0.95",
"performanceHysteresisEpochs": 1,
"slaCompetitionFactor": "0.95"
},
"logNormal": {
"riskAversionParameter": 0.000001,
"tau": 0.0001140771161,
"params": {
"sigma": 1.5
}
},
"decimalPlaces": "1",
"positionDecimalPlaces": "4",
"linearSlippageFactor": "0.001",
"quadraticSlippageFactor": "0.0"
}
}
}
}
@@ -10,7 +10,6 @@
"positionDecimalPlaces": "5", "positionDecimalPlaces": "5",
"linearSlippageFactor": "0.001", "linearSlippageFactor": "0.001",
"quadraticSlippageFactor": "0", "quadraticSlippageFactor": "0",
"lpPriceRange": "10",
"instrument": { "instrument": {
"name": "Token test market", "name": "Token test market",
"code": "TEST.24h", "code": "TEST.24h",
@@ -104,6 +103,12 @@
"r": 0.016, "r": 0.016,
"sigma": 0.5 "sigma": 0.5
} }
},
"liquiditySlaParameters": {
"priceRange": "0.95",
"commitmentMinTimeFraction": "0.5",
"performanceHysteresisEpochs": 2,
"slaCompetitionFactor": "0.75"
} }
} }
}, },
@@ -4,7 +4,6 @@
"positionDecimalPlaces": "5", "positionDecimalPlaces": "5",
"linearSlippageFactor": "0.001", "linearSlippageFactor": "0.001",
"quadraticSlippageFactor": "0", "quadraticSlippageFactor": "0",
"lpPriceRange": "10",
"instrument": { "instrument": {
"name": "Token test market", "name": "Token test market",
"code": "Token.24h", "code": "Token.24h",
@@ -98,6 +97,12 @@
"r": 0.016, "r": 0.016,
"sigma": 0.8 "sigma": 0.8
} }
},
"liquiditySlaParameters": {
"priceRange": "0.95",
"commitmentMinTimeFraction": "0.5",
"performanceHysteresisEpochs": 2,
"slaCompetitionFactor": "0.75"
} }
} }
} }
@@ -0,0 +1,16 @@
{
"rationale": {
"title": "Market resume test",
"description": "E2E test for market resume proposal"
},
"terms": {
"updateMarketState": {
"changes": {
"marketId": "b33bb4157e12355db22e41f277ddd0c10104dec29a4d6960bbcb96d186c40cbd",
"updateType": "MARKET_STATE_UPDATE_TYPE_RESUME"
}
},
"closingTimestamp": 0,
"enactmentTimestamp": 0
}
}
@@ -4,7 +4,6 @@
"positionDecimalPlaces": "5", "positionDecimalPlaces": "5",
"linearSlippageFactor": "0.001", "linearSlippageFactor": "0.001",
"quadraticSlippageFactor": "0", "quadraticSlippageFactor": "0",
"lpPriceRange": "10",
"instrument": { "instrument": {
"name": "Token test market", "name": "Token test market",
"code": "Token.24h", "code": "Token.24h",
@@ -99,6 +98,12 @@
"sigma": 0.8 "sigma": 0.8
} }
}, },
"liquiditySlaParameters": {
"priceRange": "0.95",
"commitmentMinTimeFraction": "0.5",
"performanceHysteresisEpochs": 2,
"slaCompetitionFactor": "0.75"
},
"successor": { "successor": {
"parentMarketId": "", "parentMarketId": "",
"insurancePoolFraction": "0.75" "insurancePoolFraction": "0.75"
@@ -0,0 +1,16 @@
{
"rationale": {
"title": "Market suspended test",
"description": "E2E test for market suspended proposal"
},
"terms": {
"updateMarketState": {
"changes": {
"marketId": "",
"updateType": "MARKET_STATE_UPDATE_TYPE_SUSPEND"
}
},
"closingTimestamp": 0,
"enactmentTimestamp": 0
}
}
@@ -0,0 +1,17 @@
{
"rationale": {
"title": "Market terminate test",
"description": "E2E test for market terminate proposal"
},
"terms": {
"updateMarketState": {
"changes": {
"marketId": "",
"updateType": "MARKET_STATE_UPDATE_TYPE_TERMINATE",
"price": "100"
}
},
"closingTimestamp": 0,
"enactmentTimestamp": 0
}
}
@@ -1,86 +0,0 @@
{
"lpPriceRange": "11",
"instrument": {
"code": "Token.24h",
"future": {
"quoteName": "fBTC",
"dataSourceSpecForSettlementData": {
"external": {
"oracle": {
"signers": [
{
"pubKey": {
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
}
}
],
"filters": [
{
"key": {
"name": "prices.BTC.value",
"type": "TYPE_INTEGER"
},
"conditions": [
{
"operator": "OPERATOR_GREATER_THAN",
"value": "0"
}
]
}
]
}
}
},
"dataSourceSpecForTradingTermination": {
"external": {
"oracle": {
"signers": [
{
"pubKey": {
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
}
}
],
"filters": [
{
"key": {
"name": "trading.terminated.ETH5",
"type": "TYPE_BOOLEAN"
},
"conditions": [
{
"operator": "OPERATOR_GREATER_THAN_OR_EQUAL",
"value": "1648684800000000000"
}
]
}
]
}
}
},
"dataSourceSpecBinding": {
"settlementDataProperty": "prices.BTC.value",
"tradingTerminationProperty": "trading.terminated.ETH5"
}
}
},
"metadata": ["sector:energy", "sector:food", "source:docs.vega.xyz"],
"priceMonitoringParameters": {
"triggers": [
{
"horizon": "43200",
"probability": "0.9999999",
"auctionExtension": "600"
}
]
},
"logNormal": {
"tau": 0.0001140771161,
"riskAversionParameter": 0.001,
"params": {
"mu": 0,
"r": 0.016,
"sigma": 0.3
}
}
}
@@ -1,5 +1,4 @@
{ {
"lpPriceRange": "10",
"linearSlippageFactor": "0.001", "linearSlippageFactor": "0.001",
"quadraticSlippageFactor": "0", "quadraticSlippageFactor": "0",
"instrument": { "instrument": {
@@ -98,5 +97,11 @@
"r": 0.016, "r": 0.016,
"sigma": 0.3 "sigma": 0.3
} }
},
"liquiditySlaParameters": {
"priceRange": "0.95",
"commitmentMinTimeFraction": "0.5",
"performanceHysteresisEpochs": 2,
"slaCompetitionFactor": "0.75"
} }
} }
@@ -9,6 +9,7 @@ import {
createTenDigitUnixTimeStampForSpecifiedDays, createTenDigitUnixTimeStampForSpecifiedDays,
generateFreeFormProposalTitle, generateFreeFormProposalTitle,
getDateFormatForSpecifiedDays, getDateFormatForSpecifiedDays,
getProposalDetailsValue,
getProposalFromTitle, getProposalFromTitle,
getProposalInformationFromTable, getProposalInformationFromTable,
goToMakeNewProposal, goToMakeNewProposal,
@@ -26,12 +27,16 @@ import {
} from '../../../../governance-e2e/src/support/staking.functions'; } from '../../../../governance-e2e/src/support/staking.functions';
import { ethereumWalletConnect } from '../../../../governance-e2e/src/support/wallet-eth.functions'; import { ethereumWalletConnect } from '../../../../governance-e2e/src/support/wallet-eth.functions';
import { import {
depositAsset,
switchVegaWalletPubKey, switchVegaWalletPubKey,
vegaWalletSetSpecifiedApprovalAmount, vegaWalletSetSpecifiedApprovalAmount,
} from '../../support/wallet-functions'; } from '../../support/wallet-functions';
import type { testFreeformProposal } from '../../support/common-interfaces'; import type { testFreeformProposal } from '../../support/common-interfaces';
import { formatDateWithLocalTimezone } from '@vegaprotocol/utils'; import { formatDateWithLocalTimezone } from '@vegaprotocol/utils';
import { createSuccessorMarketProposalTxBody } from '../../support/proposal.functions'; import {
createGovernanceTransferProposalTxBody,
createSuccessorMarketProposalTxBody,
} from '../../support/proposal.functions';
const proposalListItem = '[data-testid="proposals-list-item"]'; const proposalListItem = '[data-testid="proposals-list-item"]';
const participationNotMet = 'token-participation-not-met'; const participationNotMet = 'token-participation-not-met';
@@ -50,6 +55,8 @@ const openProposals = 'open-proposals';
const viewProposalButton = 'view-proposal-btn'; const viewProposalButton = 'view-proposal-btn';
const proposalTermsToggle = 'proposal-json-toggle'; const proposalTermsToggle = 'proposal-json-toggle';
const marketDataToggle = 'proposal-market-data-toggle'; const marketDataToggle = 'proposal-market-data-toggle';
const governanceTransferToggle = 'proposal-transfer-details';
const marketProposalType = 'proposal-type';
describe( describe(
'Governance flow for proposal details', 'Governance flow for proposal details',
@@ -58,6 +65,17 @@ describe(
before('connect wallets and set approval limit', function () { before('connect wallets and set approval limit', function () {
cy.visit('/'); cy.visit('/');
ethereumWalletConnect(); ethereumWalletConnect();
cy.createMarket();
navigateTo(navigation.proposals);
cy.getByTestId('closed-proposals').within(() => {
cy.contains('Add Lorem Ipsum market')
.parentsUntil(proposalListItem)
.last()
.within(() => {
cy.getByTestId(viewProposalButton).click();
});
});
getProposalInformationFromTable('ID').invoke('text').as('parentMarketId');
}); });
beforeEach('visit proposals tab', function () { beforeEach('visit proposals tab', function () {
@@ -296,9 +314,6 @@ describe(
}); });
it('Able to see successor market details with new and updated values', function () { it('Able to see successor market details with new and updated values', function () {
cy.createMarket();
cy.reload();
waitForSpinner();
cy.getByTestId('closed-proposals').within(() => { cy.getByTestId('closed-proposals').within(() => {
cy.contains('Add Lorem Ipsum market') cy.contains('Add Lorem Ipsum market')
.parentsUntil(proposalListItem) .parentsUntil(proposalListItem)
@@ -307,14 +322,9 @@ describe(
cy.getByTestId(viewProposalButton).click(); cy.getByTestId(viewProposalButton).click();
}); });
}); });
getProposalInformationFromTable('ID') cy.VegaWalletSubmitProposal(
.invoke('text') createSuccessorMarketProposalTxBody(this.parentMarketId)
.as('parentMarketId') );
.then(() => {
cy.VegaWalletSubmitProposal(
createSuccessorMarketProposalTxBody(this.parentMarketId)
);
});
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
cy.reload(); cy.reload();
getProposalFromTitle('Test successor market proposal details').within( getProposalFromTitle('Test successor market proposal details').within(
@@ -372,19 +382,221 @@ describe(
}); });
// 3003-PMAN-011 // 3003-PMAN-011
cy.get('.underline').contains('Parent Market ID').realHover(); cy.contains('Parent Market ID').realHover();
cy.getByTestId('tooltip-content', { timeout: 8000 }).should( cy.getByTestId('tooltip-content', { timeout: 8000 }).should(
'contain.text', 'contain.text',
'The ID of the market this market succeeds.' 'The ID of the market this market succeeds.'
); );
cy.get('.underline') cy.contains('Insurance Pool Fraction').realMouseUp().realHover();
.contains('Insurance Pool Fraction')
.realMouseUp()
.realHover();
cy.getByTestId('tooltip-content', { timeout: 8000 }).should( cy.getByTestId('tooltip-content', { timeout: 8000 }).should(
'contain.text', 'contain.text',
'The fraction of the insurance pool balance that is carried over from the parent market to the successor.' 'The fraction of the insurance pool balance that is carried over from the parent market to the successor.'
); );
}); });
it('Able to see perpetual market', function () {
const proposalPath =
'src/fixtures/proposals/new-market-perpetual-raw.json';
const enactmentTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
const closingTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(2);
submitUniqueRawProposal({
proposalBody: proposalPath,
enactmentTimestamp: enactmentTimestamp,
closingTimestamp: closingTimestamp,
});
getProposalFromTitle('perpetual market proposal').within(() => {
cy.getByTestId(marketProposalType).should(
'have.text',
'New market - perpetual'
);
cy.getByTestId(viewProposalButton).click();
});
cy.getByTestId(marketDataToggle).click();
getProposalDetailsValue('Product Type').should(
'contain.text',
'Perpetual'
);
cy.getByTestId(marketProposalType).should(
'have.text',
'New market - perpetual'
);
// Liquidity SLA protocols
getProposalDetailsValue('Performance Hysteresis Epochs').should(
'contain.text',
'1'
);
getProposalDetailsValue('SLA Competition Factor').should(
'contain.text',
'95.00%'
);
getProposalDetailsValue('Epoch Length').should('contain.text', '5s');
getProposalDetailsValue('Non Performance Bond Penalty Max').should(
'contain.text',
'0.05'
);
getProposalDetailsValue('Stake To CCY Volume').should(
'contain.text',
'0.3'
);
getProposalDetailsValue('Min Probability Of Trading LP Orders').should(
'contain.text',
'1e-8'
);
});
it('Able to see suspended market proposal', function () {
const proposalPath = 'src/fixtures/proposals/suspend-market-raw.json';
const enactmentTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
const closingTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(2);
submitUniqueRawProposal({
proposalBody: proposalPath,
updateMarketId: this.parentMarketId,
enactmentTimestamp: enactmentTimestamp,
closingTimestamp: closingTimestamp,
});
getProposalFromTitle('Market suspended test').within(() => {
cy.getByTestId(marketProposalType).should(
'have.text',
'Suspend market'
);
cy.getByTestId(viewProposalButton).click();
});
cy.getByTestId(marketProposalType).should('have.text', 'Suspend market');
cy.getByTestId(marketDataToggle).click();
cy.getByTestId('proposal-update-market-state').within(() => {
getProposalInformationFromTable('Market ID')
.invoke('text')
.and('eq', this.parentMarketId);
});
});
it('Able to see resume market proposal', function () {
const proposalPath = 'src/fixtures/proposals/resume-market-raw.json';
const enactmentTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
const closingTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(2);
submitUniqueRawProposal({
proposalBody: proposalPath,
updateMarketId: this.parentMarketId,
enactmentTimestamp: enactmentTimestamp,
closingTimestamp: closingTimestamp,
});
getProposalFromTitle('Market resume test').within(() => {
cy.getByTestId(marketProposalType).should('have.text', 'Resume market');
cy.getByTestId(viewProposalButton).click();
});
cy.getByTestId(marketProposalType).should('have.text', 'Resume market');
cy.getByTestId(marketDataToggle).click();
cy.getByTestId('proposal-update-market-state').within(() => {
getProposalInformationFromTable('Market ID')
.invoke('text')
.and('eq', this.parentMarketId);
});
});
it('Able to see terminate market proposal', function () {
const proposalPath = 'src/fixtures/proposals/terminate-market-raw.json';
const enactmentTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
const closingTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(2);
submitUniqueRawProposal({
proposalBody: proposalPath,
updateMarketId: this.parentMarketId,
enactmentTimestamp: enactmentTimestamp,
closingTimestamp: closingTimestamp,
});
getProposalFromTitle('Market terminate test').within(() => {
cy.getByTestId(marketProposalType).should(
'have.text',
'Terminate market'
);
cy.getByTestId(viewProposalButton).click();
});
cy.getByTestId(marketProposalType).should(
'have.text',
'Terminate market'
);
cy.getByTestId(marketDataToggle).click();
cy.getByTestId('proposal-update-market-state').within(() => {
getProposalInformationFromTable('Market ID')
.invoke('text')
.and('eq', this.parentMarketId);
getProposalDetailsValue('Termination Price').should(
'contain.text',
'0.001 fUSDC'
);
});
});
it('Able to see governance transfer proposal', function () {
const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de';
depositAsset(vegaAssetAddress, '1000', 18);
cy.getByTestId('currency-title', Cypress.env('txTimeout')).should(
'contain.text',
'Collateral'
);
cy.VegaWalletTopUpNetworkAccount('100');
cy.VegaWalletSubmitProposal(createGovernanceTransferProposalTxBody());
cy.reload();
getProposalFromTitle('Governance transfer proposal').within(() => {
cy.getByTestId(marketProposalType).should('have.text', 'New transfer');
cy.getByTestId(viewProposalButton).click();
});
cy.getByTestId(marketProposalType).should('have.text', 'New transfer');
cy.getByTestId(governanceTransferToggle).click();
cy.getByTestId('proposal-transfer-details-table').within(() => {
getProposalInformationFromTable('Source Type')
.invoke('text')
.and('eq', 'Network Treasury');
getProposalInformationFromTable('Destination')
.invoke('text')
.and('eq', Cypress.env('vegaWalletPublicKey'));
getProposalInformationFromTable('Asset')
.invoke('text')
.and('eq', 'VEGA');
getProposalInformationFromTable('Fraction Of Balance')
.invoke('text')
.and('eq', '50%');
getProposalInformationFromTable('Amount')
.invoke('text')
.and('eq', '100.00');
getProposalInformationFromTable('Transfer Type')
.invoke('text')
.and('eq', 'All or nothing');
getProposalInformationFromTable('Kind')
.invoke('text')
.and('eq', 'One off');
});
});
it(' Able to see cancel transfer proposal - rejected', function () {
const proposalPath = 'src/fixtures/proposals/cancel-transfer-raw.json';
const enactmentTimestamp =
createTenDigitUnixTimeStampForSpecifiedDays(11);
const closingTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(10);
submitUniqueRawProposal({
proposalBody: proposalPath,
enactmentTimestamp: enactmentTimestamp,
closingTimestamp: closingTimestamp,
submit: false,
});
cy.getByTestId('proposal-submit').should('be.visible').click();
cy.getByTestId('dialog-title').should('have.text', 'Proposal rejected');
cy.getByTestId('icon-cross').last().click();
navigateTo(navigation.proposals);
cy.get('[href="/proposals/rejected"]').click();
getProposalFromTitle('Governance cancel transfer proposal').within(() => {
cy.getByTestId(marketProposalType).should(
'have.text',
'CancelTransfer'
);
cy.getByTestId(viewProposalButton).click();
});
cy.getByTestId(marketProposalType).should('have.text', 'Cancel transfer');
getProposalInformationFromTable('Error details')
.invoke('text')
.and('eq', 'Governance transfer invalid transfer id not found');
getProposalInformationFromTable('transferId')
.invoke('text')
.and('eq', 'invalid transfer id');
});
} }
); );
@@ -65,7 +65,10 @@ context(
cy.getByTestId(viewProposalButton).click(); cy.getByTestId(viewProposalButton).click();
}); });
}); });
cy.getByTestId('proposal-type').should('have.text', 'New market'); cy.getByTestId('proposal-type').should(
'have.text',
'New market - future'
);
cy.getByTestId(proposalStatus).should('have.text', 'Enacted'); cy.getByTestId(proposalStatus).should('have.text', 'Enacted');
cy.getByTestId(votesTable).within(() => { cy.getByTestId(votesTable).within(() => {
cy.contains('Voting has ended.').should('be.visible'); cy.contains('Voting has ended.').should('be.visible');
@@ -36,6 +36,7 @@ const proposalType = 'proposal-type';
const proposalDetails = 'proposal-details'; const proposalDetails = 'proposal-details';
const newProposalSubmitButton = 'proposal-submit'; const newProposalSubmitButton = 'proposal-submit';
const proposalVoteDeadline = 'proposal-vote-deadline'; const proposalVoteDeadline = 'proposal-vote-deadline';
const proposalEnactmentDeadline = 'proposal-enactment-deadline';
const proposalParameterSelect = 'proposal-parameter-select'; const proposalParameterSelect = 'proposal-parameter-select';
const proposalMarketSelect = 'proposal-market-select'; const proposalMarketSelect = 'proposal-market-select';
const newProposalTitle = 'proposal-title'; const newProposalTitle = 'proposal-title';
@@ -227,6 +228,8 @@ context(
parseSpecialCharSequences: false, parseSpecialCharSequences: false,
delay: 2, delay: 2,
}); });
cy.getByTestId(proposalVoteDeadline).clear().type('2');
cy.getByTestId(proposalEnactmentDeadline).clear().type('3');
}); });
cy.getByTestId(proposalDownloadBtn) cy.getByTestId(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
@@ -634,6 +637,8 @@ context(
parseSpecialCharSequences: false, parseSpecialCharSequences: false,
delay: 2, delay: 2,
}); });
cy.getByTestId(proposalVoteDeadline).clear().type('2');
cy.getByTestId(proposalEnactmentDeadline).clear().type('3');
}); });
cy.getByTestId(proposalDownloadBtn) cy.getByTestId(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
@@ -89,11 +89,12 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
it('Newly created proposals list - shows title and portion of summary', function () { it('Newly created proposals list - shows title and portion of summary', function () {
const proposalPath = 'src/fixtures/proposals/new-market-raw.json'; const proposalPath = 'src/fixtures/proposals/new-market-raw.json';
const proposalTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(3); const enactmentTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
const closingTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(2);
submitUniqueRawProposal({ submitUniqueRawProposal({
proposalBody: proposalPath, proposalBody: proposalPath,
enactmentTimestamp: proposalTimestamp, enactmentTimestamp: enactmentTimestamp,
closingTimestamp: proposalTimestamp, closingTimestamp: closingTimestamp,
}); // 3001-VOTE-052 }); // 3001-VOTE-052
// 3001-VOTE-008 // 3001-VOTE-008
// 3001-VOTE-034 // 3001-VOTE-034
@@ -310,7 +310,9 @@ context(
closeStakingDialog(); closeStakingDialog();
navigateTo(navigation.validators); navigateTo(navigation.validators);
clickOnValidatorFromList(0); clickOnValidatorFromList(0);
cy.getByTestId(stakeRemoveStakeRadioButton, txTimeout).click(); cy.getByTestId(stakeRemoveStakeRadioButton, txTimeout).click({
force: true,
});
cy.getByTestId(stakeTokenAmountInputBox).type('-0.1'); cy.getByTestId(stakeTokenAmountInputBox).type('-0.1');
cy.contains('Waiting for next epoch to start', epochTimeout); cy.contains('Waiting for next epoch to start', epochTimeout);
cy.getByTestId(stakeTokenSubmitButton) cy.getByTestId(stakeTokenSubmitButton)
@@ -331,7 +333,7 @@ context(
closeStakingDialog(); closeStakingDialog();
navigateTo(navigation.validators); navigateTo(navigation.validators);
clickOnValidatorFromList(0); clickOnValidatorFromList(0);
cy.getByTestId(stakeRemoveStakeRadioButton).click(); cy.getByTestId(stakeRemoveStakeRadioButton).click({ force: true });
cy.getByTestId(stakeTokenAmountInputBox).type('4'); cy.getByTestId(stakeTokenAmountInputBox).type('4');
cy.contains('Waiting for next epoch to start', epochTimeout); cy.contains('Waiting for next epoch to start', epochTimeout);
cy.getByTestId(stakeTokenSubmitButton) cy.getByTestId(stakeTokenSubmitButton)
@@ -422,7 +424,7 @@ context(
validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%'); validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%');
}); });
it('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () { it.skip('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () {
// 1002-STKE-004 // 1002-STKE-004
stakingPageAssociateTokens('3'); stakingPageAssociateTokens('3');
verifyUnstakedBalance(3.0); verifyUnstakedBalance(3.0);
@@ -436,7 +438,7 @@ context(
verifyStakedBalance(7.0); verifyStakedBalance(7.0);
}); });
it('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () { it.skip('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () {
// 1002-STKE-004 // 1002-STKE-004
stakingPageAssociateTokens('3', { type: 'contract' }); stakingPageAssociateTokens('3', { type: 'contract' });
verifyUnstakedBalance(3.0); verifyUnstakedBalance(3.0);
@@ -450,7 +452,7 @@ context(
verifyStakedBalance(7.0); verifyStakedBalance(7.0);
}); });
it('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () { it.skip('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () {
// 1002-STKE-004 // 1002-STKE-004
stakingPageAssociateTokens('3', { type: 'wallet' }); stakingPageAssociateTokens('3', { type: 'wallet' });
verifyUnstakedBalance(3.0); verifyUnstakedBalance(3.0);
@@ -464,7 +466,7 @@ context(
verifyStakedBalance(7.0); verifyStakedBalance(7.0);
}); });
it('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () { it.skip('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () {
// 1002-STKE-004 // 1002-STKE-004
stakingPageAssociateTokens('6'); stakingPageAssociateTokens('6');
verifyUnstakedBalance(6.0); verifyUnstakedBalance(6.0);
@@ -156,7 +156,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
cy.getByTestId('subscription-cell').should('have.text', 'Yes'); cy.getByTestId('subscription-cell').should('have.text', 'Yes');
}); });
cy.getByTestId('connect').should('be.disabled'); cy.getByTestId('connect').should('be.disabled');
cy.getByTestId('node-url-custom').click(); cy.getByTestId('node-url-custom').click({ force: true });
cy.get('input').should('exist'); cy.get('input').should('exist');
cy.getByTestId('connect').should('be.disabled'); cy.getByTestId('connect').should('be.disabled');
cy.getByTestId('icon-cross').click(); cy.getByTestId('icon-cross').click();
@@ -74,25 +74,12 @@ context(
}); });
it('should be able to see a working link for - find out more about Vega governance', function () { it('should be able to see a working link for - find out more about Vega governance', function () {
// 3001-VOTE-001 // 3001-VOTE-001 // 3002-PROP-001
cy.getByTestId(proposalDocumentationLink) cy.getByTestId(proposalDocumentationLink)
.should('be.visible') .should('be.visible')
.and('have.text', 'Find out more about Vega governance') .and('have.text', 'Find out more about Vega governance')
.and('have.attr', 'href') .and('have.attr', 'href')
.and('equal', governanceDocsUrl); .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`
);
}
});
}); });
// 3007-PNE-021 // 3007-PNE-021
@@ -11,7 +11,6 @@ import {
waitForBeginningOfEpoch, waitForBeginningOfEpoch,
} from '../../support/staking.functions'; } from '../../support/staking.functions';
import { previousEpochData } from '../../fixtures/mocks/previous-epoch'; import { previousEpochData } from '../../fixtures/mocks/previous-epoch';
import { chainIdQuery, statisticsQuery } from '@vegaprotocol/mock';
const guideLink = 'staking-guide-link'; const guideLink = 'staking-guide-link';
const validatorTitle = 'validator-node-title'; const validatorTitle = 'validator-node-title';
@@ -38,17 +37,11 @@ const txTimeout = Cypress.env('txTimeout');
context('Validators Page - verify elements on page', function () { context('Validators Page - verify elements on page', function () {
before('navigate to validators page', () => { before('navigate to validators page', () => {
cy.mockGQL((req) => { cy.mockChainId();
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
});
cy.visit('/validators'); cy.visit('/validators');
}); });
beforeEach(() => { beforeEach(() => {
cy.mockGQL((req) => { cy.mockChainId();
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
});
}); });
describe('with wallets disconnected', { tags: '@smoke' }, function () { describe('with wallets disconnected', { tags: '@smoke' }, function () {
@@ -189,10 +182,7 @@ context('Validators Page - verify elements on page', function () {
{ tags: '@smoke' }, { tags: '@smoke' },
function () { function () {
before('connect wallets and click on validator', function () { before('connect wallets and click on validator', function () {
cy.mockGQL((req) => { cy.mockChainId();
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
});
cy.visit('/validators'); cy.visit('/validators');
cy.connectVegaWallet(); cy.connectVegaWallet();
clickOnValidatorFromList(0); clickOnValidatorFromList(0);
@@ -4,8 +4,6 @@ import {
vegaWalletFaucetAssetsWithoutCheck, vegaWalletFaucetAssetsWithoutCheck,
vegaWalletTeardown, vegaWalletTeardown,
} from '../../support/wallet-functions'; } from '../../support/wallet-functions';
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { chainIdQuery, statisticsQuery } from '@vegaprotocol/mock';
const walletContainer = 'aside [data-testid="vega-wallet"]'; const walletContainer = 'aside [data-testid="vega-wallet"]';
const walletHeader = '[data-testid="wallet-header"] h1'; const walletHeader = '[data-testid="wallet-header"] h1';
@@ -88,10 +86,7 @@ context(
describe('when vega wallet connected', function () { describe('when vega wallet connected', function () {
before('connect vega wallet', function () { before('connect vega wallet', function () {
cy.mockGQL((req) => { cy.mockChainId();
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
});
cy.visit('/'); cy.visit('/');
cy.wait('@ChainId'); cy.wait('@ChainId');
cy.connectVegaWallet(); cy.connectVegaWallet();
@@ -276,10 +271,7 @@ context(
]; ];
before('faucet assets to connected vega wallet', function () { before('faucet assets to connected vega wallet', function () {
cy.mockGQL((req) => { cy.mockChainId();
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
});
for (const { id, amount } of assets) { for (const { id, amount } of assets) {
vegaWalletFaucetAssetsWithoutCheck(id, amount, vegaWalletPublicKey); vegaWalletFaucetAssetsWithoutCheck(id, amount, vegaWalletPublicKey);
} }
@@ -54,6 +54,7 @@ export function submitUniqueRawProposal(proposalFields: {
proposalBody?: string; proposalBody?: string;
proposalTitle?: string; proposalTitle?: string;
proposalDescription?: string; proposalDescription?: string;
updateMarketId?: string;
closingTimestamp?: number; closingTimestamp?: number;
enactmentTimestamp?: number; enactmentTimestamp?: number;
submit?: boolean; submit?: boolean;
@@ -71,6 +72,10 @@ export function submitUniqueRawProposal(proposalFields: {
if (proposalFields.proposalDescription) { if (proposalFields.proposalDescription) {
rawProposal.rationale.description = proposalFields.proposalDescription; rawProposal.rationale.description = proposalFields.proposalDescription;
} }
if (proposalFields.updateMarketId) {
rawProposal.terms.updateMarketState.changes.marketId =
proposalFields.updateMarketId;
}
if (proposalFields.closingTimestamp) { if (proposalFields.closingTimestamp) {
rawProposal.terms.closingTimestamp = proposalFields.closingTimestamp; rawProposal.terms.closingTimestamp = proposalFields.closingTimestamp;
} else if ( } else if (
@@ -232,21 +237,25 @@ export function getDownloadedProposalJsonPath(proposalType: string) {
return filepath; return filepath;
} }
export function getProposalDetailsValue(RowName: string) {
return cy
.contains(RowName)
.parentsUntil(proposalInformationTableRows)
.parent()
.first();
}
export function validateProposalDetailsDiff( export function validateProposalDetailsDiff(
RowName: string, RowName: string,
changeType: proposalChangeType, changeType: proposalChangeType,
newValue: string, newValue: string,
oldValue?: string oldValue?: string
) { ) {
cy.contains(RowName) getProposalDetailsValue(RowName).within(() => {
.parentsUntil(proposalInformationTableRows) cy.contains(changeType).should('be.visible');
.parent() cy.contains(newValue).should('be.visible');
.first() if (oldValue) cy.contains(oldValue).should('have.class', 'line-through');
.within(() => { });
cy.contains(changeType).should('be.visible');
cy.contains(newValue).should('be.visible');
if (oldValue) cy.contains(oldValue).should('have.class', 'line-through');
});
} }
function getFormattedTime() { function getFormattedTime() {
+1 -6
View File
@@ -9,8 +9,6 @@ import './wallet-functions.ts';
import './proposal.functions.ts'; import './proposal.functions.ts';
import 'cypress-mochawesome-reporter/register'; import 'cypress-mochawesome-reporter/register';
import registerCypressGrep from '@cypress/grep'; import registerCypressGrep from '@cypress/grep';
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { chainIdQuery, statisticsQuery } from '@vegaprotocol/mock';
import { turnTelemetryOff } from './common.functions.ts'; import { turnTelemetryOff } from './common.functions.ts';
registerCypressGrep(); registerCypressGrep();
@@ -29,10 +27,7 @@ before(() => {
// // Ensuring the telemetry modal doesn't disrupt the tests // // Ensuring the telemetry modal doesn't disrupt the tests
turnTelemetryOff(); turnTelemetryOff();
// Mock chainId fetch which happens on every page for wallet connection // Mock chainId fetch which happens on every page for wallet connection
cy.mockGQL((req) => { cy.mockChainId();
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
});
// Self stake validators so they are displayed // Self stake validators so they are displayed
cy.validatorsSelfDelegate(); cy.validatorsSelfDelegate();
}); });
@@ -1,9 +1,10 @@
import { addSeconds, millisecondsToSeconds } from 'date-fns'; import { addDays, addSeconds, millisecondsToSeconds } from 'date-fns';
import type { ProposalSubmissionBody } from '@vegaprotocol/wallet'; import type { ProposalSubmissionBody } from '@vegaprotocol/wallet';
import { aliasGQLQuery } from '@vegaprotocol/cypress'; import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { upgradeProposalsData } from '../fixtures/mocks/network-upgrade'; import { upgradeProposalsData } from '../fixtures/mocks/network-upgrade';
import { proposalsData } from '../fixtures/mocks/proposals'; import { proposalsData } from '../fixtures/mocks/proposals';
import { nodeData } from '../fixtures/mocks/nodes'; import { nodeData } from '../fixtures/mocks/nodes';
import { AccountType, GovernanceTransferType } from '@vegaprotocol/types';
export function createUpdateNetworkProposalTxBody(): ProposalSubmissionBody { export function createUpdateNetworkProposalTxBody(): ProposalSubmissionBody {
const MIN_CLOSE_SEC = 5; const MIN_CLOSE_SEC = 5;
@@ -105,8 +106,13 @@ export function createNewMarketProposalTxBody(): ProposalSubmissionBody {
decimalPlaces: '5', decimalPlaces: '5',
positionDecimalPlaces: '5', positionDecimalPlaces: '5',
linearSlippageFactor: '0.001', linearSlippageFactor: '0.001',
liquiditySlaParameters: {
priceRange: '0.5',
commitmentMinTimeFraction: '0.1',
performanceHysteresisEpochs: 2,
slaCompetitionFactor: '0.1',
},
quadraticSlippageFactor: '0', quadraticSlippageFactor: '0',
lpPriceRange: '10',
instrument: { instrument: {
name: 'Token test market', name: 'Token test market',
code: 'TEST.24h', code: 'TEST.24h',
@@ -235,7 +241,12 @@ export function createSuccessorMarketProposalTxBody(
positionDecimalPlaces: '5', positionDecimalPlaces: '5',
linearSlippageFactor: '0.001', linearSlippageFactor: '0.001',
quadraticSlippageFactor: '0', quadraticSlippageFactor: '0',
lpPriceRange: '10', liquiditySlaParameters: {
priceRange: '0.5',
commitmentMinTimeFraction: '0.1',
performanceHysteresisEpochs: 2,
slaCompetitionFactor: '0.1',
},
instrument: { instrument: {
name: 'Token test market', name: 'Token test market',
code: 'TEST.24h', code: 'TEST.24h',
@@ -348,6 +359,46 @@ export function createSuccessorMarketProposalTxBody(
}; };
} }
export function createGovernanceTransferProposalTxBody(): ProposalSubmissionBody {
const MIN_CLOSE_SEC = 5;
const MIN_ENACT_SEC = 7;
const closingDate = addDays(new Date(), MIN_CLOSE_SEC);
const enactmentDate = addDays(closingDate, MIN_ENACT_SEC);
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
const destination = Cypress.env('vegaWalletPublicKey');
return {
proposalSubmission: {
rationale: {
title: 'Governance transfer proposal',
description: 'E2E test for transfer proposal test',
},
terms: {
newTransfer: {
changes: {
fractionOfBalance: '0.5',
amount: '100' + '0'.repeat(18),
sourceType: AccountType.ACCOUNT_TYPE_NETWORK_TREASURY,
source: '',
transferType:
GovernanceTransferType.GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING,
destinationType: AccountType.ACCOUNT_TYPE_GENERAL,
destination,
asset:
'b4f2726571fbe8e33b442dc92ed2d7f0d810e21835b7371a7915a365f07ccd9b',
oneOff: {
deliverOn: '0',
},
},
},
closingTimestamp,
enactmentTimestamp,
},
},
};
}
export function mockNetworkUpgradeProposal() { export function mockNetworkUpgradeProposal() {
cy.mockGQL((req) => { cy.mockGQL((req) => {
aliasGQLQuery(req, 'Nodes', nodeData); aliasGQLQuery(req, 'Nodes', nodeData);
@@ -46,7 +46,7 @@ export function stakingValidatorPageAddStake(stake: string) {
export function stakingValidatorPageRemoveStake(stake: string) { export function stakingValidatorPageRemoveStake(stake: string) {
cy.highlight(`Removing a stake of ${stake}`); cy.highlight(`Removing a stake of ${stake}`);
cy.get(removeStakeRadioButton, epochTimeout).click(); cy.get(removeStakeRadioButton, epochTimeout).click({ force: true });
cy.get(tokenAmountInputBox).type(stake); cy.get(tokenAmountInputBox).type(stake);
waitForBeginningOfEpoch(); waitForBeginningOfEpoch();
cy.get(tokenSubmitButton) cy.get(tokenSubmitButton)
@@ -70,9 +70,13 @@ export function stakingPageAssociateTokens(
cy.highlight(`Associating ${amount} tokens from ${type}`); cy.highlight(`Associating ${amount} tokens from ${type}`);
cy.get(ethWalletAssociateButton).first().click(); cy.get(ethWalletAssociateButton).first().click();
if (type === 'wallet') { if (type === 'wallet') {
cy.get(associateWalletRadioButton, { timeout: 30000 }).click(); cy.get(associateWalletRadioButton, { timeout: 30000 }).click({
force: true,
});
} else if (type === 'contract') { } else if (type === 'contract') {
cy.get(associateContractRadioButton, { timeout: 30000 }).click(); cy.get(associateContractRadioButton, { timeout: 30000 }).click({
force: true,
});
} else { } else {
cy.highlight(`${type} is not association option`); cy.highlight(`${type} is not association option`);
} }
@@ -41,6 +41,9 @@ export async function depositAsset(
) { ) {
// Approve asset // Approve asset
const faucet = new Token(assetEthAddress, signer); const faucet = new Token(assetEthAddress, signer);
// Wait needed to allow Eth chain to catch up
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(4000);
cy.wrap( cy.wrap(
faucet.approve(Erc20BridgeAddress, amount + '0'.repeat(decimalPlaces + 1)), faucet.approve(Erc20BridgeAddress, amount + '0'.repeat(decimalPlaces + 1)),
transactionTimeout transactionTimeout
+6
View File
@@ -8,6 +8,7 @@ NX_FAIRGROUND=false
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","STAGNET1":"https://governance.stagnet1.vega.rocks","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz"}' NX_VEGA_NETWORKS='{"DEVNET":"https://dev.governance.vega.xyz","STAGNET1":"https://governance.stagnet1.vega.rocks","TESTNET":"https://governance.fairground.wtf","MAINNET":"https://governance.vega.xyz"}'
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_VEGA_WALLET_URL=http://localhost:1789 NX_VEGA_WALLET_URL=http://localhost:1789
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
@@ -32,3 +33,8 @@ LC_ALL="en_US.UTF-8"
# Cosmic elevator flags # Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true NX_SUCCESSOR_MARKETS=true
NX_METAMASK_SNAPS=true NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=false
NX_UPDATE_MARKET_STATE=false
NX_REFERRALS=false
NX_GOVERNANCE_TRANSFERS=false
NX_VOLUME_DISCOUNTS=false
+4
View File
@@ -33,3 +33,7 @@ CYPRESS_FAIRGROUND=false
# Cosmic elevator flags # Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false NX_SUCCESSOR_MARKETS=false
NX_METAMASK_SNAPS=false NX_METAMASK_SNAPS=false
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_VOLUME_DISCOUNTS=true
+4
View File
@@ -25,3 +25,7 @@ NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/m
# Cosmic elevator flags # Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true NX_SUCCESSOR_MARKETS=true
NX_METAMASK_SNAPS=true NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_VOLUME_DISCOUNTS=true
+5 -1
View File
@@ -17,10 +17,14 @@ NX_VEGA_REST_URL=https://api.vega.community/api/v2/
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
NX_TENDERMINT_URL=https://be.vega.community NX_TENDERMINT_URL=https://be.vega.community
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
# Cosmic elevator flags # Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false NX_SUCCESSOR_MARKETS=false
NX_METAMASK_SNAPS=false NX_METAMASK_SNAPS=false
NX_PRODUCT_PERPETUALS=false
NX_UPDATE_MARKET_STATE=false
NX_REFERRALS=false
NX_VOLUME_DISCOUNTS=false
+4
View File
@@ -23,3 +23,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
# Cosmic elevator flags # Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false NX_SUCCESSOR_MARKETS=false
NX_METAMASK_SNAPS=false NX_METAMASK_SNAPS=false
NX_PRODUCT_PERPETUALS=false
NX_UPDATE_MARKET_STATE=false
NX_REFERRALS=false
NX_VOLUME_DISCOUNTS=false
+6
View File
@@ -10,6 +10,7 @@ NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/ NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
@@ -20,3 +21,8 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
# Cosmic elevator flags # Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true NX_SUCCESSOR_MARKETS=true
NX_METAMASK_SNAPS=true NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_GOVERNANCE_TRANSFERS=true
NX_VOLUME_DISCOUNTS=true
+5
View File
@@ -15,6 +15,7 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/ NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996 NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
@@ -25,3 +26,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
# Cosmic elevator flags # Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true NX_SUCCESSOR_MARKETS=true
NX_METAMASK_SNAPS=true NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_VOLUME_DISCOUNTS=true
+4
View File
@@ -22,3 +22,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.
# Cosmic elevator flags # Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false NX_SUCCESSOR_MARKETS=false
NX_METAMASK_SNAPS=false NX_METAMASK_SNAPS=false
NX_PRODUCT_PERPETUALS=false
NX_UPDATE_MARKET_STATE=false
NX_REFERRALS=false
NX_VOLUME_DISCOUNTS=false
+1
View File
@@ -1,4 +1,5 @@
/* eslint-disable */ /* eslint-disable */
process.env.TZ = 'GMT';
export default { export default {
displayName: 'governance', displayName: 'governance',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
+18 -6
View File
@@ -26,11 +26,11 @@ import {
} from '@vegaprotocol/web3'; } from '@vegaprotocol/web3';
import { Web3Provider } from '@vegaprotocol/web3'; import { Web3Provider } from '@vegaprotocol/web3';
import { VegaWalletDialogs } from './components/vega-wallet-dialogs'; import { VegaWalletDialogs } from './components/vega-wallet-dialogs';
import { VegaWalletProvider } from '@vegaprotocol/wallet';
import { import {
useVegaTransactionManager, useVegaTransactionManager,
useVegaTransactionUpdater, useVegaTransactionUpdater,
VegaWalletProvider, } from '@vegaprotocol/web3';
} from '@vegaprotocol/wallet';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { useEthereumConfig } from '@vegaprotocol/web3'; import { useEthereumConfig } from '@vegaprotocol/web3';
import { import {
@@ -38,10 +38,10 @@ import {
NetworkLoader, NetworkLoader,
useInitializeEnv, useInitializeEnv,
NodeGuard, NodeGuard,
AppFailure,
NodeSwitcherDialog, NodeSwitcherDialog,
useNodeSwitcherStore, useNodeSwitcherStore,
DocsLinks, DocsLinks,
NodeFailure,
} from '@vegaprotocol/environment'; } from '@vegaprotocol/environment';
import { ENV } from './config'; import { ENV } from './config';
import type { InMemoryCacheConfig } from '@apollo/client'; import type { InMemoryCacheConfig } from '@apollo/client';
@@ -106,6 +106,7 @@ const Web3Container = ({
useEthWithdrawApprovalsManager(); useEthWithdrawApprovalsManager();
return null; return null;
}; };
const [connectors, initializeConnectors] = useWeb3ConnectStore((store) => [ const [connectors, initializeConnectors] = useWeb3ConnectStore((store) => [
store.connectors, store.connectors,
store.initialize, store.initialize,
@@ -184,7 +185,7 @@ const Web3Container = ({
<TemplateSidebar sidebar={sideBar}> <TemplateSidebar sidebar={sideBar}>
<AppRouter /> <AppRouter />
</TemplateSidebar> </TemplateSidebar>
<footer className="p-4 border-t border-neutral-700 break-all"> <footer className="p-4 break-all border-t border-neutral-700">
<NetworkInfo /> <NetworkInfo />
</footer> </footer>
</AppLayout> </AppLayout>
@@ -239,6 +240,9 @@ const AppContainer = () => {
store.setDialogOpen, store.setDialogOpen,
]); ]);
// Hacky skip all the loading & web3 init for geo restricted users
const isRestricted = document?.location?.pathname?.includes('/restricted');
useEffect(() => { useEffect(() => {
if (ENV.dsn && telemetryOn === 'true') { if (ENV.dsn && telemetryOn === 'true') {
Sentry.init({ Sentry.init({
@@ -304,15 +308,23 @@ const AppContainer = () => {
} }
}, [GIT_COMMIT_HASH, GIT_BRANCH, VEGA_ENV, telemetryOn]); }, [GIT_COMMIT_HASH, GIT_BRANCH, VEGA_ENV, telemetryOn]);
if (isRestricted) {
return (
<Router>
<AppRouter />
</Router>
);
}
return ( return (
<Router> <Router>
<ScrollToTop /> <ScrollToTop />
<AppStateProvider> <AppStateProvider>
<div className="min-h-full text-white"> <div className="min-h-full text-white grid">
<NodeGuard <NodeGuard
skeleton={<div>{t('Loading')}</div>} skeleton={<div>{t('Loading')}</div>}
failure={ failure={
<AppFailure title={t('NodeUnsuitable', { url: VEGA_URL })} /> <NodeFailure title={t('NodeUnsuitable', { url: VEGA_URL })} />
} }
> >
<AsyncRenderer<EthereumConfig | null> <AsyncRenderer<EthereumConfig | null>
+80 -1
View File
@@ -9,6 +9,7 @@
"pageTitleRedemptionTranche": "Redeem from Tranche", "pageTitleRedemptionTranche": "Redeem from Tranche",
"pageTitleTranches": "Vesting tranches", "pageTitleTranches": "Vesting tranches",
"pageTitle404": "Page not found", "pageTitle404": "Page not found",
"pageTitle451": "451 unavailable",
"pageTitleNotPermitted": "Can not proceed!", "pageTitleNotPermitted": "Can not proceed!",
"pageTitleDisassociate": "Disassociate $VEGA tokens from a Vega key", "pageTitleDisassociate": "Disassociate $VEGA tokens from a Vega key",
"pageTitleProposals": "Proposals", "pageTitleProposals": "Proposals",
@@ -613,6 +614,9 @@
"proposalDetails": "Proposal details", "proposalDetails": "Proposal details",
"marketSpecification": "Market specification", "marketSpecification": "Market specification",
"viewMarketJson": "View market JSON", "viewMarketJson": "View market JSON",
"marketId": "Market ID",
"marketName": "Market name",
"marketCode": "Market code",
"proposalDescription": "Description", "proposalDescription": "Description",
"currentlySetTo": "Currently expected to ", "currentlySetTo": "Currently expected to ",
"currently": "currently", "currently": "currently",
@@ -705,10 +709,21 @@
"parameter": "parameter", "parameter": "parameter",
"NewMarketProposal": "New market proposal", "NewMarketProposal": "New market proposal",
"UpdateMarketProposal": "Update market proposal", "UpdateMarketProposal": "Update market proposal",
"UpdateMarketStateProposal": "Update market state proposal",
"UpdateReferralProgramProposal": "Update referral program proposal",
"UpdateVolumeDiscountProgramProposal": "Update volume discount program proposal",
"MarketChange": "Market change",
"MarketStateChange": "Market state change",
"MarketDetails": "Market details",
"NewAssetProposal": "New asset proposal", "NewAssetProposal": "New asset proposal",
"UpdateAssetProposal": "Update asset proposal", "UpdateAssetProposal": "Update asset proposal",
"NewFreeformProposal": "New freeform proposal", "NewFreeformProposal": "New freeform proposal",
"NewRawProposal": "New proposal", "NewRawProposal": "New proposal",
"NewTransferProposal": "New transfer proposal",
"CancelTransferProposal": "Cancel transfer proposal",
"MARKET_STATE_UPDATE_TYPE_RESUME": "Resume market",
"MARKET_STATE_UPDATE_TYPE_SUSPEND": "Suspend market",
"MARKET_STATE_UPDATE_TYPE_TERMINATE": "Terminate market",
"MinProposalRequirements": "You must have at least {{value}} VEGA associated to make a proposal", "MinProposalRequirements": "You must have at least {{value}} VEGA associated to make a proposal",
"MinProposalVoteRequirements": "You must have at least {{value}} VEGA associated to vote on this proposal", "MinProposalVoteRequirements": "You must have at least {{value}} VEGA associated to vote on this proposal",
"totalSupply": "Total Supply", "totalSupply": "Total Supply",
@@ -717,9 +732,17 @@
"ProposalDocsPrefix": "For guidance on how to make proposals, see", "ProposalDocsPrefix": "For guidance on how to make proposals, see",
"NetworkParameter": "Network parameter", "NetworkParameter": "Network parameter",
"NewMarket": "New market", "NewMarket": "New market",
"NewMarketPerpetualProduct": "New market - perpetual",
"NewMarketFutureProduct": "New market - future",
"NewMarketSpotProduct": "New market - spot",
"UpdateMarket": "Update market", "UpdateMarket": "Update market",
"UpdateMarketState": "Update market state",
"UpdateReferralProgram": "Update referral program",
"UpdateVolumeDiscountProgram": "Update volume discount program",
"NewAsset": "New asset", "NewAsset": "New asset",
"UpdateAsset": "Update asset", "UpdateAsset": "Update asset",
"NewTransfer": "New transfer",
"CancelTransfer": "Cancel transfer",
"AssetID": "Asset ID", "AssetID": "Asset ID",
"Freeform": "Freeform", "Freeform": "Freeform",
"RawProposal": "Let me choose (raw proposal)", "RawProposal": "Let me choose (raw proposal)",
@@ -874,5 +897,61 @@
"HowToPropose": "How to make a proposal", "HowToPropose": "How to make a proposal",
"HowToProposeRawStep1": "1. Sense check your proposal with the community on the forum:", "HowToProposeRawStep1": "1. Sense check your proposal with the community on the forum:",
"HowToProposeRawStep2": "2. Use the appropriate proposal template in the docs:", "HowToProposeRawStep2": "2. Use the appropriate proposal template in the docs:",
"HowToProposeRawStep3": "3. Submit on-chain below" "HowToProposeRawStep3": "3. Submit on-chain below",
"proposalTransferDetails": "New governance transfer details",
"proposalCancelTransferDetails": "Cancel governance transfer details",
"BenefitTiers": "Benefit tiers",
"BenefitTierMinimumEpochs": "Minimum epochs",
"BenefitTierMinimumEpochsDescription": "The minimum number of epochs the party needs to be in the referral set to be eligible for the benefit",
"BenefitTierMinimumRunningNotionalTakerVolume": "Minimum running notional taker volume",
"BenefitTierMinimumRunningNotionalTakerVolumeDescription": "The minimum running notional for the given benefit tier",
"BenefitTierReferralDiscountFactor": "Referral discount factor",
"BenefitTierReferralDiscountFactorDescription": "The proportion of the referee's taker fees to be discounted",
"BenefitTierReferralRewardFactor": "Referral reward factor",
"BenefitTierReferralRewardFactorDescription": "The proportion of the referee's taker fees to be rewarded to the referrer",
"BenefitTierMinimumActivityStreak": "Minimum activity streak",
"BenefitTierMinimumActivityStreakDescription": "The minimum number of times the party needs to have completed the activity",
"BenefitTierMinimumQuantumBalance": "Minimum quantum balance",
"BenefitTierMinimumQuantumBalanceDescription": "The minimum amount of the vesting token to qualify",
"BenefitTierVestingMultiplier": "Vesting multiplier",
"BenefitTierVestingMultiplierDescription": "Vesting multiplier for the tier",
"BenefitTierRewardMultiplier": "Reward multiplier",
"BenefitTierRewardMultiplierDescription": "The multiplier",
"StakingTiers": "Staking tiers",
"StakingTierMinimumStakedTokens": "Minimum staked tokens",
"StakingTierMinimumStakedTokensDescription": "Required number of governance tokens ($VEGA) a referrer must have staked to receive the multiplier",
"StakingTierReferralRewardMultiplier": "Referral reward multiplier",
"StakingTierReferralRewardMultiplierDescription": "Multiplier applied to the referral reward factor when calculating referral rewards due to the referrer",
"WindowLength": "Window length",
"WindowLengthDescription": "Number of epochs over which to evaluate a referral set's running volume",
"EndOfProgramTimestamp": "End of program",
"EndOfProgramTimestampDescription": "Time after which when the current epoch ends, the programs will end and benefits will be disabled.",
"BenefitTierVolumeDiscountFactor": "Volume discount factor",
"BenefitTierVolumeDiscountFactorDescription": "Discount given to those in this benefit tier",
"ACCOUNT_TYPE_INSURANCE": "Insurance account",
"ACCOUNT_TYPE_GLOBAL_INSURANCE": "Global insurance account",
"ACCOUNT_TYPE_SETTLEMENT": "Settlement account",
"ACCOUNT_TYPE_MARGIN": "Margin account ",
"ACCOUNT_TYPE_GENERAL": "General account",
"ACCOUNT_TYPE_FEES_INFRASTRUCTURE": "Infrastructure fees account",
"ACCOUNT_TYPE_FEES_LIQUIDITY": "Liquidity fees account",
"ACCOUNT_TYPE_FEES_MAKER": "Maker fees account",
"ACCOUNT_TYPE_BOND": "Bond account",
"ACCOUNT_TYPE_EXTERNAL": "External account",
"ACCOUNT_TYPE_GLOBAL_REWARD": "Global reward account",
"ACCOUNT_TYPE_PENDING_TRANSFERS": "Pending transfers account",
"ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES": "Maker paid fees reward account",
"ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES": "Maker received fees reward account",
"ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES": "Liquidity provider received fees reward account",
"ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS": "Market proposers reward account",
"ACCOUNT_TYPE_HOLDING": "Holding account",
"ACCOUNT_TYPE_LP_LIQUIDITY_FEES": "Liquidity provider fees account",
"ACCOUNT_TYPE_NETWORK_TREASURY": "Network treasury account",
"ACCOUNT_TYPE_VESTING_REWARDS": "Vesting rewards account",
"ACCOUNT_TYPE_VESTED_REWARDS": "Vested rewards account",
"ACCOUNT_TYPE_REWARD_AVERAGE_POSITION": "Average position reward account",
"ACCOUNT_TYPE_REWARD_RELATIVE_RETURN": "Relative return reward account",
"ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY": "Return volatility reward account",
"ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING": "Validator ranking reward account",
"ACCOUNT_TYPE_PENDING_FEE_REFERRAL_REWARD": "Pending fee referral reward account"
} }
+18 -7
View File
@@ -12,7 +12,7 @@ import { useRefreshAfterEpoch } from '../../hooks/use-refresh-after-epoch';
import { ProposalsListItem } from '../proposals/components/proposals-list-item'; import { ProposalsListItem } from '../proposals/components/proposals-list-item';
import { ProtocolUpgradeProposalsListItem } from '../proposals/components/protocol-upgrade-proposals-list-item/protocol-upgrade-proposals-list-item'; import { ProtocolUpgradeProposalsListItem } from '../proposals/components/protocol-upgrade-proposals-list-item/protocol-upgrade-proposals-list-item';
import Routes from '../routes'; import Routes from '../routes';
import { ExternalLinks } from '@vegaprotocol/environment'; import { ExternalLinks, FLAGS } from '@vegaprotocol/environment';
import { removePaginationWrapper } from '@vegaprotocol/utils'; import { removePaginationWrapper } from '@vegaprotocol/utils';
import { useNodesQuery } from '../staking/home/__generated__/Nodes'; import { useNodesQuery } from '../staking/home/__generated__/Nodes';
import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals'; import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals';
@@ -23,7 +23,6 @@ import {
import { Heading, SubHeading } from '../../components/heading'; import { Heading, SubHeading } from '../../components/heading';
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
import type { RouteChildProps } from '..'; import type { RouteChildProps } from '..';
import type { ProposalFieldsFragment } from '../proposals/proposals/__generated__/Proposals';
import type { NodesFragmentFragment } from '../staking/home/__generated__/Nodes'; import type { NodesFragmentFragment } from '../staking/home/__generated__/Nodes';
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals'; import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
import { useProtocolUpgradeProposalsQuery } from '@vegaprotocol/proposals'; import { useProtocolUpgradeProposalsQuery } from '@vegaprotocol/proposals';
@@ -32,6 +31,7 @@ import {
orderByUpgradeBlockHeight, orderByUpgradeBlockHeight,
} from '../proposals/components/proposals-list/proposals-list'; } from '../proposals/components/proposals-list/proposals-list';
import { BigNumber } from '../../lib/bignumber'; import { BigNumber } from '../../lib/bignumber';
import type { ProposalQuery } from '../proposals/proposal/__generated__/Proposal';
const nodesToShow = 6; const nodesToShow = 6;
@@ -39,7 +39,7 @@ const HomeProposals = ({
proposals, proposals,
protocolUpgradeProposals, protocolUpgradeProposals,
}: { }: {
proposals: ProposalFieldsFragment[]; proposals: ProposalQuery['proposal'][];
protocolUpgradeProposals: ProtocolUpgradeProposalFieldsFragment[]; protocolUpgradeProposals: ProtocolUpgradeProposalFieldsFragment[];
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -60,9 +60,12 @@ const HomeProposals = ({
<ProtocolUpgradeProposalsListItem key={index} proposal={proposal} /> <ProtocolUpgradeProposalsListItem key={index} proposal={proposal} />
))} ))}
{proposals.map((proposal) => ( {proposals.map(
<ProposalsListItem key={proposal.id} proposal={proposal} /> (proposal) =>
))} proposal?.id && (
<ProposalsListItem key={proposal.id} proposal={proposal} />
)
)}
</ul> </ul>
<div className="mt-6"> <div className="mt-6">
@@ -182,6 +185,12 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
pollInterval: 5000, pollInterval: 5000,
fetchPolicy: 'network-only', fetchPolicy: 'network-only',
errorPolicy: 'ignore', errorPolicy: 'ignore',
variables: {
includeNewMarketProductFields: !!FLAGS.PRODUCT_PERPETUALS,
includeUpdateMarketStates: !!FLAGS.UPDATE_MARKET_STATE,
includeUpdateReferralPrograms: !!FLAGS.REFERRALS,
includeUpdateVolumeDiscountPrograms: !!FLAGS.VOLUME_DISCOUNTS,
},
}); });
const { const {
@@ -206,7 +215,9 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
const proposals = useMemo( const proposals = useMemo(
() => () =>
proposalsData proposalsData
? getNotRejectedProposals(proposalsData.proposalsConnection) ? getNotRejectedProposals(
removePaginationWrapper(proposalsData.proposalsConnection?.edges)
)
: [], : [],
[proposalsData] [proposalsData]
); );
@@ -12,18 +12,19 @@ import {
generateProposal, generateProposal,
generateYesVotes, generateYesVotes,
} from '../../test-helpers/generate-proposals'; } from '../../test-helpers/generate-proposals';
import { ProposalHeader } from './proposal-header'; import { ProposalHeader, NewTransferSummary } from './proposal-header';
import { import {
lastWeek, lastWeek,
nextWeek, nextWeek,
mockWalletContext, mockWalletContext,
createUserVoteQueryMock, createUserVoteQueryMock,
} from '../../test-helpers/mocks'; } from '../../test-helpers/mocks';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import type { MockedResponse } from '@apollo/client/testing';
import { FLAGS } from '@vegaprotocol/environment'; import { FLAGS } from '@vegaprotocol/environment';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import { VoteState } from '../vote-details/use-user-vote'; import { VoteState } from '../vote-details/use-user-vote';
import { useNewTransferProposalDetails } from '@vegaprotocol/proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import type { MockedResponse } from '@apollo/client/testing';
jest.mock('@vegaprotocol/proposals', () => ({ jest.mock('@vegaprotocol/proposals', () => ({
...jest.requireActual('@vegaprotocol/proposals'), ...jest.requireActual('@vegaprotocol/proposals'),
@@ -31,6 +32,7 @@ jest.mock('@vegaprotocol/proposals', () => ({
code: 'PARENT_CODE', code: 'PARENT_CODE',
parentMarketId: 'PARENT_ID', parentMarketId: 'PARENT_ID',
}), }),
useNewTransferProposalDetails: jest.fn(),
})); }));
const renderComponent = ( const renderComponent = (
@@ -418,3 +420,78 @@ describe('Proposal header', () => {
expect(await screen.findByTestId('user-voted-yes')).toBeInTheDocument(); expect(await screen.findByTestId('user-voted-yes')).toBeInTheDocument();
}); });
}); });
jest.mock('@vegaprotocol/proposals');
describe('<NewTransferSummary />', () => {
it('renders null if no details are provided', () => {
(useNewTransferProposalDetails as jest.Mock).mockReturnValue(null);
const { container } = render(<NewTransferSummary proposalId="1" />);
expect(container.firstChild).toBeNull();
});
it('handles OneOffGovernanceTransfer', () => {
(useNewTransferProposalDetails as jest.Mock).mockReturnValue({
kind: { __typename: 'OneOffGovernanceTransfer', deliverOn: null },
source: '0x123',
sourceType: 'wallet',
destination: '0x456',
destinationType: 'contract',
});
const { getByText } = render(<NewTransferSummary proposalId="1" />);
const textMatch = (content: string) => content.includes('One off transfer');
expect(getByText(textMatch)).toBeInTheDocument();
});
it('handles RecurringGovernanceTransfer', () => {
(useNewTransferProposalDetails as jest.Mock).mockReturnValue({
kind: {
__typename: 'RecurringGovernanceTransfer',
startEpoch: 1,
endEpoch: 5,
},
source: '0x123',
sourceType: 'wallet',
destination: '0x456',
destinationType: 'contract',
});
const { getByText } = render(<NewTransferSummary proposalId="1" />);
const textMatch = (content: string) =>
content.includes('Recurring transfer');
expect(getByText(textMatch)).toBeInTheDocument();
});
it('should fallback to translated sourceType when source is not set', () => {
(useNewTransferProposalDetails as jest.Mock).mockReturnValue({
kind: {
__typename: 'RecurringGovernanceTransfer',
startEpoch: 1,
endEpoch: 5,
},
source: undefined,
sourceType: 'ACCOUNT_TYPE_GENERAL',
destination: '0x456',
destinationType: 'ACCOUNT_TYPE_GENERAL',
});
render(<NewTransferSummary proposalId="1" />);
expect(screen.getByText('General account')).toBeInTheDocument();
});
it('should fallback to translated destinationType when destination is not set', () => {
(useNewTransferProposalDetails as jest.Mock).mockReturnValue({
kind: {
__typename: 'RecurringGovernanceTransfer',
startEpoch: 1,
endEpoch: 5,
},
source: '0x123',
sourceType: 'ACCOUNT_TYPE_GENERAL',
destination: undefined,
destinationType: 'ACCOUNT_TYPE_GLOBAL_INSURANCE',
});
render(<NewTransferSummary proposalId="1" />);
expect(screen.getByText('Global insurance account')).toBeInTheDocument();
});
});
@@ -3,24 +3,28 @@ import { Lozenge, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
import { shorten } from '@vegaprotocol/utils'; import { shorten } from '@vegaprotocol/utils';
import { Heading, SubHeading } from '../../../../components/heading'; import { Heading, SubHeading } from '../../../../components/heading';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal'; import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import { truncateMiddle } from '../../../../lib/truncate-middle'; import { truncateMiddle } from '../../../../lib/truncate-middle';
import { CurrentProposalState } from '../current-proposal-state'; import { CurrentProposalState } from '../current-proposal-state';
import { ProposalInfoLabel } from '../proposal-info-label'; import { ProposalInfoLabel } from '../proposal-info-label';
import { useSuccessorMarketProposalDetails } from '@vegaprotocol/proposals'; import {
useCancelTransferProposalDetails,
useNewTransferProposalDetails,
useSuccessorMarketProposalDetails,
} from '@vegaprotocol/proposals';
import { FLAGS } from '@vegaprotocol/environment'; import { FLAGS } from '@vegaprotocol/environment';
import Routes from '../../../routes'; import Routes from '../../../routes';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import type { VoteState } from '../vote-details/use-user-vote'; import type { VoteState } from '../vote-details/use-user-vote';
import { VoteBreakdown } from '../vote-breakdown'; import { VoteBreakdown } from '../vote-breakdown';
import { GovernanceTransferKindMapping } from '@vegaprotocol/types';
export const ProposalHeader = ({ export const ProposalHeader = ({
proposal, proposal,
isListItem = true, isListItem = true,
voteState, voteState,
}: { }: {
proposal: ProposalFieldsFragment | ProposalQuery['proposal']; proposal: ProposalQuery['proposal'];
isListItem?: boolean; isListItem?: boolean;
voteState?: VoteState | null; voteState?: VoteState | null;
}) => { }) => {
@@ -37,7 +41,10 @@ export const ProposalHeader = ({
switch (change?.__typename) { switch (change?.__typename) {
case 'NewMarket': { case 'NewMarket': {
proposalType = 'NewMarket'; proposalType =
FLAGS.PRODUCT_PERPETUALS && change?.instrument?.product?.__typename
? `NewMarket${change?.instrument?.product?.__typename}`
: 'NewMarket';
fallbackTitle = t('NewMarketProposal'); fallbackTitle = t('NewMarketProposal');
details = ( details = (
<> <>
@@ -61,17 +68,46 @@ export const ProposalHeader = ({
); );
break; break;
} }
case 'UpdateMarketState': {
proposalType =
FLAGS.UPDATE_MARKET_STATE && change?.updateType
? t(change.updateType)
: 'UpdateMarketState';
fallbackTitle = t('UpdateMarketStateProposal');
details = (
<span>
{FLAGS.UPDATE_MARKET_STATE &&
change?.market?.id &&
change.updateType ? (
<>
{t(change.updateType)}: {truncateMiddle(change.market.id)}
</>
) : null}
</span>
);
break;
}
case 'UpdateMarket': { case 'UpdateMarket': {
proposalType = 'UpdateMarket'; proposalType = 'UpdateMarket';
fallbackTitle = t('UpdateMarketProposal'); fallbackTitle = t('UpdateMarketProposal');
details = ( details = (
<> <>
<span>{t('Market change')}:</span>{' '} <span>{t('MarketChange')}:</span>{' '}
<span>{truncateMiddle(change.marketId)}</span> <span>{truncateMiddle(change.marketId)}</span>
</> </>
); );
break; break;
} }
case 'UpdateReferralProgram': {
proposalType = 'UpdateReferralProgram';
fallbackTitle = t('UpdateReferralProgramProposal');
break;
}
case 'UpdateVolumeDiscountProgram': {
proposalType = 'UpdateVolumeDiscountProgram';
fallbackTitle = t('UpdateVolumeDiscountProgramProposal');
break;
}
case 'NewAsset': { case 'NewAsset': {
proposalType = 'NewAsset'; proposalType = 'NewAsset';
fallbackTitle = t('NewAssetProposal'); fallbackTitle = t('NewAssetProposal');
@@ -126,6 +162,20 @@ export const ProposalHeader = ({
); );
break; break;
} }
case 'NewTransfer':
proposalType = 'NewTransfer';
fallbackTitle = t('NewTransferProposal');
details = FLAGS.GOVERNANCE_TRANSFERS ? (
<NewTransferSummary proposalId={proposal?.id} />
) : null;
break;
case 'CancelTransfer':
proposalType = 'CancelTransfer';
fallbackTitle = t('CancelTransferProposal');
details = FLAGS.GOVERNANCE_TRANSFERS ? (
<CancelTransferSummary proposalId={proposal?.id} />
) : null;
break;
} }
return ( return (
@@ -187,7 +237,11 @@ export const ProposalHeader = ({
); );
}; };
const SuccessorCode = ({ proposalId }: { proposalId?: string | null }) => { export const SuccessorCode = ({
proposalId,
}: {
proposalId?: string | null;
}) => {
const { t } = useTranslation(); const { t } = useTranslation();
const successor = useSuccessorMarketProposalDetails(proposalId); const successor = useSuccessorMarketProposalDetails(proposalId);
@@ -203,3 +257,50 @@ const SuccessorCode = ({ proposalId }: { proposalId?: string | null }) => {
</span> </span>
) : null; ) : null;
}; };
export const NewTransferSummary = ({
proposalId,
}: {
proposalId?: string | null;
}) => {
const { t } = useTranslation();
const details = useNewTransferProposalDetails(proposalId);
if (!details) return null;
return (
<span>
{GovernanceTransferKindMapping[details.kind.__typename]}{' '}
{t('transfer from')}{' '}
<Lozenge>
{details.source
? truncateMiddle(details.source)
: t(details.sourceType)}
</Lozenge>{' '}
{t('to')}{' '}
<Lozenge>
{details.destination
? truncateMiddle(details.destination)
: t(details.destinationType)}
</Lozenge>
</span>
);
};
export const CancelTransferSummary = ({
proposalId,
}: {
proposalId?: string | null;
}) => {
const { t } = useTranslation();
const details = useCancelTransferProposalDetails(proposalId);
if (!details) return null;
return (
<span>
{t('Cancel transfer: ')}{' '}
<Lozenge>{truncateMiddle(details.transferId)}</Lozenge>
</span>
);
};
@@ -6,13 +6,18 @@ import {
KeyDetailsInfoPanel, KeyDetailsInfoPanel,
LiquidityMonitoringParametersInfoPanel, LiquidityMonitoringParametersInfoPanel,
LiquidityPriceRangeInfoPanel, LiquidityPriceRangeInfoPanel,
LiquiditySLAParametersInfoPanel,
MetadataInfoPanel, MetadataInfoPanel,
OracleInfoPanel, OracleInfoPanel,
PriceMonitoringBoundsInfoPanel, PriceMonitoringBoundsInfoPanel,
RiskFactorsInfoPanel, RiskFactorsInfoPanel,
RiskModelInfoPanel, RiskModelInfoPanel,
RiskParametersInfoPanel,
SettlementAssetInfoPanel, SettlementAssetInfoPanel,
getDataSourceSpecForSettlementSchedule,
getDataSourceSpecForSettlementData,
getDataSourceSpecForTradingTermination,
getSigners,
MarginScalingFactorsPanel,
} from '@vegaprotocol/markets'; } from '@vegaprotocol/markets';
import { import {
Button, Button,
@@ -24,7 +29,6 @@ import {
import { SubHeading } from '../../../../components/heading'; import { SubHeading } from '../../../../components/heading';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle'; import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
import type { MarketInfo } from '@vegaprotocol/markets'; import type { MarketInfo } from '@vegaprotocol/markets';
import type { DataSourceDefinition } from '@vegaprotocol/types';
import { create } from 'zustand'; import { create } from 'zustand';
type MarketDataDialogState = { type MarketDataDialogState = {
@@ -59,20 +63,31 @@ export const ProposalMarketData = ({
return null; return null;
} }
const settlementData = marketData.tradableInstrument.instrument.product const { product } = marketData.tradableInstrument.instrument;
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
const settlementData = getDataSourceSpecForSettlementData(product);
const settlementScheduleData =
getDataSourceSpecForSettlementSchedule(product);
const terminationData = getDataSourceSpecForTradingTermination(product);
const parentProduct = parentMarketData?.tradableInstrument.instrument.product;
const parentSettlementData = const parentSettlementData =
parentMarketData?.tradableInstrument.instrument?.product parentProduct && getDataSourceSpecForSettlementData(parentProduct);
?.dataSourceSpecForSettlementData?.data; const parentSettlementScheduleData =
const terminationData = marketData.tradableInstrument.instrument.product parentProduct && getDataSourceSpecForSettlementSchedule(parentProduct);
.dataSourceSpecForTradingTermination.data as DataSourceDefinition;
const parentTerminationData = const parentTerminationData =
parentMarketData?.tradableInstrument.instrument?.product parentProduct && getDataSourceSpecForTradingTermination(parentProduct);
?.dataSourceSpecForTradingTermination?.data;
// TODO add settlementScheduleData for Perp Proposal
const isParentSettlementDataEqual = const isParentSettlementDataEqual =
parentSettlementData !== undefined && parentSettlementData !== undefined &&
isEqual(settlementData, parentSettlementData); isEqual(settlementData, parentSettlementData);
const isParentSettlementScheduleDataEqual =
parentSettlementData !== undefined &&
isEqual(settlementScheduleData, parentSettlementScheduleData);
const isParentTerminationDataEqual = const isParentTerminationDataEqual =
parentTerminationData !== undefined && parentTerminationData !== undefined &&
isEqual(terminationData, parentTerminationData); isEqual(terminationData, parentTerminationData);
@@ -85,20 +100,6 @@ export const ProposalMarketData = ({
parentMarketData?.priceMonitoringSettings?.parameters?.triggers parentMarketData?.priceMonitoringSettings?.parameters?.triggers
); );
const getSigners = (data: DataSourceDefinition) => {
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
const signers = data.sourceType.sourceType.signers || [];
return signers.map(({ signer }) => {
return (
(signer.__typename === 'ETHAddress' && signer.address) ||
(signer.__typename === 'PubKey' && signer.key)
);
});
}
return [];
};
return ( return (
<section className="relative" data-testid="proposal-market-data"> <section className="relative" data-testid="proposal-market-data">
<CollapsibleToggle <CollapsibleToggle
@@ -129,10 +130,9 @@ export const ProposalMarketData = ({
parentMarket={parentMarketData} parentMarket={parentMarketData}
/> />
{isEqual( {settlementData &&
getSigners(settlementData), terminationData &&
getSigners(terminationData) isEqual(getSigners(settlementData), getSigners(terminationData)) ? (
) ? (
<> <>
<h2 className={marketDataHeaderStyles}>{t('Oracle')}</h2> <h2 className={marketDataHeaderStyles}>{t('Oracle')}</h2>
@@ -140,14 +140,17 @@ export const ProposalMarketData = ({
market={marketData} market={marketData}
type="settlementData" type="settlementData"
parentMarket={ parentMarket={
isParentSettlementDataEqual ? undefined : parentMarketData isParentSettlementDataEqual ||
isParentSettlementScheduleDataEqual
? undefined
: parentMarketData
} }
/> />
</> </>
) : ( ) : (
<> <>
<h2 className={marketDataHeaderStyles}> <h2 className={marketDataHeaderStyles}>
{t('Settlement Oracle')} {t('Settlement oracle')}
</h2> </h2>
<OracleInfoPanel <OracleInfoPanel
market={marketData} market={marketData}
@@ -157,16 +160,41 @@ export const ProposalMarketData = ({
} }
/> />
<h2 className={marketDataHeaderStyles}> {marketData.tradableInstrument.instrument.product.__typename ===
{t('Termination Oracle')} 'Future' && (
</h2> <div>
<OracleInfoPanel <h2 className={marketDataHeaderStyles}>
market={marketData} {t('Termination oracle')}
type="termination" </h2>
parentMarket={ <OracleInfoPanel
isParentTerminationDataEqual ? undefined : parentMarketData market={marketData}
} type="termination"
/> parentMarket={
isParentTerminationDataEqual
? undefined
: parentMarketData
}
/>
</div>
)}
{marketData.tradableInstrument.instrument.product.__typename ===
'Perpetual' && (
<div>
<h2 className={marketDataHeaderStyles}>
{t('Settlement schedule oracle')}
</h2>
<OracleInfoPanel
market={marketData}
type="settlementSchedule"
parentMarket={
isParentSettlementScheduleDataEqual
? undefined
: parentMarketData
}
/>
</div>
)}
</> </>
)} )}
@@ -191,8 +219,10 @@ export const ProposalMarketData = ({
parentMarket={parentMarketData} parentMarket={parentMarketData}
/> />
<h2 className={marketDataHeaderStyles}>{t('Risk parameters')}</h2> <h2 className={marketDataHeaderStyles}>
<RiskParametersInfoPanel {t('Margin scaling factors')}
</h2>
<MarginScalingFactorsPanel
market={marketData} market={marketData}
parentMarket={parentMarketData} parentMarket={parentMarketData}
/> />
@@ -244,7 +274,6 @@ export const ProposalMarketData = ({
market={marketData} market={marketData}
parentMarket={parentMarketData} parentMarket={parentMarketData}
/> />
<h2 className={marketDataHeaderStyles}> <h2 className={marketDataHeaderStyles}>
{t('Liquidity price range')} {t('Liquidity price range')}
</h2> </h2>
@@ -252,6 +281,14 @@ export const ProposalMarketData = ({
market={marketData} market={marketData}
parentMarket={parentMarketData} parentMarket={parentMarketData}
/> />
<h2 className={marketDataHeaderStyles}>
{t('Liquidity SLA protocol')}
</h2>
<LiquiditySLAParametersInfoPanel
market={marketData}
parentMarket={parentMarketData}
/>
</div> </div>
</> </>
)} )}
@@ -0,0 +1 @@
export * from './proposal-referral-program-details';
@@ -0,0 +1,156 @@
import { render, screen } from '@testing-library/react';
import {
formatMinimumRunningNotionalTakerVolume,
formatReferralDiscountFactor,
formatReferralRewardFactor,
formatMinimumStakedTokens,
formatReferralRewardMultiplier,
ProposalReferralProgramDetails,
} from './proposal-referral-program-details';
import { generateProposal } from '../../test-helpers/generate-proposals';
jest.mock('../../../../contexts/app-state/app-state-context', () => ({
useAppState: () => ({
appState: {
decimals: 2,
},
}),
}));
beforeEach(() => {
jest.useFakeTimers();
jest.setSystemTime(0);
});
afterEach(() => {
jest.useRealTimers();
});
describe('ProposalReferralProgramDetails helper functions', () => {
it('should format minimum running notional taker volume correctly', () => {
const input = '1000';
const formatted = formatMinimumRunningNotionalTakerVolume(input);
expect(formatted).toBe('1,000');
});
it('should format referral discount factor correctly', () => {
const input = '0.05';
const formatted = formatReferralDiscountFactor(input);
expect(formatted).toBe('5%');
});
it('should format referral reward factor correctly', () => {
const input = '0.1';
const formatted = formatReferralRewardFactor(input);
expect(formatted).toBe('10%');
});
it('should format minimum staked tokens correctly', () => {
const input = '15';
const decimals = 18;
const formatted = formatMinimumStakedTokens(input, decimals);
expect(formatted).toBe('0.000000000000000015');
});
it('should format referral reward multiplier correctly', () => {
const input = '3';
const formatted = formatReferralRewardMultiplier(input);
expect(formatted).toBe('3x');
});
});
const mockReferralProposal = generateProposal({
terms: {
change: {
__typename: 'UpdateReferralProgram',
benefitTiers: [
{
minimumEpochs: 6,
minimumRunningNotionalTakerVolume: '10000',
referralDiscountFactor: '0.001',
referralRewardFactor: '0.001',
},
{
minimumEpochs: 24,
minimumRunningNotionalTakerVolume: '500000',
referralDiscountFactor: '0.005',
referralRewardFactor: '0.005',
},
{
minimumEpochs: 48,
minimumRunningNotionalTakerVolume: '1000000',
referralDiscountFactor: '0.01',
referralRewardFactor: '0.01',
},
],
endOfProgram: '2026-10-03T10:34:34Z',
windowLength: 3,
stakingTiers: [
{
minimumStakedTokens: '1',
referralRewardMultiplier: '1',
},
{
minimumStakedTokens: '2',
referralRewardMultiplier: '2',
},
{
minimumStakedTokens: '5',
referralRewardMultiplier: '3',
},
],
},
},
});
describe('<ProposalReferralProgramDetails />', () => {
it('should not render if proposal is null', () => {
render(<ProposalReferralProgramDetails proposal={null} />);
expect(
screen.queryByTestId('proposal-referral-program-details')
).toBeNull();
});
it('should not render if __typename is not UpdateReferralProgram', () => {
const updateMarketProposal = generateProposal({
terms: {
change: {
__typename: 'UpdateMarket',
},
},
});
render(<ProposalReferralProgramDetails proposal={updateMarketProposal} />);
expect(
screen.queryByTestId('proposal-referral-program-details')
).toBeNull();
});
it('should not render if there are no relevant fields', () => {
const incompleteProposal = generateProposal({
terms: {
change: {},
},
});
render(<ProposalReferralProgramDetails proposal={incompleteProposal} />);
expect(
screen.queryByTestId('proposal-referral-program-details')
).toBeNull();
});
it('should render relevant fields if present', () => {
render(<ProposalReferralProgramDetails proposal={mockReferralProposal} />);
expect(
screen.getByTestId('proposal-referral-program-window-length')
).toBeInTheDocument();
expect(
screen.getByTestId('proposal-referral-program-end-of-program-timestamp')
).toBeInTheDocument();
expect(
screen.getByTestId('proposal-referral-program-benefit-tiers')
).toBeInTheDocument();
expect(
screen.getByTestId('proposal-referral-program-benefit-tiers')
).toBeInTheDocument();
});
});
@@ -0,0 +1,232 @@
import { useTranslation } from 'react-i18next';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import {
KeyValueTable,
KeyValueTableRow,
RoundedWrapper,
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import { formatNumber } from '../../../../lib/format-number';
import {
formatDateWithLocalTimezone,
formatNumberPercentage,
toBigNum,
} from '@vegaprotocol/utils';
import BigNumber from 'bignumber.js';
import { useAppState } from '../../../../contexts/app-state/app-state-context';
interface ProposalReferralProgramDetailsProps {
proposal: ProposalQuery['proposal'];
}
export const formatEndOfProgramTimestamp = (value: string) => {
return formatDateWithLocalTimezone(new Date(value));
};
export const formatMinimumRunningNotionalTakerVolume = (value: string) => {
return formatNumber(toBigNum(value, 0), 0);
};
export const formatReferralDiscountFactor = (value: string) => {
return formatNumberPercentage(new BigNumber(value).times(100));
};
export const formatReferralRewardFactor = (value: string) => {
return formatNumberPercentage(new BigNumber(value).times(100));
};
export const formatMinimumStakedTokens = (value: string, decimals: number) => {
return formatNumber(toBigNum(value, decimals));
};
export const formatReferralRewardMultiplier = (value: string) => {
return `${value}x`;
};
export const ProposalReferralProgramDetails = ({
proposal,
}: ProposalReferralProgramDetailsProps) => {
const {
appState: { decimals },
} = useAppState();
const { t } = useTranslation();
if (proposal?.terms?.change?.__typename !== 'UpdateReferralProgram') {
return null;
}
const benefitTiers = proposal?.terms?.change?.benefitTiers;
const stakingTiers = proposal?.terms?.change?.stakingTiers;
const windowLength = proposal?.terms?.change?.windowLength;
const endOfProgramTimestamp = proposal?.terms?.change?.endOfProgram;
if (
!benefitTiers &&
!stakingTiers &&
!windowLength &&
!endOfProgramTimestamp
) {
return null;
}
return (
<div data-testid="proposal-referral-program-details">
<RoundedWrapper paddingBottom={true}>
{windowLength && (
<div data-testid="proposal-referral-program-window-length">
<KeyValueTable>
<KeyValueTableRow>
<Tooltip description={t('WindowLengthDescription')}>
<span>{t('WindowLength')}</span>
</Tooltip>
{windowLength}
</KeyValueTableRow>
</KeyValueTable>
</div>
)}
{endOfProgramTimestamp && (
<div
className="mb-6"
data-testid="proposal-referral-program-end-of-program-timestamp"
>
<KeyValueTable>
<KeyValueTableRow>
<Tooltip description={t('EndOfProgramTimestampDescription')}>
<span>{t('EndOfProgramTimestamp')}</span>
</Tooltip>
{formatEndOfProgramTimestamp(endOfProgramTimestamp)}
</KeyValueTableRow>
</KeyValueTable>
</div>
)}
{benefitTiers && (
<div
className="mb-6"
data-testid="proposal-referral-program-benefit-tiers"
>
<h3 className="mb-3 uppercase font-semibold text-lg">
{t('BenefitTiers')}
</h3>
<KeyValueTable>
{benefitTiers
.sort((a, b) => a.minimumEpochs - b.minimumEpochs)
.map((benefitTier, index) => (
<div className="mb-4" key={index}>
<h4 className="font-semibold uppercase">
Tier {index + 1}
</h4>
{benefitTier.minimumEpochs && (
<KeyValueTableRow>
<Tooltip
description={t('BenefitTierMinimumEpochsDescription')}
>
<span>{t('BenefitTierMinimumEpochs')}</span>
</Tooltip>
{benefitTier.minimumEpochs}
</KeyValueTableRow>
)}
{benefitTier.minimumRunningNotionalTakerVolume && (
<KeyValueTableRow>
<Tooltip
description={t(
'BenefitTierMinimumRunningNotionalTakerVolumeDescription'
)}
>
<span>
{t('BenefitTierMinimumRunningNotionalTakerVolume')}
</span>
</Tooltip>
{formatMinimumRunningNotionalTakerVolume(
benefitTier.minimumRunningNotionalTakerVolume
)}
</KeyValueTableRow>
)}
{benefitTier.referralDiscountFactor && (
<KeyValueTableRow>
<Tooltip
description={t(
'BenefitTierReferralDiscountFactorDescription'
)}
>
<span>{t('BenefitTierReferralDiscountFactor')}</span>
</Tooltip>
{formatReferralDiscountFactor(
benefitTier.referralDiscountFactor
)}
</KeyValueTableRow>
)}
{benefitTier.referralRewardFactor && (
<KeyValueTableRow>
<Tooltip
description={t(
'BenefitTierReferralRewardFactorDescription'
)}
>
<span>{t('BenefitTierReferralRewardFactor')}</span>
</Tooltip>
{formatReferralRewardFactor(
benefitTier.referralRewardFactor
)}
</KeyValueTableRow>
)}
</div>
))}
</KeyValueTable>
</div>
)}
{stakingTiers && (
<div data-testid="proposal-referral-program-staking-tiers">
<h3 className="mb-3 uppercase font-semibold text-lg">
{t('StakingTiers')}
</h3>
<KeyValueTable>
{stakingTiers
.sort(
(a, b) =>
Number(a.minimumStakedTokens) -
Number(b.minimumStakedTokens)
)
.map((stakingTier, index) => (
<div className="mb-4" key={index}>
{stakingTier.referralRewardMultiplier && (
<KeyValueTableRow>
<Tooltip
description={t(
'StakingTierReferralRewardMultiplierDescription'
)}
>
<span>
{t('StakingTierReferralRewardMultiplier')}
</span>
</Tooltip>
{formatReferralRewardMultiplier(
stakingTier.referralRewardMultiplier
)}
</KeyValueTableRow>
)}
{stakingTier.minimumStakedTokens && (
<KeyValueTableRow>
<Tooltip
description={t(
'StakingTierMinimumStakedTokensFactorDescription'
)}
>
<span>{t('StakingTierMinimumStakedTokens')}</span>
</Tooltip>
{formatMinimumStakedTokens(
stakingTier.minimumStakedTokens,
decimals
)}
</KeyValueTableRow>
)}
</div>
))}
</KeyValueTable>
</div>
)}
</RoundedWrapper>
</div>
);
};
@@ -0,0 +1,2 @@
export * from './proposal-transfer-details';
export * from './proposal-cancel-transfer-details';
@@ -0,0 +1,37 @@
import { useTranslation } from 'react-i18next';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import { useCancelTransferProposalDetails } from '@vegaprotocol/proposals';
import {
KeyValueTable,
KeyValueTableRow,
RoundedWrapper,
} from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
export const ProposalCancelTransferDetails = ({
proposal,
}: {
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
}) => {
const { t } = useTranslation();
const details = useCancelTransferProposalDetails(proposal?.id);
if (!details) {
return null;
}
return (
<>
<SubHeading title={t('proposalCancelTransferDetails')} />
<RoundedWrapper paddingBottom={true}>
<KeyValueTable data-testid="proposal-cancel-transfer-details-table">
<KeyValueTableRow noBorder={true}>
{t('transferId')}
{details.transferId}
</KeyValueTableRow>
</KeyValueTable>
</RoundedWrapper>
</>
);
};
@@ -0,0 +1,145 @@
import { useState } from 'react';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
import { SubHeading } from '../../../../components/heading';
import { useTranslation } from 'react-i18next';
import {
KeyValueTable,
KeyValueTableRow,
RoundedWrapper,
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import { useNewTransferProposalDetails } from '@vegaprotocol/proposals';
import {
AccountTypeMapping,
DescriptionGovernanceTransferTypeMapping,
GovernanceTransferKindMapping,
GovernanceTransferTypeMapping,
} from '@vegaprotocol/types';
import {
addDecimalsFormatNumberQuantum,
formatDateWithLocalTimezone,
} from '@vegaprotocol/utils';
export const ProposalTransferDetails = ({
proposal,
}: {
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
}) => {
const { t } = useTranslation();
const [show, setShow] = useState(false);
const details = useNewTransferProposalDetails(proposal?.id);
if (!details) {
return null;
}
return (
<>
<CollapsibleToggle
toggleState={show}
setToggleState={setShow}
dataTestId="proposal-transfer-details"
>
<SubHeading title={t('proposalTransferDetails')} />
</CollapsibleToggle>
{show && (
<RoundedWrapper paddingBottom={true}>
<KeyValueTable data-testid="proposal-transfer-details-table">
{/* The source account */}
<KeyValueTableRow>
{t('Source')}
{details.source}
</KeyValueTableRow>
{/* The type of source account */}
<KeyValueTableRow>
{t('Source Type')}
{AccountTypeMapping[details.sourceType]}
</KeyValueTableRow>
{/* The destination account */}
<KeyValueTableRow>
{t('Destination')}
{details.destination}
</KeyValueTableRow>
{/* The type of destination account */}
<KeyValueTableRow>
{t('Destination Type')}
{AccountTypeMapping[details.destinationType]}
</KeyValueTableRow>
{/* The asset to transfer */}
<KeyValueTableRow>
{t('Asset')}
{details.asset.symbol}
</KeyValueTableRow>
{/*The fraction of the balance to be transfer */}
<KeyValueTableRow>
{t('Fraction Of Balance')}
{`${Number(details.fraction_of_balance) * 100}%`}
</KeyValueTableRow>
{/* The maximum amount to be transferred */}
<KeyValueTableRow>
{t('Amount')}
{addDecimalsFormatNumberQuantum(
details.amount,
details.asset.decimals,
details.asset.quantum
)}
</KeyValueTableRow>
{/* The type of the governance transfer */}
<KeyValueTableRow>
{t('Transfer Type')}
<Tooltip
description={
DescriptionGovernanceTransferTypeMapping[details.transferType]
}
>
<span>
{GovernanceTransferTypeMapping[details.transferType]}
</span>
</Tooltip>
</KeyValueTableRow>
{/* The type of governance transfer being made, i.e. a one-off or recurring trans */}
<KeyValueTableRow>
{t('Kind')}
{GovernanceTransferKindMapping[details.kind.__typename]}
</KeyValueTableRow>
{details.kind.__typename === 'OneOffGovernanceTransfer' &&
details.kind.deliverOn && (
<KeyValueTableRow noBorder={true}>
{t('Deliver On')}
{formatDateWithLocalTimezone(
new Date(details.kind.deliverOn)
)}
</KeyValueTableRow>
)}
{details.kind.__typename === 'RecurringGovernanceTransfer' && (
<>
<KeyValueTableRow noBorder={!details.kind.endEpoch}>
{t('Start On')}
<span>{details.kind.startEpoch}</span>
</KeyValueTableRow>
{details.kind.endEpoch && (
<KeyValueTableRow noBorder={true}>
{t('End on')}
{details.kind.endEpoch}
</KeyValueTableRow>
)}
</>
)}
</KeyValueTable>
</RoundedWrapper>
)}
</>
);
};
@@ -0,0 +1 @@
export * from './proposal-update-benefit-tiers-details';
@@ -0,0 +1,158 @@
import { render, screen } from '@testing-library/react';
import { ProposalUpdateBenefitTiers } from './proposal-update-benefit-tiers-details';
import { generateProposal } from '../../test-helpers/generate-proposals';
jest.mock('../../../../contexts/app-state/app-state-context', () => ({
useAppState: () => ({
appState: {
decimals: 2,
},
}),
}));
const mockVestingBenefitTierProposal = generateProposal({
terms: {
change: {
__typename: 'UpdateNetworkParameter',
networkParameter: {
key: 'blah.blah.benefitTiers',
value: JSON.stringify({
tiers: [
{
minimum_quantum_balance: '10000',
reward_multiplier: '0.05',
},
{
minimum_quantum_balance: '500000000000',
reward_multiplier: '0.1',
},
{
minimum_quantum_balance: '10000000000000',
reward_multiplier: '10',
},
],
}),
},
},
},
});
const mockActivityStreakBenefitTierProposal = generateProposal({
terms: {
change: {
__typename: 'UpdateNetworkParameter',
networkParameter: {
key: 'blah.blah.benefitTiers',
value: JSON.stringify({
tiers: [
{
minimum_activity_streak: '10000',
vesting_multiplier: '5',
reward_multiplier: '0.1',
},
{
minimum_activity_streak: '10000000000000',
vesting_multiplier: '100',
reward_multiplier: '10',
},
],
}),
},
},
},
});
describe('ProposalUpdateBenefitTiers', () => {
it('should not render if proposal is null', () => {
render(<ProposalUpdateBenefitTiers proposal={null} />);
expect(screen.queryByTestId('proposal-update-benefit-tiers')).toBeNull();
});
it('should not render if __typename is not UpdateNetworkParameter', () => {
const updateMarketProposal = generateProposal({
terms: {
change: {
__typename: 'UpdateMarket',
},
},
});
render(<ProposalUpdateBenefitTiers proposal={updateMarketProposal} />);
expect(screen.queryByTestId('proposal-update-benefit-tiers')).toBeNull();
});
it('should not render if there are no relevant fields', () => {
const incompleteProposal = generateProposal({
terms: {
change: {
__typename: 'UpdateNetworkParameter',
},
},
});
render(<ProposalUpdateBenefitTiers proposal={incompleteProposal} />);
expect(screen.queryByTestId('proposal-update-benefit-tiers')).toBeNull();
});
it('should not render if there are relevant fields that are empty', () => {
const incompleteProposal = generateProposal({
terms: {
change: {
__typename: 'UpdateNetworkParameter',
networkParameter: {
key: 'blah.blah.benefitTiers',
value: JSON.stringify({}),
},
},
},
});
render(<ProposalUpdateBenefitTiers proposal={incompleteProposal} />);
expect(screen.queryByTestId('proposal-update-benefit-tiers')).toBeNull();
});
it('should render a valid vesting benefit tier proposal', () => {
render(
<ProposalUpdateBenefitTiers proposal={mockVestingBenefitTierProposal} />
);
// 3 tiers in the sample data
expect(screen.getByText('Tier 1')).toBeInTheDocument();
expect(screen.getByText('Tier 2')).toBeInTheDocument();
expect(screen.getByText('Tier 3')).toBeInTheDocument();
expect(screen.getAllByText('Minimum quantum balance').length).toBe(3);
expect(screen.getAllByText('Reward multiplier').length).toBe(3);
expect(screen.getByText('0.00000000000001')).toBeInTheDocument();
expect(screen.getByText('0.05x')).toBeInTheDocument();
expect(screen.getByText('0.0000005')).toBeInTheDocument();
expect(screen.getByText('0.1x')).toBeInTheDocument();
expect(screen.getByText('0.00001')).toBeInTheDocument();
expect(screen.getByText('10x')).toBeInTheDocument();
});
it('should render a valid activity streak benefit tier proposal', () => {
render(
<ProposalUpdateBenefitTiers
proposal={mockActivityStreakBenefitTierProposal}
/>
);
// 3 tiers in the sample data
expect(screen.getByText('Tier 1')).toBeInTheDocument();
expect(screen.getByText('Tier 2')).toBeInTheDocument();
expect(screen.getAllByText('Minimum activity streak').length).toBe(2);
expect(screen.getAllByText('Vesting multiplier').length).toBe(2);
expect(screen.getAllByText('Reward multiplier').length).toBe(2);
expect(screen.getByText('10000')).toBeInTheDocument();
expect(screen.getByText('5x')).toBeInTheDocument();
expect(screen.getByText('0.1x')).toBeInTheDocument();
expect(screen.getByText('10000000000000')).toBeInTheDocument();
expect(screen.getByText('100x')).toBeInTheDocument();
expect(screen.getByText('10x')).toBeInTheDocument();
});
});
@@ -0,0 +1,164 @@
import { useTranslation } from 'react-i18next';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import {
KeyValueTable,
KeyValueTableRow,
RoundedWrapper,
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import {
formatMinimumStakedTokens,
formatReferralRewardMultiplier,
} from '../proposal-referral-program-details';
import { formatNumberPercentage } from '@vegaprotocol/utils';
import BigNumber from 'bignumber.js';
// These types are not generated as it's not known how dynamic these are
type VestingBenefitTier = {
minimum_quantum_balance: string;
reward_multiplier: string;
};
type ActivityStreakBenefitTier = {
minimum_activity_streak: number;
reward_multiplier: string;
vesting_multiplier: string;
};
export type BenefitTiers =
| Array<ActivityStreakBenefitTier>
| Array<VestingBenefitTier>;
export function getBenefitTiers(json: string): BenefitTiers {
try {
const parsed = JSON.parse(json);
return parsed.tiers;
} catch (e) {
return [];
}
}
export const formatVolumeDiscountFactor = (value: string) => {
return formatNumberPercentage(new BigNumber(value).times(100));
};
interface ProposalReferralProgramDetailsProps {
proposal: ProposalQuery['proposal'];
}
/**
* Special rendered for network proposals that change any benefit tiers,
* which is detected by:
* 1) it being a network parameter change
* 2) the name of the field ending in `.benefitTiers`
*
* It only renders known fields so that they can be formatted correctly.
*/
export const ProposalUpdateBenefitTiers = ({
proposal,
}: ProposalReferralProgramDetailsProps) => {
const { t } = useTranslation();
if (
proposal?.terms?.change?.__typename !== 'UpdateNetworkParameter' ||
proposal?.terms?.change?.networkParameter.key.slice(-13) !== '.benefitTiers'
) {
return null;
}
const benefitTiersString = proposal?.terms?.change?.networkParameter.value;
const benefitTiers = getBenefitTiers(benefitTiersString);
if (!benefitTiers) {
return null;
}
return (
<div data-testid="proposal-update-benefit-tiers">
<RoundedWrapper paddingBottom={true}>
{benefitTiers && (
<div
className="mb-6"
data-testid="proposal-volume-discount-program-benefit-tiers"
>
<h3 className="mb-3 uppercase font-semibold text-lg">
{t('BenefitTiers')}
</h3>
<KeyValueTable>
{benefitTiers
.sort(
(a, b) =>
Number(a.reward_multiplier) - Number(b.reward_multiplier)
)
.map((benefitTier, index) => (
<div className="mb-4" key={index}>
<h4 className="font-semibold uppercase">
Tier {index + 1}
</h4>
{'minimum_activity_streak' in benefitTier && (
<KeyValueTableRow
data-testid={`mas-${benefitTier.reward_multiplier}`}
>
<Tooltip
description={t(
'BenefitTierMinimumActivityStreakDescription'
)}
>
<span>{t('BenefitTierMinimumActivityStreak')}</span>
</Tooltip>
{benefitTier.minimum_activity_streak}
</KeyValueTableRow>
)}
{'minimum_quantum_balance' in benefitTier && (
<KeyValueTableRow
data-testid={`mqb-${benefitTier.reward_multiplier}`}
>
<Tooltip
description={t(
'BenefitTierMinimumQuantumBalanceDescription'
)}
>
<span>{t('BenefitTierMinimumQuantumBalance')}</span>
</Tooltip>
{formatMinimumStakedTokens(
benefitTier.minimum_quantum_balance,
18
)}
</KeyValueTableRow>
)}
{'vesting_multiplier' in benefitTier && (
<KeyValueTableRow
data-testid={`vm-${benefitTier.reward_multiplier}`}
>
<Tooltip
description={t('BenefitTierVestingMultiplier')}
>
<span>{t('BenefitTierVestingMultiplier')}</span>
</Tooltip>
{formatReferralRewardMultiplier(
benefitTier.vesting_multiplier
)}
</KeyValueTableRow>
)}
{'reward_multiplier' in benefitTier && (
<KeyValueTableRow
data-testid={`rm-${benefitTier.reward_multiplier}`}
>
<Tooltip description={t('BenefitTierRewardMultiplier')}>
<span>{t('BenefitTierRewardMultiplier')}</span>
</Tooltip>
{formatReferralRewardMultiplier(
benefitTier.reward_multiplier
)}
</KeyValueTableRow>
)}
</div>
))}
</KeyValueTable>
</div>
)}
</RoundedWrapper>
</div>
);
};
@@ -0,0 +1 @@
export * from './proposal-update-market-state';
@@ -0,0 +1,123 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { ProposalUpdateMarketState } from './proposal-update-market-state';
import { generateProposal } from '../../test-helpers/generate-proposals';
import { MarketUpdateType } from '@vegaprotocol/types';
describe('<ProposalUpdateMarketState />', () => {
const suspendProposal = generateProposal({
terms: {
change: {
__typename: 'UpdateMarketState',
market: {
id: '1',
decimalPlaces: 0,
tradableInstrument: {
instrument: {
name: 'suspendProposal Name',
code: 'suspendProposal Code',
product: {
__typename: 'Future',
quoteName: 'USD',
},
},
},
},
updateType: MarketUpdateType.MARKET_STATE_UPDATE_TYPE_SUSPEND,
},
},
});
const resumeProposal = generateProposal({
terms: {
change: {
__typename: 'UpdateMarketState',
market: {
id: '1',
decimalPlaces: 0,
tradableInstrument: {
instrument: {
name: 'resumeProposal Name',
code: 'resumeProposal Code',
product: {
__typename: 'Future',
quoteName: 'USD',
},
},
},
},
updateType: MarketUpdateType.MARKET_STATE_UPDATE_TYPE_RESUME,
},
},
});
const terminateProposal = generateProposal({
terms: {
change: {
__typename: 'UpdateMarketState',
market: {
id: '1',
decimalPlaces: 0,
tradableInstrument: {
instrument: {
name: 'terminateProposal Name',
code: 'terminateProposal Code',
product: {
__typename: 'Future',
quoteName: 'USD',
},
},
},
},
updateType: MarketUpdateType.MARKET_STATE_UPDATE_TYPE_TERMINATE,
price: '123',
},
},
});
it('should render nothing if proposal is null', () => {
render(<ProposalUpdateMarketState proposal={null} />);
expect(screen.queryByTestId('proposal-update-market-state')).toBeNull();
});
it('should toggle details when CollapsibleToggle is clicked', () => {
render(<ProposalUpdateMarketState proposal={suspendProposal} />);
expect(
screen.queryByTestId('proposal-update-market-state-table')
).toBeNull();
fireEvent.click(screen.getByTestId('proposal-market-data-toggle'));
expect(
screen.getByTestId('proposal-update-market-state-table')
).toBeInTheDocument();
});
it('should display suspend market information when showDetails is true', () => {
render(<ProposalUpdateMarketState proposal={suspendProposal} />);
fireEvent.click(screen.getByTestId('proposal-market-data-toggle'));
expect(screen.getByText('suspendProposal Name')).toBeInTheDocument();
expect(screen.getByText('suspendProposal Code')).toBeInTheDocument();
});
it('should display resume market information when showDetails is true', () => {
render(<ProposalUpdateMarketState proposal={resumeProposal} />);
fireEvent.click(screen.getByTestId('proposal-market-data-toggle'));
expect(screen.getByText('resumeProposal Name')).toBeInTheDocument();
expect(screen.getByText('resumeProposal Code')).toBeInTheDocument();
});
it('should display terminate market information when showDetails is true', () => {
render(<ProposalUpdateMarketState proposal={terminateProposal} />);
fireEvent.click(screen.getByTestId('proposal-market-data-toggle'));
expect(screen.getByText('terminateProposal Name')).toBeInTheDocument();
expect(screen.getByText('terminateProposal Code')).toBeInTheDocument();
expect(screen.getByText('123 USD')).toBeInTheDocument();
});
});

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