Compare commits

..
Author SHA1 Message Date
Madalina Raicu e966320466 Merge branches 'feat/liquidity-info-sla-devnet' and 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-22 10:21:41 +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
Madalina Raicu d5f55adba6 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-21 15:09:55 +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
Madalina Raicu 9bfe033f89 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-21 09:47:54 +01: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
Madalina Raicu 86d1f96c72 chore(trading): update .env to stagnet1 2023-09-20 15:52:03 +01:00
Madalina Raicu ffa360584b chore: set iceberg orders to true 2023-09-20 15:24:46 +01:00
Madalina Raicu 0266dcb04e chore: remove empty line 2023-09-20 15:23:22 +01:00
Madalina Raicu 1c6a8d3dfb test: add liq. price range back in tests cypress 2023-09-20 15:22:36 +01:00
Madalina Raicu 7c9fd50540 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-20 11:10:21 +01:00
Madalina Raicu 690844c287 Merge branch 'feat/liquidity-info-sla-devnet' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-20 10:37:18 +01:00
m.rayandcandida-d eb9be9989a Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-20 10:36:09 +01:00
Madalina Raicu 6829a5f672 chore: update lint 2023-09-19 18:31:32 +01:00
Madalina Raicu 11e73ad740 Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-19 18:31:17 +01:00
Madalina Raicu ad51d98081 Merge branch 'feat/liquidity-info-sla-devnet' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-19 18:30:21 +01:00
Madalina Raicu d2a27b5e78 chore: update governance-e2e proposal.functions.ts 2023-09-19 18:27:37 +01:00
m.rayandcandida-d fd2d513bc7 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 17:56:40 +01:00
m.rayandcandida-d 89f78cac55 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 17:55:42 +01:00
m.rayandcandida-d c45428d322 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 17:55:32 +01:00
Madalina Raicu 0e90d43c2e fix: on proposals UpdateNetworkParameterFields typo 2023-09-19 17:53:56 +01:00
Madalina Raicu 041e5cf836 chore: update types 2023-09-19 17:47:46 +01:00
Madalina Raicu 37868a1509 chore: update lint issue 2023-09-19 16:52:14 +01:00
Madalina Raicu 2724431751 Merge branch 'feat/liquidity-info-sla-devnet' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-19 16:48:00 +01:00
m.rayandcandida-d 2959d56375 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 16:47:44 +01:00
Madalina Raicu 03d33e54e2 Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-19 16:47:04 +01:00
Madalina Raicu 54fd511ae7 Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-09-19 16:40:17 +01:00
Madalina Raicu 0c4dab973f chore: update closed.tsx 2023-09-19 16:40:01 +01:00
Madalina Raicu c6c0baa003 Merge branch 'feat/liquidity-info-sla-devnet' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-19 16:35:49 +01:00
Madalina Raicu d4ef912be4 Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-19 16:35:21 +01:00
m.rayandcandida-d a1dbd31510 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 16:20:49 +01:00
m.rayandcandida-d 896245813e Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 16:20:05 +01:00
m.rayandcandida-d e43ac158e0 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 16:19:52 +01:00
m.rayandcandida-d 79cc20393c Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 16:19:43 +01:00
m.rayandcandida-d ac536d10df Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 16:19:23 +01:00
m.rayandcandida-d 31f16e566d Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 16:19:12 +01:00
m.rayandcandida-d 03592a7bf5 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 16:19:04 +01:00
m.rayandcandida-d 4016301869 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 16:18:55 +01:00
m.rayandcandida-d b250398def Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-09-19 16:18:42 +01:00
Joe a908f0ca7e Merge remote-tracking branch 'origin/feature/browse-perpetuals' into feature/browse-perpetuals 2023-09-19 16:04:22 +01:00
Madalina Raicu 6875db7ad3 test: fixed closed.spec and updated types 2023-09-19 15:46:00 +01:00
Joe Tsang ce42246ab9 chore: fix failing tests by adding liquidity sla params 2023-09-19 15:32:11 +01:00
Madalina Raicu c6053e0af0 chore: update market-info.mock.ts 2023-09-19 14:55:22 +01:00
Madalina Raicu 8870fee18d Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-19 14:41:06 +01:00
Madalina Raicu 2870a36366 test: skip renders correctly formatted and filtered rows 2023-09-19 13:27:41 +01:00
Madalina Raicu 51848e125e chore: comment out temporarily spots market fragements 2023-09-19 13:17:39 +01:00
Madalina Raicu e91579965e Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-09-19 13:13:04 +01:00
Madalina Raicu e7c58eb59b chore: update .env to use stagnet1 for develop 2023-09-18 16:40:00 +01:00
Madalina Raicu ef4ef8daec Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-09-18 13:01:40 +01:00
Madalina Raicu 05016bcfcf test: remove double literal 2023-09-18 09:43:25 +01:00
Madalina Raicu 0776910818 chore: remove redundant reload literals 2023-09-15 17:38:35 +01:00
Madalina Raicu 1a5fcfc9fc Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-15 17:07:49 +01:00
Madalina Raicu d935f58e39 Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-09-15 17:06:36 +01:00
Madalina Raicu add6450b66 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-09-15 17:05:38 +01:00
Bartłomiej Głownia 0df6c20799 feat: fix type errror in mocked order data 2023-09-15 11:29:56 +02:00
Matthew Russell 1681672415 chore: fix lint 2023-09-13 20:19:30 -07:00
Madalina Raicu cc128725d1 chore: update fee calculation timestep 2023-09-13 18:47:28 +01:00
Madalina Raicu 40fa38673f Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-13 18:44:38 +01:00
Madalina Raicu 5a691f35ca Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-09-13 17:20:59 +01:00
Madalina Raicu cf63959dbc chore: update product data types 2023-09-13 15:50:17 +01:00
Madalina Raicu 09a082cd83 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-09-12 13:29:12 +01:00
Madalina Raicu 2a0d7f9340 chore: remove unused import 2023-09-12 13:28:53 +01:00
Madalina Raicu b5f50e8f80 chore: update types 2023-09-11 16:21:00 +01:00
Madalina Raicu 7a84fbc534 Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-09-11 16:20:40 +01:00
Madalina Raicu 4dc0a30df7 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-09-11 16:17:52 +01:00
Bartłomiej Głownia 70b350aa79 feat(trading): change empty value from dash to Unknown 2023-09-08 15:20:01 +02:00
Bartłomiej Głownia ba0abb7de0 feat(trading): add MarketProductPill to MarketHeader 2023-09-06 13:34:45 +02:00
Bartłomiej Głownia a5fb9d2c58 feat(trading): show funding in market info 2023-09-06 11:22:04 +02:00
Bartłomiej Głownia eb4ffd05ef feat(trading): show funding info in perpetual markets 2023-09-06 08:03:31 +02:00
Madalina Raicu b0df045b10 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-09-05 18:23:35 +01:00
Madalina Raicu 4ac1cd10c4 Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-09-05 18:20:43 +01:00
Madalina Raicu 3fd08aa387 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-05 18:09:59 +01:00
Madalina Raicu 3c35fe065a chore: update SLA tooltips and arrangement 2023-09-04 13:30:29 +01:00
Madalina Raicu b139b79ebc chore: update missing import 2023-09-04 11:24:48 +01:00
Madalina Raicu b79df69a56 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-09-04 11:24:13 +01:00
Bartłomiej Głownia 9b44b5d8eb feat: add funding chart 2023-09-04 09:27:55 +02:00
Bartłomiej Głownia 699ddbcee5 feat: add funding tab 2023-09-01 13:53:10 +02:00
Bartłomiej Głownia e910505e3d feat(markets): dry in tradableInstrument product queries, improve dataSourceSpec typing 2023-09-01 13:52:15 +02:00
Madalina Raicu 63daa5e6ec chore: add back liquidity price range panel 2023-08-31 13:23:07 +01:00
Madalina Raicu 93c6908767 Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-08-31 11:46:42 +01:00
Madalina Raicu 6b124dcec8 chore: remove closed-markets.cy.ts 2023-08-31 11:41:57 +01:00
Madalina Raicu f6492b2b26 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-31 11:10:33 +01:00
Madalina Raicu 91b2d97b44 chore: update mappings and types 2023-08-31 11:07:57 +01:00
Madalina Raicu dbe1c49f40 chore: update types 2023-08-31 11:06:42 +01:00
Madalina Raicu 84b4ef1708 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-08-31 11:02:23 +01:00
Madalina Raicu c4ca5e1b56 chore: update dependency and typo in file name 2023-08-30 18:45:49 +01:00
Madalina Raicu 175a15e845 chore: remove price range tooltip 2023-08-30 16:55:01 +01:00
Madalina Raicu cf50ca53a3 Merge branch 'feat/liquidity-info-sla-devnet' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-08-30 16:51:53 +01:00
Madalina Raicu 9199049786 chore: update sla completion factor 2023-08-30 16:51:13 +01:00
m.rayandcandida-d 61bbbe8c66 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-08-30 16:50:13 +01:00
Madalina Raicu f657030be3 Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-08-30 16:06:17 +01:00
Madalina Raicu 5da73f34d7 Merge branch 'feat/liquidity-info-sla-devnet' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-08-30 16:04:29 +01:00
m.rayandcandida-d 035fd7f5a0 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-08-30 16:00:17 +01:00
m.rayandcandida-d ba90891cdb Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-08-30 15:59:56 +01:00
m.rayandcandida-d 70df1dcb3d Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-08-30 15:59:29 +01:00
m.rayandcandida-d 509fdf7eb7 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-08-30 15:59:19 +01:00
m.rayandcandida-d 39d7287307 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-08-30 15:59:04 +01:00
m.rayandcandida-d 7cdd2d66a1 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-08-30 15:58:43 +01:00
m.rayandcandida-d 850bc12342 Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-08-30 15:58:36 +01:00
m.rayandcandida-d 87a4b9fb4a Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-08-30 15:58:12 +01:00
m.rayandcandida-d 925cb747ca Update libs/markets/src/lib/components/market-info/tooltip-mapping.tsx
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-08-30 15:58:04 +01:00
Madalina Raicu 6e050abd1f chore: update product types in specs 2023-08-30 15:40:22 +01:00
Madalina Raicu 532ee62c32 chore: add product type to closed-markets 2023-08-30 12:46:13 +01:00
Madalina Raicu 9ec04be5dd chore: add product type to closed-markets 2023-08-30 12:45:46 +01:00
Madalina Raicu 4e908a0e0b Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-29 18:05:22 +01:00
Madalina Raicu 07e59f8832 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/liquidity-info-sla-devnet 2023-08-29 18:04:16 +01:00
Madalina Raicu 1dc6b00f61 feat(trading): add network params for SLAs in market info 2023-08-29 18:03:20 +01:00
Madalina Raicu b3eb1033ad chore(trading): add market info mock and test for LP SLA params 2023-08-29 17:27:30 +01:00
Madalina Raicu 966b370699 feat(trading): update tooltips for liquidity SLA parameters in market info 2023-08-29 17:17:03 +01:00
Madalina Raicu 85e52621f1 feat(trading): add liquidity SLA parameters in market info 2023-08-29 17:02:05 +01:00
Madalina Raicu 2572ce4e9f feat(trading): add liquidity SLA parameters in query 2023-08-29 16:54:16 +01:00
Madalina Raicu 149274454d Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-29 16:14:25 +01:00
Madalina Raicu 1cec1cea32 chore: update to new product types 2023-08-29 15:40:45 +01:00
Madalina Raicu 2b98290a7d feat(trading): remove lp price range 2023-08-29 14:49:21 +01:00
Madalina Raicu 425d77f271 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-29 11:59:56 +01:00
Madalina Raicu 1a6d15723d Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-29 09:48:09 +01:00
Madalina Raicu 85d4d667ae Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-29 09:43:54 +01:00
Madalina Raicu f5f393bc1e Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-26 13:10:52 +01:00
Madalina Raicu fa613b30d5 chore: update cypress tests 2023-08-26 10:53:10 +01:00
Madalina Raicu 96c71225e5 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-25 23:14:28 +01:00
Madalina Raicu 7a7ff4ac3e chore: update TRANSFER_TYPE_PERPETUALS_FUNDING_LOSS 2023-08-25 23:12:37 +01:00
Madalina Raicu e6b946c39c chore: update proposal with UpdateProposalProduct 2023-08-25 18:13:39 +01:00
Madalina Raicu 905c79c412 chore: update mocks for markets and disable test temporarily 2023-08-25 18:05:58 +01:00
Madalina Raicu f1ee43e9d2 chore: update tests for market list and fills 2023-08-25 18:02:12 +01:00
Madalina Raicu 34f21b189c chore: update market-selector 2023-08-25 16:12:47 +01:00
Madalina Raicu 58574951d9 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-25 14:51:05 +01:00
Madalina Raicu 13e6992b6b chore: increment AC in cypress tests for market-info 2023-08-25 13:47:51 +01:00
Madalina Raicu dcbac112fd Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-25 11:55:51 +01:00
Madalina Raicu 80ce7cece3 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-25 10:59:13 +01:00
Madalina Raicu a753378dab Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-25 09:41:42 +01:00
Matthew Russell 9e559ffb5a chore: use getAsset rather than relying on presence of settlementAsset 2023-08-24 16:48:03 -07:00
Matthew Russell 96b8f65f87 chore: adjust error messages 2023-08-24 16:47:12 -07:00
Matthew Russell a2a671b296 chore: switch type cast for const so strings are interpreted literally 2023-08-24 16:46:20 -07:00
Matthew Russell f0bba23560 chore: remove unnecessary null/undefined checks 2023-08-24 16:45:54 -07:00
Matthew Russell bfa02ed14d chore: removed unused lodash get 2023-08-24 16:45:06 -07:00
Matthew Russell 90e94c4bfd chore: generate proposal product types dynamically 2023-08-24 16:44:39 -07:00
Madalina Raicu 0fcde8e1f7 Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-24 17:37:37 +01:00
m.ray c9168a7941 Update libs/markets/src/lib/market-utils.ts 2023-08-24 17:07:51 +01:00
m.ray 8a630a9a44 Update libs/markets/src/lib/market-utils.ts 2023-08-24 17:07:18 +01:00
Madalina Raicu da7ee17e21 chore: update oracle and data specs 2023-08-24 17:06:21 +01:00
Madalina Raicu cd6e340e5a Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-24 10:31:41 +01:00
Madalina Raicu 6e1020ae92 chore: add getQuoteName in market-utils.ts 2023-08-23 17:57:10 +01:00
Madalina Raicu 4f2e28c54d chore: market-info.mock.ts update with quantum 2023-08-23 17:41:20 +01:00
Madalina Raicu 3452b15cf1 chore: update with getAsset 2023-08-23 17:40:56 +01:00
Madalina Raicu 87ca719ed3 chore: remove lpPriceRange 2023-08-23 17:01:39 +01:00
Madalina Raicu be52f22fc9 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-23 16:47:26 +01:00
Madalina Raicu e209cb828b chore(trading): add getAsset method in market-utils for product type check 2023-08-22 18:36:39 +01:00
Madalina Raicu 0ffcb5f9a7 Merge branch 'feature/browse-perpetuals' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-22 18:35:04 +01:00
Madalina Raicu cb8574ff41 chore(trading): add getAsset method in market-utils for product type check 2023-08-22 18:31:00 +01:00
m.rayandMatthew Russell 39c96dbf44 Update apps/explorer/src/app/routes/oracles/components/oracle-markets.tsx
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-08-22 17:47:23 +03:00
Madalina Raicu 41f3c8d9bb chore(trading): update build-spec 2023-08-22 13:16:03 +01:00
Madalina Raicu 38a3c3150a chore(trading): update types 2023-08-22 12:38:14 +01:00
Madalina Raicu 2a898c4cdb chore(trading): update types 2023-08-22 12:38:03 +01:00
Madalina Raicu eff3fd772c chore(explorer): update party block state 2023-08-22 12:35:08 +01:00
Madalina Raicu 49d1c7b8bf Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feature/browse-perpetuals 2023-08-22 12:25:49 +01:00
Madalina Raicu 9c01a69e73 chore: update schema for perpetuals and spots 2023-08-22 12:22:00 +01:00
Madalina Raicu b65697d096 feat(trading): update schema after perpetuals 2023-08-17 15:34:32 +03:00
106 changed files with 2653 additions and 596 deletions
+10 -8
View File
@@ -14,6 +14,8 @@ on:
- synchronize
jobs:
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
name: 'Cache yarn modules'
steps:
@@ -175,14 +177,14 @@ jobs:
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
preview_tools: ${{ env.PREVIEW_TOOLS }}
console-e2e:
needs: build-sources
name: '(CI) console python'
uses: ./.github/workflows/console-test-run.yml
secrets: inherit
if: ${{ contains(fromJSON(needs.build-sources.outputs.projects), 'trading') && github.event_name == 'pull_request' }}
with:
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
# console-e2e:
# needs: build-sources
# name: '(CI) console python'
# uses: ./.github/workflows/console-test-run.yml
# secrets: inherit
# if: ${{ contains(fromJSON(needs.build-sources.outputs.projects), 'trading') && github.event_name == 'pull_request' }}
# with:
# github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
cypress:
needs: build-sources
+2 -2
View File
@@ -7,7 +7,7 @@ on:
workflow_call:
inputs:
github-sha:
required: false
required: true
type: string
jobs:
@@ -109,7 +109,7 @@ jobs:
#----------------------------------------------
- name: Run tests
working-directory: ./console-test
run: poetry run pytest -v -s
run: poetry run pytest -v -s --numprocesses 2 --dist loadfile --durations=20
- name: Check files
run: |
ls -al .
@@ -95,7 +95,6 @@ context('Market page', { tags: '@regression' }, function () {
);
cy.validate_element_from_table('Lowest Price', '0.00 fUSDC');
cy.validate_element_from_table('Highest Price', '0.00 fUSDC');
cy.getByTestId('oracle-spec-links')
.should('have.attr', 'href')
.and(
@@ -1,6 +1,8 @@
import { t } from '@vegaprotocol/i18n';
import type { MarketInfoWithData } from '@vegaprotocol/markets';
import {
LiquidityPriceRangeInfoPanel,
LiquiditySLAParametersInfoPanel,
PriceMonitoringBoundsInfoPanel,
SuccessionLineInfoPanel,
getDataSourceSpecForSettlementData,
@@ -94,6 +96,10 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
)}
<h2 className={headerClassName}>{t('Liquidity monitoring')}</h2>
<LiquidityMonitoringParametersInfoPanel market={market} />
<h2 className={headerClassName}>{t('Liquidity price range')}</h2>
<LiquidityPriceRangeInfoPanel market={market} />
<h2 className={headerClassName}>{t('Liquidity SLA protocol')}</h2>
<LiquiditySLAParametersInfoPanel market={market} />
<h2 className={headerClassName}>{t('Liquidity')}</h2>
<LiquidityInfoPanel market={market} />
{showTwoOracles ? (
@@ -108,7 +108,7 @@ export function createNewMarketProposalTxBody(): ProposalSubmissionBody {
liquiditySlaParameters: {
priceRange: '0.5',
commitmentMinTimeFraction: '0.1',
performanceHysteresisEpochs: 0,
performanceHysteresisEpochs: 2,
slaCompetitionFactor: '0.1',
},
quadraticSlippageFactor: '0',
@@ -243,7 +243,7 @@ export function createSuccessorMarketProposalTxBody(
liquiditySlaParameters: {
priceRange: '0.5',
commitmentMinTimeFraction: '0.1',
performanceHysteresisEpochs: 0,
performanceHysteresisEpochs: 2,
slaCompetitionFactor: '0.1',
},
instrument: {
@@ -5,6 +5,8 @@ import {
InstrumentInfoPanel,
KeyDetailsInfoPanel,
LiquidityMonitoringParametersInfoPanel,
LiquidityPriceRangeInfoPanel,
LiquiditySLAParametersInfoPanel,
MetadataInfoPanel,
OracleInfoPanel,
PriceMonitoringBoundsInfoPanel,
@@ -270,6 +272,21 @@ export const ProposalMarketData = ({
market={marketData}
parentMarket={parentMarketData}
/>
<h2 className={marketDataHeaderStyles}>
{t('Liquidity price range')}
</h2>
<LiquidityPriceRangeInfoPanel
market={marketData}
parentMarket={parentMarketData}
/>
<h2 className={marketDataHeaderStyles}>
{t('Liquidity SLA protocol')}
</h2>
<LiquiditySLAParametersInfoPanel
market={marketData}
parentMarket={parentMarketData}
/>
</div>
</>
)}
@@ -6,6 +6,11 @@ import { MockedProvider } from '@apollo/client/testing';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { ProposalDocument } from './__generated__/Proposal';
jest.mock('@vegaprotocol/data-provider', () => ({
...jest.requireActual('@vegaprotocol/data-provider'),
useDataProvider: jest.fn(() => ({ data: [], loading: false })),
}));
jest.mock('../components/proposal', () => ({
Proposal: () => <div data-testid="proposal" />,
}));
@@ -44,7 +49,9 @@ const renderComponent = (
);
};
describe('Proposal container', () => {
// These tests are broken due to schema changes. NewMarket.futureProduct -> NewMarket.product union
// eslint-disable-next-line jest/no-disabled-tests
describe.skip('Proposal container', () => {
it('Renders not found if the proposal is not found', async () => {
render(renderComponent(null, 'foo'));
await waitFor(() => {
+1
View File
@@ -24,6 +24,7 @@ NX_STOP_ORDERS=true
NX_ICEBERG_ORDERS=true
# NX_PRODUCT_PERPETUALS
NX_METAMASK_SNAPS=true
NX_REFERRALS=true
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
+1
View File
@@ -24,6 +24,7 @@ NX_STOP_ORDERS=false
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS
NX_METAMASK_SNAPS=false
NX_REFERRALS=false
NX_TENDERMINT_URL=http://localhost:26617
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
+1
View File
@@ -22,6 +22,7 @@ NX_STOP_ORDERS=true
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS
NX_METAMASK_SNAPS=true
NX_REFERRALS=true
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
+1 -4
View File
@@ -17,16 +17,13 @@ NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-ma
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
# TAG name of the current app version - TODO: bump to the latest upon release
NX_APP_VERSION=v0.21.2-core-0.72.14
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_STOP_ORDERS=true
NX_ICEBERG_ORDERS=true
# NX_PRODUCT_PERPETUALS
NX_METAMASK_SNAPS=true
NX_REFERRALS=false
NX_TENDERMINT_URL=https://be.vega.community
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
+1
View File
@@ -24,6 +24,7 @@ NX_STOP_ORDERS=true
NX_ICEBERG_ORDERS=true
# NX_PRODUCT_PERPETUALS
NX_METAMASK_SNAPS=false
NX_REFERRALS=false
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
+1
View File
@@ -24,3 +24,4 @@ NX_STOP_ORDERS=true
NX_ICEBERG_ORDERS=true
# NX_PRODUCT_PERPETUALS
NX_METAMASK_SNAPS=true
NX_REFERRALS=true
+1
View File
@@ -24,6 +24,7 @@ NX_STOP_ORDERS=true
NX_ICEBERG_ORDERS=true
# NX_PRODUCT_PERPETUALS
NX_METAMASK_SNAPS=true
NX_REFERRALS=true
NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket
+1
View File
@@ -25,6 +25,7 @@ NX_STOP_ORDERS=true
NX_ICEBERG_ORDERS=true
# NX_PRODUCT_PERPETUALS
NX_METAMASK_SNAPS=false
NX_REFERRALS=false
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
@@ -0,0 +1,31 @@
import { t } from '@vegaprotocol/i18n';
import { Links } from '../../lib/links';
import classNames from 'classnames';
import { NavLink, Outlet } from 'react-router-dom';
export const Assets = () => {
const linkClasses = ({ isActive }: { isActive: boolean }) => {
return classNames('border-b-2 border-transparent', {
'border-vega-yellow': isActive,
});
};
return (
<div className="max-w-[500px] px-4 mx-auto my-8">
<nav className="flex mb-6 text-lg gap-4">
<NavLink to={Links.DEPOSIT()} className={linkClasses}>
{t('Deposit')}
</NavLink>
<NavLink to={Links.WITHDRAW()} className={linkClasses}>
{t('Withdraw')}
</NavLink>
<NavLink to={Links.TRANSFER()} className={linkClasses}>
{t('Transfer')}
</NavLink>
</nav>
<div className="pt-4 border-t md:p-6 md:border md:rounded-xl border-default">
<Outlet />
</div>
</div>
);
};
@@ -0,0 +1 @@
export { Assets } from './assets';
@@ -0,0 +1,44 @@
import { t } from '@vegaprotocol/i18n';
import { Intent, TradingAnchorButton } from '@vegaprotocol/ui-toolkit';
import { GetStartedCheckList } from '../../components/welcome-dialog';
import {
useGetOnboardingStep,
useOnboardingStore,
OnboardingStep,
} from '../../components/welcome-dialog/use-get-onboarding-step';
import { Links } from '../../lib/links';
import classNames from 'classnames';
export const DepositGetStarted = () => {
const onboardingDismissed = useOnboardingStore((store) => store.dismissed);
const dismiss = useOnboardingStore((store) => store.dismiss);
const step = useGetOnboardingStep();
const wrapperClasses = classNames(
'flex flex-col py-4 px-6 gap-4 rounded',
'bg-vega-blue-300 dark:bg-vega-blue-700',
'border border-vega-blue-350 dark:border-vega-blue-650'
);
// Dont show unless still onboarding
if (onboardingDismissed) {
return null;
}
return (
<div className="pt-6 border-t border-default">
<div className={wrapperClasses}>
<h3 className="text-lg">{t('Get started')}</h3>
<GetStartedCheckList />
{step > OnboardingStep.ONBOARDING_DEPOSIT_STEP && (
<TradingAnchorButton
href={Links.HOME()}
onClick={() => dismiss()}
intent={Intent.Info}
>
{t('Start trading')}
</TradingAnchorButton>
)}
</div>
</div>
);
};
@@ -0,0 +1,30 @@
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { Deposit } from './deposit';
jest.mock('@vegaprotocol/deposits', () => ({
DepositContainer: ({ assetId }: { assetId?: string }) => (
<div data-testid="assetId">{assetId}</div>
),
}));
jest.mock('./deposit-get-started', () => ({
DepositGetStarted: () => <div>DepositGetStarted</div>,
}));
const renderJsx = (route = '/deposit') => {
render(
<MemoryRouter initialEntries={[route]}>
<Deposit />
</MemoryRouter>
);
};
describe('Deposit page', () => {
it('assetId should be passed down', () => {
const assetId = 'foo';
const route = '/deposit?assetId=' + assetId;
renderJsx(route);
expect(screen.getByTestId('assetId')).toHaveTextContent(assetId);
});
});
+7 -52
View File
@@ -1,59 +1,14 @@
import { DepositContainer } from '@vegaprotocol/deposits';
import { t } from '@vegaprotocol/i18n';
import { Intent, TradingAnchorButton } from '@vegaprotocol/ui-toolkit';
import { GetStartedCheckList } from '../../components/welcome-dialog';
import {
useGetOnboardingStep,
useOnboardingStore,
OnboardingStep,
} from '../../components/welcome-dialog/use-get-onboarding-step';
import { Links, Routes } from '../../pages/client-router';
import classNames from 'classnames';
import { useSearchParams } from 'react-router-dom';
import { DepositGetStarted } from './deposit-get-started';
export const Deposit = () => {
const [searchParams] = useSearchParams();
const assetId = searchParams.get('assetId') || undefined;
return (
<div className="max-w-[600px] px-4 py-8 mx-auto lg:px-8">
<h1 className="mb-6 text-4xl uppercase xl:text-5xl font-alpha calt">
{t('Deposit')}
</h1>
<div className="flex flex-col gap-6">
<DepositContainer />
<DepositGetStarted />
</div>
</div>
);
};
const DepositGetStarted = () => {
const onboardingDismissed = useOnboardingStore((store) => store.dismissed);
const dismiss = useOnboardingStore((store) => store.dismiss);
const step = useGetOnboardingStep();
const wrapperClasses = classNames(
'flex flex-col py-4 px-6 gap-4 rounded',
'bg-vega-blue-300 dark:bg-vega-blue-700',
'border border-vega-blue-350 dark:border-vega-blue-650'
);
// Dont show unless still onboarding
if (onboardingDismissed) {
return null;
}
return (
<div className="pt-6 border-t border-default">
<div className={wrapperClasses}>
<h3 className="text-lg">{t('Get started')}</h3>
<GetStartedCheckList />
{step > OnboardingStep.ONBOARDING_DEPOSIT_STEP && (
<TradingAnchorButton
href={Links[Routes.HOME]()}
onClick={() => dismiss()}
intent={Intent.Info}
>
{t('Start trading')}
</TradingAnchorButton>
)}
</div>
<div className="flex flex-col gap-6">
<DepositContainer assetId={assetId} />
<DepositGetStarted />
</div>
);
};
@@ -2,47 +2,45 @@ import { t } from '@vegaprotocol/i18n';
export const Disclaimer = () => {
return (
<div className="py-16 px-8 flex w-full justify-center">
<div className="lg:min-w-[700px] min-w-[300px] max-w-[700px]">
<h1 className="text-4xl xl:text-5xl uppercase font-alpha calt">
{t('Disclaimer')}
</h1>
<p className="mb-6 mt-10">
{t(
'Vega is a decentralised peer-to-peer protocol that can be used to trade derivatives with cryptoassets. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are supplied to the Vega Protocol and losses due to the fluctuation of prices of assets.'
)}
</p>
<p className="mb-6">
{t(
'Before using the Vega Protocol, review the relevant documentation at docs.vega.xyz to make sure that you understand how it works. Conduct your own due diligence and consult your financial advisor before making any investment decisions.'
)}
</p>
<p className="mb-6">
{t(
'As described in the Vega Protocol core license, the Vega Protocol is provided “as is”, at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.'
)}
</p>
<p className="mb-8">
{t(
'No developer or entity involved in creating the Vega Protocol will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Vega Protocol, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or legal costs, or loss of profits, cryptoassets, tokens or anything else of value.'
)}
</p>
<p className="mb-8">
{t(
'This website is hosted on a decentralised network, the Interplanetary File System (“IPFS”). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers.'
)}
</p>
<p className="mb-8">
{t(
"The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website's content as such. No party recommends that any cryptoasset should be bought, sold, or held by you via this website. No party ensures the accuracy of information listed on this website or holds any responsibility for any missing or wrong information. You understand that you are using any and all information available here at your own risk."
)}
</p>
<p className="mb-8">
{t(
'Additionally, just as you can access email protocols such as SMTP through multiple email clients, you can potentially access the Vega Protocol through many web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.'
)}
</p>
</div>
</div>
<>
<h1 className="text-4xl uppercase xl:text-5xl font-alpha calt">
{t('Disclaimer')}
</h1>
<p className="mt-10 mb-6">
{t(
'Vega is a decentralised peer-to-peer protocol that can be used to trade derivatives with cryptoassets. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are supplied to the Vega Protocol and losses due to the fluctuation of prices of assets.'
)}
</p>
<p className="mb-6">
{t(
'Before using the Vega Protocol, review the relevant documentation at docs.vega.xyz to make sure that you understand how it works. Conduct your own due diligence and consult your financial advisor before making any investment decisions.'
)}
</p>
<p className="mb-6">
{t(
'As described in the Vega Protocol core license, the Vega Protocol is provided “as is”, at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.'
)}
</p>
<p className="mb-8">
{t(
'No developer or entity involved in creating the Vega Protocol will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Vega Protocol, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or legal costs, or loss of profits, cryptoassets, tokens or anything else of value.'
)}
</p>
<p className="mb-8">
{t(
'This website is hosted on a decentralised network, the Interplanetary File System (“IPFS”). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers.'
)}
</p>
<p className="mb-8">
{t(
"The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website's content as such. No party recommends that any cryptoasset should be bought, sold, or held by you via this website. No party ensures the accuracy of information listed on this website or holds any responsibility for any missing or wrong information. You understand that you are using any and all information available here at your own risk."
)}
</p>
<p className="mb-8">
{t(
'Additionally, just as you can access email protocols such as SMTP through multiple email clients, you can potentially access the Vega Protocol through many web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.'
)}
</p>
</>
);
};
@@ -1,3 +1 @@
import { Disclaimer } from './disclaimer';
export default Disclaimer;
export { Disclaimer } from './disclaimer';
+4 -4
View File
@@ -1,9 +1,9 @@
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
import { Links, Routes } from '../../pages/client-router';
import { useGlobalStore } from '../../stores';
import { useTopTradedMarkets } from '../../lib/hooks/use-top-traded-markets';
import { Links } from '../../lib/links';
// The home pages only purpose is to redirect to the users last market,
// the top traded if they are new, or fall back to the list of markets.
@@ -15,17 +15,17 @@ export const Home = () => {
useEffect(() => {
if (marketId) {
navigate(Links[Routes.MARKET](marketId), {
navigate(Links.MARKET(marketId), {
replace: true,
});
} else if (data) {
const marketDataId = data[0]?.id;
if (marketDataId) {
navigate(Links[Routes.MARKET](marketDataId), {
navigate(Links.MARKET(marketDataId), {
replace: true,
});
} else {
navigate(Links[Routes.MARKETS]());
navigate(Links.MARKETS());
}
}
}, [marketId, data, navigate]);
+1 -3
View File
@@ -1,3 +1 @@
import { Home } from './home';
export default Home;
export { Home } from './home';
+1 -3
View File
@@ -1,3 +1 @@
import { Liquidity } from './liquidity';
export default Liquidity;
export { Liquidity } from './liquidity';
+1 -3
View File
@@ -1,3 +1 @@
import { MarketPage } from './market';
export default MarketPage;
export { MarketPage as default } from './market';
@@ -126,32 +126,20 @@ export const FundingRate = ({ marketId }: { marketId: string }) => {
);
};
const padStart = (n: number) => n.toString().padStart(2, '0');
export const FundingCountdown = ({ marketId }: { marketId: string }) => {
const { data: fundingPeriods } = useFundingPeriodsQuery({
variables: {
marketId: marketId,
pagination: { first: 1 },
},
});
const { data: marketInfo } = useDataProvider({
dataProvider: marketInfoProvider,
variables: { marketId },
});
const useNow = () => {
const [now, setNow] = useState(Date.now());
useEffect(() => {
const interval = setInterval(() => setNow(Date.now()), 1000);
return () => clearInterval(interval);
}, []);
return now;
};
const node = fundingPeriods?.fundingPeriods.edges?.[0]?.node;
let startTime: number | undefined = undefined;
if (node && node.startTime && !node.endTime) {
startTime = fromNanoSeconds(node.startTime).getTime();
}
let diffFormatted = t('Unknown');
const useEvery = (marketId: string) => {
const { data: marketInfo } = useDataProvider({
dataProvider: marketInfoProvider,
variables: { marketId },
});
let every: number | undefined = undefined;
const sourceType =
marketInfo &&
@@ -165,14 +153,51 @@ export const FundingCountdown = ({ marketId }: { marketId: string }) => {
every *= 1000;
}
}
return every;
};
const useStartTime = (marketId: string) => {
const { data: fundingPeriods } = useFundingPeriodsQuery({
variables: {
marketId: marketId,
pagination: { first: 1 },
},
});
const node = fundingPeriods?.fundingPeriods.edges?.[0]?.node;
let startTime: number | undefined = undefined;
if (node && node.startTime && !node.endTime) {
startTime = fromNanoSeconds(node.startTime).getTime();
}
return startTime;
};
const padStart = (n: number) => n.toString().padStart(2, '0');
const useFormatCountdown = (
now: number,
startTime?: number,
every?: number
) => {
if (startTime && every) {
const diff = every - ((now - startTime) % every);
const hours = (diff / 3.6e6) | 0;
const mins = ((diff % 3.6e6) / 6e4) | 0;
const secs = Math.round((diff % 6e4) / 1e3);
diffFormatted = `${padStart(hours)}:${padStart(mins)}:${padStart(secs)}`;
return `${padStart(hours)}:${padStart(mins)}:${padStart(secs)}`;
}
return <div data-testid="funding-countdown">{diffFormatted}</div>;
return t('Unknown');
};
export const FundingCountdown = ({ marketId }: { marketId: string }) => {
const now = useNow();
const startTime = useStartTime(marketId);
const every = useEvery(marketId);
return (
<div data-testid="funding-countdown">
{useFormatCountdown(now, startTime, every)}
</div>
);
};
const ExpiryLabel = ({ market }: ExpiryLabelProps) => {
+4 -4
View File
@@ -9,7 +9,7 @@ import { useGlobalStore, usePageTitleStore } from '../../stores';
import { TradeGrid } from './trade-grid';
import { TradePanels } from './trade-panels';
import { useNavigate, useParams } from 'react-router-dom';
import { Links, Routes } from '../../pages/client-router';
import { Links } from '../../lib/links';
import { ViewType, useSidebar } from '../../components/sidebar';
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
@@ -96,12 +96,12 @@ export const MarketPage = () => {
return (
<Splash>
<span className="flex flex-col items-center gap-2">
<p className="text-sm justify-center">
<p className="justify-center text-sm">
{t('This market URL is not available any more.')}
</p>
<p className="text-sm justify-center">
<p className="justify-center text-sm">
{t(`Please choose another market from the`)}{' '}
<ExternalLink onClick={() => navigate(Links[Routes.MARKETS]())}>
<ExternalLink onClick={() => navigate(Links.MARKETS())}>
market list
</ExternalLink>
</p>
+1 -3
View File
@@ -1,3 +1 @@
import { MarketsPage } from './markets-page';
export default MarketsPage;
export { MarketsPage } from './markets-page';
@@ -10,7 +10,7 @@ import {
import { DApp, EXPLORER_MARKET, useLinks } from '@vegaprotocol/environment';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import { useNavigate } from 'react-router-dom';
import { Links, Routes } from '../../pages/client-router';
import { Links } from '../../lib/links';
export const MarketActionsDropdown = ({
marketId,
@@ -52,7 +52,7 @@ export const MarketActionsDropdown = ({
{parentMarketID && (
<TradingDropdownItem
onClick={() => {
navigate(Links[Routes.MARKET](parentMarketID));
navigate(Links.MARKET(parentMarketID));
}}
>
<VegaIcon name={VegaIconNames.EYE} size={16} />
@@ -62,7 +62,7 @@ export const MarketActionsDropdown = ({
{successorMarketID && (
<TradingDropdownItem
onClick={() => {
navigate(Links[Routes.MARKET](successorMarketID));
navigate(Links.MARKET(successorMarketID));
}}
>
<VegaIcon name={VegaIconNames.EYE} size={16} />
@@ -28,7 +28,6 @@ export const useColumnDefs = () => {
{
headerName: t('Market'),
field: 'tradableInstrument.instrument.code',
flex: 2,
cellRenderer: ({
value,
data,
@@ -50,7 +49,6 @@ export const useColumnDefs = () => {
{
headerName: t('Description'),
field: 'tradableInstrument.instrument.name',
flex: 2,
},
{
headerName: t('Trading mode'),
+1 -3
View File
@@ -1,3 +1 @@
import { Portfolio } from './portfolio';
export default Portfolio;
export { Portfolio as default } from './portfolio';
@@ -0,0 +1,102 @@
import {
Input,
InputError,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import type { FieldValues } from 'react-hook-form';
import { useForm } from 'react-hook-form';
import classNames from 'classnames';
import { useSearchParams } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { Button } from './buttons';
import { useVegaWallet } from '@vegaprotocol/wallet';
export const ApplyCodeForm = () => {
const [finalized, setFinalized] = useState<boolean>(false);
const { isReadOnly, pubKey, sendTx } = useVegaWallet();
const {
register,
handleSubmit,
formState: { errors },
setValue,
setError,
} = useForm();
const [params] = useSearchParams();
useEffect(() => {
const code = params.get('code');
if (code) setValue('code', code);
}, [params, setValue]);
const onSubmit = ({ code }: FieldValues) => {
if (isReadOnly || !pubKey || !code || code.length === 0) {
return;
}
sendTx(pubKey, {
applyReferralCode: {
id: code as string,
},
})
.then((res) => {
setFinalized(true);
})
.catch((err) => {
setError('code', {
type: 'required',
message: 'Your code has been rejected',
});
});
};
if (finalized) {
return (
<div className="w-1/2 mx-auto">
<h3 className="mb-5 text-xl text-center uppercase calt flex flex-row gap-2 justify-center items-center">
<span className="text-vega-green-500">
<VegaIcon name={VegaIconNames.TICK} size={20} />
</span>{' '}
<span className="pt-1">Code applied</span>
</h3>
</div>
);
}
return (
<div className="w-1/2 mx-auto">
<h3 className="mb-5 text-xl text-center uppercase calt">
Apply a referral code
</h3>
<p className="mb-6 text-center">Enter a referral code</p>
<form
className={classNames('w-full flex flex-col gap-3', {
'animate-shake': Boolean(errors.code),
})}
onSubmit={handleSubmit(onSubmit)}
>
<label className="flex-grow">
<span className="block mb-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100">
Your referral code
</span>
<Input
hasError={Boolean(errors.code)}
{...register('code', {
required: 'You have to provide a code to apply it.',
})}
/>
</label>
<Button
disabled={isReadOnly || !pubKey}
className="w-full"
type="submit"
>
Apply
</Button>
</form>
{errors.code && (
<InputError>{errors.code.message?.toString()}</InputError>
)}
</div>
);
};
@@ -0,0 +1,83 @@
import { Intent, TradingButton } from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames';
import type { ComponentProps, ButtonHTMLAttributes } from 'react';
import { forwardRef } from 'react';
import { NavLink } from 'react-router-dom';
type RainbowButtonProps = {
variant?: 'full' | 'border';
};
export const RainbowButton = ({
variant = 'full',
children,
className,
...props
}: RainbowButtonProps & ButtonHTMLAttributes<HTMLButtonElement>) => (
<button
className={classNames(
'bg-rainbow hover:bg-none hover:bg-rainbow enabled:hover:bg-vega-pink-500 rounded-lg overflow-hidden disabled:opacity-40',
{
'px-5 py-3 text-white': variant === 'full',
'p-[0.125rem]': variant === 'border',
},
className
)}
{...props}
>
<div
className={classNames({
'bg-white dark:bg-vega-cdark-900 text-black dark:text-white px-5 py-3 rounded-[0.35rem] overflow-hidden':
variant === 'border',
})}
>
{children}
</div>
</button>
);
const RAINBOW_TAB_STYLE = classNames(
'inline-block',
'bg-vega-clight-500 dark:bg-vega-cdark-500 hover:bg-vega-clight-400 dark:hover:bg-vega-cdark-400',
'data-[state="active"]:text-white data-[state="active"]:bg-rainbow data-[state="active"]:hover:bg-none data-[state="active"]:hover:bg-vega-pink-500 dark:data-[state="active"]:hover:bg-vega-pink-500',
'[&.active]:text-white [&.active]:bg-rainbow [&.active]:hover:bg-none [&.active]:hover:bg-vega-pink-500 dark:[&.active]:hover:bg-vega-pink-500',
'px-5 py-3',
'first:rounded-tl-lg last:rounded-tr-lg'
);
export const RainbowTabButton = forwardRef<
HTMLButtonElement,
ButtonHTMLAttributes<HTMLButtonElement>
>(({ children, ...props }, ref) => (
<button ref={ref} className={RAINBOW_TAB_STYLE} {...props}>
{children}
</button>
));
RainbowTabButton.displayName = 'RainbowTabButton';
export const RainbowTabLink = ({
to,
children,
...props
}: ComponentProps<typeof NavLink>) => (
<NavLink to={to} className={RAINBOW_TAB_STYLE} {...props}>
{children}
</NavLink>
);
export const Button = forwardRef<
HTMLButtonElement,
ComponentProps<typeof TradingButton>
>(({ children, intent, type, ...props }, ref) => {
return (
<TradingButton
ref={ref}
intent={intent || type === 'submit' ? Intent.Primary : Intent.None}
type={type}
{...props}
>
{children}
</TradingButton>
);
});
Button.displayName = 'TradingButton';
@@ -0,0 +1,6 @@
export const BORDER_COLOR = 'border-vega-clight-500 dark:border-vega-cdark-500';
export const GRADIENT =
'bg-gradient-to-b from-vega-clight-800 dark:from-vega-cdark-800 to-transparent';
export const SKY_BACKGROUND =
'bg-[url(/sky-light.png)] dark:bg-[url(/sky-dark.png)] bg-[40%_0px] bg-[length:1440px] bg-no-repeat bg-local';
@@ -0,0 +1,225 @@
import {
useVegaWallet,
useVegaWalletDialogStore,
determineId,
} from '@vegaprotocol/wallet';
import { RainbowButton } from './buttons';
import { useState } from 'react';
import {
CopyWithTooltip,
Dialog,
ExternalLink,
InputError,
Intent,
TradingAnchorButton,
TradingButton,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
import { DApp, TokenStaticLinks, useLinks } from '@vegaprotocol/environment';
import { useStakeAvailable } from './hooks/use-stake-available';
export const CreateCodeContainer = () => {
const { stakeAvailable, requiredStake } = useStakeAvailable();
if (stakeAvailable == null || requiredStake == null) {
return null;
}
return (
<CreateCodeForm
currentStakeAvailable={stakeAvailable}
requiredStake={requiredStake}
/>
);
};
export const CreateCodeForm = ({
currentStakeAvailable,
requiredStake,
}: {
currentStakeAvailable: bigint;
requiredStake: bigint;
}) => {
const [dialogOpen, setDialogOpen] = useState(false);
const openWalletDialog = useVegaWalletDialogStore(
(store) => store.openVegaWalletDialog
);
const { pubKey } = useVegaWallet();
return (
<div className="w-1/2 mx-auto">
<h3 className="mb-5 text-xl text-center uppercase calt">
Create a referral code
</h3>
<p className="mb-6 text-center">
Generate a referral code to share with your friends and start earning
commission.
</p>
<div className="mb-5">
<div className="text-center">
<RainbowButton
variant="border"
onClick={() => {
if (pubKey) {
setDialogOpen(true);
} else {
openWalletDialog();
}
}}
>
{pubKey ? 'Create a referral code' : 'Connect wallet'}
</RainbowButton>
</div>
</div>
<Dialog
title="Create a referral code"
open={dialogOpen}
onChange={() => setDialogOpen(false)}
size="small"
>
<CreateCodeDialog
currentStakeAvailable={currentStakeAvailable}
setDialogOpen={setDialogOpen}
requiredStake={requiredStake}
/>
</Dialog>
</div>
);
};
const CreateCodeDialog = ({
setDialogOpen,
currentStakeAvailable,
requiredStake,
}: {
setDialogOpen: (open: boolean) => void;
currentStakeAvailable: bigint;
requiredStake: bigint;
}) => {
const createLink = useLinks(DApp.Governance);
const { isReadOnly, pubKey, sendTx } = useVegaWallet();
const [err, setErr] = useState<string | null>(null);
const [code, setCode] = useState<string | null>(null);
const [status, setStatus] = useState<
'idle' | 'loading' | 'success' | 'error'
>('idle');
const onSubmit = () => {
if (isReadOnly || !pubKey) {
setErr('Not connected');
} else {
setErr(null);
setStatus('loading');
setCode(null);
sendTx(pubKey, {
createReferralSet: {
isTeam: false,
},
})
.then((res) => {
if (!res) {
setErr(`Invalid response: ${JSON.stringify(res)}`);
return;
}
const code = determineId(res.signature);
setCode(code);
setStatus('success');
})
.catch((err) => {
if (err.message.includes('user rejected')) {
setStatus('idle');
return;
}
setStatus('error');
setErr(err.message);
});
}
};
const getButtonProps = () => {
if (status === 'idle' || status === 'error') {
return {
children: 'Generate code',
onClick: () => onSubmit(),
};
}
if (status === 'loading') {
return {
children: 'Confirm in wallet...',
disabled: true,
};
}
if (status === 'success') {
return {
children: 'Close',
intent: Intent.Success,
onClick: () => setDialogOpen(false),
};
}
};
// TODO: Add when network parameters are updated
if (
currentStakeAvailable === BigInt(0) ||
currentStakeAvailable < requiredStake
) {
return (
<div className="flex flex-col gap-4">
<p>
You need at least{' '}
{addDecimalsFormatNumber(requiredStake.toString(), 18)} VEGA staked to
generate a referral code and participate in the referral program.
</p>
<TradingAnchorButton
href={createLink(TokenStaticLinks.ASSOCIATE)}
intent={Intent.Primary}
target="_blank"
>
Stake some $VEGA now
</TradingAnchorButton>
</div>
);
}
return (
<div className="flex flex-col gap-4">
{(status === 'idle' || status === 'loading' || status === 'error') && (
<p>
Generate a referral code to share with your friends and start earning
commission.
</p>
)}
{status === 'success' && code && (
<div className="flex items-center gap-2">
<div className="flex-1 min-w-0 p-2 text-sm rounded bg-vega-clight-700 dark:bg-vega-cdark-700">
<p className="overflow-hidden whitespace-nowrap text-ellipsis">
{code}
</p>
</div>
<CopyWithTooltip text={code}>
<TradingButton
className="text-sm no-underline"
icon={<VegaIcon name={VegaIconNames.COPY} />}
>
<span>Copy</span>
</TradingButton>
</CopyWithTooltip>
</div>
)}
<TradingButton
fill={true}
intent={Intent.Primary}
{...getButtonProps()}
/>
{err && <InputError>{err}</InputError>}
{/* TODO: Add links */}
<div className="flex justify-center pt-5 mt-2 text-sm border-t gap-4 text-default border-default">
<ExternalLink>About the referral program</ExternalLink>
<ExternalLink>Disclaimer</ExternalLink>
</div>
</div>
);
};
@@ -0,0 +1,77 @@
import { isRouteErrorResponse, useNavigate, useRouteError } from 'react-router';
import { RainbowButton } from './buttons';
import { AnimatedDudeWithWire } from './graphics/dude';
import { LayoutWithSky } from './layout';
import { Routes } from '../../lib/links';
export const ErrorBoundary = () => {
const error = useRouteError();
const navigate = useNavigate();
const title = isRouteErrorResponse(error)
? `${error.status} ${error.statusText}`
: 'Something went wrong';
const code = isRouteErrorResponse(error) ? error.status : 0;
const messages: Record<number, string> = {
0: 'An unknown error occurred.',
404: "The page you're looking for doesn't exists.",
};
return (
<LayoutWithSky className="pt-32">
<div
aria-hidden
className="absolute top-64 right-[220px] md:right-[340px] max-sm:hidden"
>
<AnimatedDudeWithWire className="animate-spin" />
</div>
<h1 className="text-6xl font-alpha calt mb-10">{title}</h1>
{Object.keys(messages).includes(code.toString()) ? (
<p className="text-lg mb-10">{messages[code]}</p>
) : null}
<p className="text-lg mb-10">
<RainbowButton
onClick={() => navigate('..')}
variant="border"
className="text-xs"
>
Go back and try again
</RainbowButton>
</p>
</LayoutWithSky>
);
};
export const NotFound = () => {
const navigate = useNavigate();
return (
<div className="pt-32">
<div
aria-hidden
className="absolute top-64 right-[220px] md:right-[340px] max-sm:hidden"
>
<AnimatedDudeWithWire className="animate-spin" />
</div>
<h1 className="text-6xl font-alpha calt mb-10">{'Not found'}</h1>
<p className="text-lg mb-10">
{"The page you're looking for doesn't exists."}
</p>
<p className="text-lg mb-10">
<RainbowButton
onClick={() => navigate(Routes.REFERRALS)}
variant="border"
className="text-xs"
>
Go back and try again
</RainbowButton>
</p>
</div>
);
};
@@ -0,0 +1,70 @@
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
export const Dude = ({ className }: HTMLAttributes<SVGElement>) => {
return (
<svg
width="41"
height="47"
viewBox="0 0 41 47"
fill="none"
className={className}
>
<path
d="M21.1895 0.298767L5.08827 27.4101L8.96133 29.7103L4.36099 37.4564L8.23404 39.7566L12.8344 32.0105L16.7074 34.3107L12.1071 42.0568L15.9801 44.3569L20.5805 36.6108L24.4535 38.911L40.5547 11.7996L21.1895 0.298767Z"
className="fill-black dark:fill-white"
/>
<path
d="M35.9346 15.1683L20.4424 5.96765L14.3086 16.2958L29.8008 25.4965L35.9346 15.1683Z"
className="fill-white dark:fill-black"
/>
<path
d="M25.646 17.7895L23.064 16.2561L21.5305 18.8381L24.1126 20.3716L25.646 17.7895Z"
className="fill-black dark:fill-white"
/>
<path
d="M29.7612 16.7412L27.1792 15.2077L25.6458 17.7898L28.2278 19.3232L29.7612 16.7412Z"
className="fill-black dark:fill-white"
/>
<path
d="M33.877 15.6925L31.2949 14.159L29.7615 16.7411L32.3435 18.2745L33.877 15.6925Z"
className="fill-black dark:fill-white"
/>
<path
d="M29.0342 26.7874L26.4521 25.2539L24.9187 27.836L27.5007 29.3694L29.0342 26.7874Z"
fill="#FF077F"
/>
</svg>
);
};
export const Wire = ({ className }: HTMLAttributes<SVGElement>) => {
return (
<svg
width="157"
height="88"
viewBox="0 0 157 88"
fill="none"
className={className}
>
<path
d="M109.398 6.12235C127.37 -3.81898 146.791 1.45045 153.465 14.307C160.138 27.1636 154.195 43.9948 140.438 52.1164C126.68 60.238 105.767 54.9998 84.9212 43.464C64.0752 31.9281 32.2412 6.42016 18.8175 24.185C6.90871 40.719 41.9332 68.4495 29.2664 82.7049C23.187 88.4974 11.1379 88.2645 0.968295 80.3398"
className="stroke-black dark:stroke-white"
strokeWidth="1.5"
strokeMiterlimit="10"
/>
</svg>
);
};
export const AnimatedDudeWithWire = ({ className }: { className?: string }) => (
<div className="relative">
<Wire className="absolute top-[25px]" />
<Dude
className={classNames(
'absolute left-[96px] animate-[wave_20s_ease-in-out_infinite]',
className
)}
/>
</div>
);
@@ -0,0 +1,133 @@
import { gql, useQuery } from '@apollo/client';
import { getNumberFormat } from '@vegaprotocol/utils';
import { addDays } from 'date-fns';
import sortBy from 'lodash/sortBy';
import omit from 'lodash/omit';
// TODO: Generate query
// eslint-disable-next-line
const REFERRAL_PROGRAM_QUERY = gql`
query ReferralProgram {
currentReferralProgram {
id
version
endOfProgramTimestamp
windowLength
endedAt
benefitTiers {
minimumEpochs
minimumRunningNotionalTakerVolume
referralDiscountFactor
referralRewardFactor
}
stakingTiers {
minimumStakedTokens
referralRewardMultiplier
}
}
}
`;
const STAKING_TIERS_MAPPING: Record<number, string> = {
1: 'Tradestarter',
2: 'Mid level degen',
3: 'Reward hoarder',
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const MOCK = {
data: {
currentReferralProgram: {
id: 'abc',
version: 1,
endOfProgramTimestamp: addDays(new Date(), 10).toISOString(),
windowLength: 10,
benefitTiers: [
{
minimumEpochs: 5,
minimumRunningNotionalTakerVolume: '30000',
referralDiscountFactor: '0.01',
referralRewardFactor: '0.01',
},
{
minimumEpochs: 5,
minimumRunningNotionalTakerVolume: '20000',
referralDiscountFactor: '0.05',
referralRewardFactor: '0.05',
},
{
minimumEpochs: 5,
minimumRunningNotionalTakerVolume: '10000',
referralDiscountFactor: '0.001',
referralRewardFactor: '0.001',
},
],
stakingTiers: [
{
minimumStakedTokens: '10000',
referralRewardMultiplier: '1',
},
{
minimumStakedTokens: '20000',
referralRewardMultiplier: '2',
},
{
minimumStakedTokens: '30000',
referralRewardMultiplier: '3',
},
],
},
},
loading: false,
error: undefined,
};
export const useReferralProgram = () => {
const { data, loading, error } = useQuery(REFERRAL_PROGRAM_QUERY, {
fetchPolicy: 'cache-and-network',
});
if (!data) {
return {
benefitTiers: [],
stakingTiers: [],
details: undefined,
loading,
error,
};
}
const benefitTiers = sortBy(data.currentReferralProgram.benefitTiers, (t) =>
Number(t.referralRewardFactor)
)
.reverse()
.map((t, i) => {
return {
tier: i + 1,
commission: Number(t.referralRewardFactor) * 100 + '%',
discount: Number(t.referralDiscountFactor) * 100 + '%',
volume: getNumberFormat(0).format(
Number(t.minimumRunningNotionalTakerVolume)
),
};
});
const stakingTiers = sortBy(
data.currentReferralProgram.stakingTiers,
(t) => t.referralRewardMultiplier
).map((t, i) => {
return {
tier: i + 1,
label: STAKING_TIERS_MAPPING[i + 1],
...t,
};
});
return {
benefitTiers,
stakingTiers,
details: omit(data.currentReferralProgram, 'benefitTiers', 'stakingTiers'),
loading,
error,
};
};
@@ -0,0 +1,114 @@
import { gql, useQuery } from '@apollo/client';
import { removePaginationWrapper } from '@vegaprotocol/utils';
const REFERRER_QUERY = gql`
query ReferralSets($partyId: ID!) {
referralSets(referrer: $partyId) {
edges {
node {
id
referrer
createdAt
updatedAt
}
}
}
}
`;
const REFEREE_QUERY = gql`
query ReferralSets($partyId: ID!) {
referralSets(referee: $partyId) {
edges {
node {
id
referrer
createdAt
updatedAt
}
}
}
}
`;
const REFEREES_QUERY = gql`
query ReferralSets($code: ID!) {
referralSetReferees(id: $code) {
edges {
node {
referralSetId
refereeId
joinedAt
atEpoch
}
}
}
}
`;
// TODO: generate types after perps work is merged
export type ReferralData = {
code: string;
referees: Array<{
refereeId: string;
joinedAt: string;
atEpoch: number;
}>;
};
export const useReferral = (
pubKey: string | null,
role: 'referrer' | 'referee'
) => {
const query = {
referrer: REFERRER_QUERY,
referee: REFEREE_QUERY,
};
const {
data: referralData,
loading: referralLoading,
error: referralError,
} = useQuery(query[role], {
variables: {
partyId: pubKey,
},
skip: !pubKey,
fetchPolicy: 'cache-and-network',
});
// A user can only have 1 active referral program at a time
const referral = referralData?.referralSets.edges.length
? referralData.referralSets.edges[0].node
: undefined;
const {
data: refereesData,
loading: refereesLoading,
error: refereesError,
} = useQuery(REFEREES_QUERY, {
variables: {
code: referral?.id,
},
skip: !referral?.id,
fetchPolicy: 'cache-and-network',
});
const referees = removePaginationWrapper(
refereesData?.referralSetReferees.edges
);
const data =
referral && refereesData
? {
code: referral.id,
referees,
}
: undefined;
return {
data: data as ReferralData | undefined,
loading: referralLoading || refereesLoading,
error: referralError || refereesError,
};
};
@@ -0,0 +1,34 @@
import { gql, useQuery } from '@apollo/client';
import { useVegaWallet } from '@vegaprotocol/wallet';
const STAKE_QUERY = gql`
query CreateCode($partyId: ID!) {
party(id: $partyId) {
stakingSummary {
currentStakeAvailable
}
}
networkParameter(key: "referralProgram.minStakedVegaTokens") {
value
}
}
`;
export const useStakeAvailable = () => {
const { pubKey } = useVegaWallet();
const { data } = useQuery(STAKE_QUERY, {
variables: { partyId: pubKey || '' },
skip: !pubKey,
// TODO: remove when network params available
errorPolicy: 'ignore',
});
return {
stakeAvailable: data
? BigInt(data.party?.stakingSummary.currentStakeAvailable || '0')
: undefined,
requiredStake: data
? BigInt(data.networkParameter?.value || '0')
: undefined,
};
};
@@ -0,0 +1,52 @@
import { Table } from './table';
export const HowItWorksTable = () => (
<Table
className="bg-none bg-vega-clight-800 dark:bg-vega-cdark-800"
noHeader
noCollapse
columns={[{ name: 'number', className: 'pr-0' }, { name: 'step' }]}
data={[
{
number: (
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
1
</span>
),
step: 'Referrers generate a code assigned to their key via an on chain transaction',
},
{
number: (
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
2
</span>
),
step: 'Anyone with the referral link can apply it to their key(s) of choice via an on chain transaction',
},
{
number: (
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
3
</span>
),
step: 'Discounts are applied automatically during trading based on the key(s) used',
},
{
number: (
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
4
</span>
),
step: 'Referrers earn commission based on a percentage of the taker fees their referees pay',
},
{
number: (
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
5
</span>
),
step: 'The commission is taken from the infrastructure fee, maker fee, and liquidity provider fee, not from the referee',
},
]}
></Table>
);
@@ -0,0 +1,31 @@
import classNames from 'classnames';
import { AnimatedDudeWithWire } from './graphics/dude';
export const LandingBanner = () => {
return (
<div className={classNames('relative mb-20')}>
<div className="">
<div
aria-hidden
className="absolute top-64 right-[220px] md:right-[340px] max-sm:hidden"
>
<AnimatedDudeWithWire />
</div>
<div className="pt-32 sm:w-[50%]">
<h1 className="text-6xl font-alpha calt mb-10">
Earn commission & stake rewards
</h1>
<p className="text-lg mb-10">
Invite friends and earn commission in the form of Vega rewards from
the trading fees they pay. Stake those rewards to earn multipliers
on future rewards.
</p>
<p className="text-lg">
Any friends that join using the code will receive discounts off
trading fees.
</p>
</div>
</div>
</div>
);
};
@@ -0,0 +1,35 @@
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
import { SKY_BACKGROUND } from './constants';
import { Outlet } from 'react-router-dom';
export const Layout = ({
className,
children,
...props
}: HTMLAttributes<HTMLDivElement>) => {
return (
<div
className={classNames(
'max-w-[1440px]',
'mx-auto px-16 md:px-32 pb-32',
'relative z-0',
className
)}
{...props}
>
{children || <Outlet />}
</div>
);
};
export const LayoutWithSky = ({
className,
...props
}: HTMLAttributes<HTMLDivElement>) => {
return (
<div className={classNames('h-full overflow-auto', SKY_BACKGROUND)}>
<Layout className={className} {...props} />
</div>
);
};
@@ -0,0 +1,113 @@
import { Tile } from './tile';
import {
CopyWithTooltip,
Input,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { Button, RainbowButton } from './buttons';
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import type { ReferralData } from './hooks/use-referral';
import { useReferral } from './hooks/use-referral';
import { CreateCodeContainer } from './create-code-form';
import classNames from 'classnames';
const CodeTile = ({
code,
as,
}: {
code: string;
as: 'referrer' | 'referee';
}) => {
return (
<Tile variant="rainbow">
<h3 className="mb-1 text-lg calt">Your referral code</h3>
{as === 'referrer' && (
<p className="mb-3 text-sm text-vega-clight-100 dark:text-vega-cdark-100">
Share this code with friends
</p>
)}
<div className="flex gap-2">
<Input size={1} readOnly value={code} />
<CopyWithTooltip text={code}>
<Button
className="text-sm no-underline"
icon={<VegaIcon name={VegaIconNames.COPY} />}
>
<span>Copy</span>
</Button>
</CopyWithTooltip>
</div>
</Tile>
);
};
export const ReferralStatistics = () => {
const openWalletDialog = useVegaWalletDialogStore(
(store) => store.openVegaWalletDialog
);
const { pubKey } = useVegaWallet();
const { data: referee } = useReferral(pubKey, 'referee');
const { data: referrer } = useReferral(pubKey, 'referrer');
if (!pubKey) {
return (
<div className="text-center">
<RainbowButton variant="border" onClick={() => openWalletDialog()}>
Connect wallet
</RainbowButton>
</div>
);
}
if (referee?.code) {
return <Statistics data={referee} as="referee" />;
}
if (referrer?.code) {
return <Statistics data={referrer} as="referrer" />;
}
return <CreateCodeContainer />;
};
const Statistics = ({
data,
as,
}: {
data: ReferralData;
as: 'referrer' | 'referee';
}) => {
return (
<div
className={classNames('grid grid-cols-1 grid-rows-1 gap-5 mx-auto', {
'md:w-1/2': as === 'referee',
'md:w-2/3': as === 'referrer',
})}
>
<div
className={classNames('grid grid-rows-1 gap-5', {
'grid-cols-2': as === 'referrer',
'grid-cols-1': as === 'referee',
})}
>
{as === 'referrer' && data?.referees && (
<Tile className="py-3 h-full">
<div className="absolute top-1/2 left-1/2 translate-x-[-50%] translate-y-[-50%]">
<h3 className="mb-1 text-6xl text-center">
{data.referees.length}
</h3>
<p className="text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
{data.referees.length === 1
? 'Trader referred'
: 'Total traders referred'}
</p>
</div>
</Tile>
)}
<CodeTile code={data?.code} as={as} />
</div>
</div>
);
};
@@ -0,0 +1,50 @@
import {
TradingAnchorButton,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { HowItWorksTable } from './how-it-works-table';
import { LandingBanner } from './landing-banner';
import { TiersContainer } from './tiers';
import { RainbowTabLink } from './buttons';
import { Outlet } from 'react-router-dom';
import { Routes } from '../../lib/links';
export const Referrals = () => {
return (
<>
<LandingBanner />
<div>
<div className="flex justify-center">
<RainbowTabLink end to={Routes.REFERRALS}>
Your referrals
</RainbowTabLink>
<RainbowTabLink to={Routes.REFERRALS_APPLY_CODE}>
Apply a code
</RainbowTabLink>
</div>
<div className="py-16 border-t border-b border-vega-cdark-500">
<Outlet />
</div>
</div>
<TiersContainer />
<div className="mt-10 mb-5 text-center">
<h2 className="text-2xl">How it works</h2>
</div>
<div className="md:w-[60%] mx-auto">
<HowItWorksTable />
<div className="mt-5">
<TradingAnchorButton
className="mx-auto w-max"
href="https://docs.vega.xyz/"
target="_blank"
>
Read the terms <VegaIcon name={VegaIconNames.OPEN_EXTERNAL} />
</TradingAnchorButton>
</div>
</div>
</>
);
};
@@ -0,0 +1,116 @@
import { Tooltip, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
import { BORDER_COLOR, GRADIENT } from './constants';
type TableColumnDefinition = {
displayName?: string;
name: string;
tooltip?: string;
className?: string;
};
type TableProps = {
columns: TableColumnDefinition[];
data: Record<TableColumnDefinition['name'] | 'className', React.ReactNode>[];
noHeader?: boolean;
noCollapse?: boolean;
};
const INNER_BORDER_STYLE = `border-b ${BORDER_COLOR}`;
export const Table = ({
columns,
data,
noHeader = false,
noCollapse = false,
className,
...props
}: TableProps & HTMLAttributes<HTMLTableElement>) => {
const header = (
<thead className={classNames({ 'max-md:hidden': !noCollapse })}>
<tr>
{columns.map(({ displayName, name, tooltip }) => (
<th
key={name}
col-id={name}
className={classNames(
'px-5 py-3 text-sm text-vega-clight-100 dark:text-vega-cdark-100',
INNER_BORDER_STYLE
)}
>
<span className="flex flex-row gap-2 items-center">
<span>{displayName}</span>
{tooltip ? (
<Tooltip description={tooltip}>
<button className="text-vega-clight-400 dark:text-vega-cdark-400 no-underline decoration-transparent w-[12px] h-[12px] inline-flex">
<VegaIcon size={12} name={VegaIconNames.INFO} />
</button>
</Tooltip>
) : null}
</span>
</th>
))}
</tr>
</thead>
);
return (
<table
className={classNames(
'w-full',
'border-separate border rounded-md border-spacing-0',
BORDER_COLOR,
GRADIENT,
className
)}
{...props}
>
{!noHeader && header}
<tbody>
{data.map((d, i) => (
<tr
key={i}
className={classNames(d['className'] as string, {
'max-md:flex flex-col w-full': !noCollapse,
})}
>
{columns.map(({ name, displayName, className }, j) => (
<td
className={classNames(
'px-5 py-3 text-base',
{
'max-md:flex max-md:flex-col max-md:justify-between':
!noCollapse,
},
INNER_BORDER_STYLE,
{
'border-none': i === data.length - 1 && noCollapse,
'md:border-none': i === data.length - 1,
'max-md:border-none':
i === data.length - 1 && j === columns.length - 1,
},
className
)}
key={`${i}-${name}`}
>
{/** display column name in mobile view */}
{!noCollapse &&
!noHeader &&
displayName &&
displayName.length > 0 && (
<span
aria-hidden
className="md:hidden font-mono text-xs px-0 text-vega-clight-100 dark:text-vega-cdark-100"
>
{displayName}
</span>
)}
<span>{d[name]}</span>
</td>
))}
</tr>
))}
</tbody>
</table>
);
};
@@ -0,0 +1,32 @@
import type { HTMLAttributes } from 'react';
import classNames from 'classnames';
type TagProps = {
color?: 'yellow' | 'green' | 'blue' | 'purple' | 'pink' | 'orange' | 'none';
};
export const Tag = ({
color = 'none',
children,
className,
...props
}: TagProps & HTMLAttributes<HTMLDivElement>) => (
<div
className={classNames(
'mt-3 w-max border rounded-[1rem] py-[0.125rem] px-2 text-xs',
{
'border-vega-yellow-500 text-vega-yellow-500': color === 'yellow',
'border-vega-green-500 text-vega-green-500': color === 'green',
'border-vega-blue-500 text-vega-blue-500': color === 'blue',
'border-vega-purple-500 text-vega-purple-500': color === 'purple',
'border-vega-pink-500 text-vega-pink-500': color === 'pink',
'border-vega-orange-500 text-vega-orange-500': color === 'orange',
'border-vega-clight-100 text-vega-clight-100 dark:border-vega-cdark-100 dark:text-vega-cdark-100':
color === 'none',
},
className
)}
{...props}
>
{children}
</div>
);
@@ -0,0 +1,172 @@
import { getDateTimeFormat } from '@vegaprotocol/utils';
import { useReferralProgram } from './hooks/use-referral-program';
import { Table } from './table';
import classNames from 'classnames';
import { BORDER_COLOR, GRADIENT } from './constants';
import { Tag } from './tag';
import type { ComponentProps } from 'react';
const Loading = ({ variant }: { variant: 'large' | 'inline' }) => (
<div
className={classNames(
'bg-vega-clight-800 dark:bg-vega-cdark-800 rounded-lg animate-pulse',
{
'w-full h-20': variant === 'large',
}
)}
></div>
);
const StakingTier = ({
tier,
label,
referralRewardMultiplier,
minimumStakedTokens,
}: {
tier: number;
label: string;
referralRewardMultiplier: string;
minimumStakedTokens: string;
}) => {
const color: Record<number, ComponentProps<typeof Tag>['color']> = {
1: 'green',
2: 'blue',
3: 'pink',
};
return (
<div
className={classNames(
'overflow-hidden',
'border rounded-md w-full',
BORDER_COLOR
)}
>
<div aria-hidden>
{tier < 4 && (
// eslint-disable-next-line @next/next/no-img-element
<img
src={`/${tier}x.png`}
alt={`${referralRewardMultiplier}x multiplier`}
width={768}
height={400}
className="w-full"
/>
)}
</div>
<div className={classNames('p-3', GRADIENT)}>
<h3 className="mb-3 text-xl">{label}</h3>
<p className="text-base text-vega-clight-100 dark:text-vega-cdark-100">
Stake a minimum of {minimumStakedTokens} $VEGA tokens
</p>
<Tag color={color[tier]}>
Reward multiplier {referralRewardMultiplier}x
</Tag>
</div>
</div>
);
};
export const TiersContainer = () => {
const { benefitTiers, stakingTiers, details, loading } = useReferralProgram();
const ends = details?.endOfProgramTimestamp
? getDateTimeFormat().format(new Date(details.endOfProgramTimestamp))
: undefined;
return (
<>
<div className="flex flex-row items-baseline justify-between mt-10 mb-5">
<h2 className="text-2xl">Referral tiers</h2>
{ends && (
<span className="text-base">
<span className="text-vega-clight-200 dark:text-vega-cdark-200">
Program ends:
</span>{' '}
{ends}
</span>
)}
</div>
<div className="mb-20">
{loading || !benefitTiers || benefitTiers.length === 0 ? (
<Loading variant="large" />
) : (
<TiersTable data={benefitTiers} />
)}
</div>
<div className="flex flex-row items-baseline justify-between mb-5">
<h2 className="text-2xl">Staking multipliers</h2>
</div>
<div className="flex flex-col mb-20 justify-items-stretch md:flex-row gap-5">
{loading || !stakingTiers || stakingTiers.length === 0 ? (
<>
<Loading variant="large" />
<Loading variant="large" />
<Loading variant="large" />
</>
) : (
<StakingTiers data={stakingTiers} />
)}
</div>
</>
);
};
const StakingTiers = ({
data,
}: {
data: ReturnType<typeof useReferralProgram>['stakingTiers'];
}) => (
<>
{data.map(
({ tier, label, referralRewardMultiplier, minimumStakedTokens }, i) => (
<StakingTier
key={i}
tier={tier}
label={label}
referralRewardMultiplier={referralRewardMultiplier}
minimumStakedTokens={minimumStakedTokens}
/>
)
)}
</>
);
const TiersTable = ({
data,
}: {
data: Array<{
tier: number;
commission: string;
discount: string;
volume: string;
}>;
}) => {
return (
<Table
columns={[
{ name: 'tier', displayName: 'Tier' },
{
name: 'commission',
displayName: 'Referrer commission',
tooltip: 'A percentage of commission earned by the referrer',
},
{ name: 'discount', displayName: 'Referrer trading discount' },
{ name: 'volume', displayName: 'Min. trading volume' },
]}
data={data.map((d) => ({
...d,
className: classNames({
'from-vega-pink-400 dark:from-vega-pink-600 to-20% bg-highlight':
d.tier === 1,
'from-vega-purple-400 dark:from-vega-purple-600 to-20% bg-highlight':
d.tier === 2,
'from-vega-blue-400 dark:from-vega-blue-600 to-20% bg-highlight':
d.tier === 3,
'from-vega-orange-400 dark:from-vega-orange-600 to-20% bg-highlight':
d.tier > 3,
}),
}))}
/>
);
};
@@ -0,0 +1,39 @@
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
import { BORDER_COLOR, GRADIENT } from './constants';
type TileProps = {
variant?: 'rainbow' | 'default';
};
export const Tile = ({
variant = 'default',
className,
children,
}: TileProps & HTMLAttributes<HTMLDivElement>) => {
return (
<div
className={classNames(
{
'bg-rainbow p-[0.125rem]': variant === 'rainbow',
[`border-2 ${BORDER_COLOR} p-0`]: variant === 'default',
},
'rounded-lg overflow-hidden relative'
)}
>
<div
className={classNames(
{
'bg-white dark:bg-vega-cdark-900 text-black dark:text-white rounded-[0.35rem] overflow-hidden':
variant === 'rainbow',
},
'p-6',
GRADIENT,
className
)}
>
{children}
</div>
</div>
);
};
@@ -21,14 +21,6 @@ const renderJsx = (route = '/transfer') => {
};
describe('Transfer page', () => {
it('properly rendered', () => {
renderJsx();
expect(
screen.getByRole('heading', { level: 1, name: 'Transfer' })
).toBeInTheDocument();
expect(screen.getByTestId('assetId')).toBeEmptyDOMElement();
});
it('assetId should be passed down', () => {
const assetId = 'foo';
const route = '/transfer?assetId=' + assetId;
@@ -1,5 +1,4 @@
import { useSearchParams } from 'react-router-dom';
import { t } from '@vegaprotocol/i18n';
import { TransferContainer } from '@vegaprotocol/accounts';
import { GetStarted } from '../../components/welcome-dialog';
@@ -8,16 +7,9 @@ export const Transfer = () => {
const assetId = searchParams.get('assetId') || undefined;
return (
<div className="flex justify-center w-full px-8 py-16">
<div className="lg:min-w-[700px] min-w-[300px] max-w-[700px]">
<h1 className="text-4xl uppercase xl:text-5xl font-alpha calt">
{t('Transfer')}
</h1>
<div className="mt-10">
<TransferContainer assetId={assetId} />
<GetStarted />
</div>
</div>
</div>
<>
<TransferContainer assetId={assetId} />
<GetStarted />
</>
);
};
@@ -21,21 +21,10 @@ const renderJsx = (route = '/withdraw') => {
};
describe('Withdraw page', () => {
it('should be properly rendered', () => {
renderJsx();
expect(
screen.getByRole('heading', { level: 1, name: 'Withdraw' })
).toBeInTheDocument();
expect(screen.getByTestId('assetId')).toBeEmptyDOMElement();
});
it('assetId should be passed down', () => {
const assetId = 'foo';
const route = '/withdraw?assetId=' + assetId;
renderJsx(route);
expect(
screen.getByRole('heading', { level: 1, name: 'Withdraw' })
).toBeInTheDocument();
expect(screen.getByTestId('assetId')).toHaveTextContent(assetId);
});
});
@@ -1,5 +1,4 @@
import { useSearchParams } from 'react-router-dom';
import { t } from '@vegaprotocol/i18n';
import { GetStarted } from '../../components/welcome-dialog';
import { WithdrawContainer } from '../../components/withdraw-container';
@@ -7,16 +6,9 @@ export const Withdraw = () => {
const [searchParams] = useSearchParams();
const assetId = searchParams.get('assetId') || undefined;
return (
<div className="flex justify-center w-full px-8 py-16">
<div className="lg:min-w-[700px] min-w-[300px] max-w-[700px]">
<h1 className="text-4xl uppercase xl:text-5xl font-alpha calt">
{t('Withdraw')}
</h1>
<div className="mt-10">
<WithdrawContainer assetId={assetId} />
<GetStarted />
</div>
</div>
</div>
<>
<WithdrawContainer assetId={assetId} />
<GetStarted />
</>
);
};
-1
View File
@@ -1,2 +1 @@
export * from './announcement-banner';
export * from './upgrade-banner';
@@ -1,84 +0,0 @@
import { useMemo, useState } from 'react';
import { gt, prerelease } from 'semver';
import {
ReleasesFeed,
useEnvironment,
useReleases,
Networks,
} from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n';
import {
CopyWithTooltip,
ExternalLink,
Intent,
NotificationBanner,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
// v0.20.12-core-0.71.4 -> v0.20.12
// we need to strip the "core" suffix in order to determine whether a release
// is a pre-release (candidate); example: v.0.21.0-beta.1-core-0.71.4
const parseTagName = (tagName: string) => tagName.replace(/-core-[\d.]+$/i, '');
type UpgradeBannerProps = {
showVersionChange: boolean;
};
export const UpgradeBanner = ({ showVersionChange }: UpgradeBannerProps) => {
const [visible, setVisible] = useState(true);
const { data } = useReleases(ReleasesFeed.FrontEnd);
const { APP_VERSION, VEGA_ENV, VEGA_NETWORKS } = useEnvironment();
const CANONICAL_URL = VEGA_NETWORKS[VEGA_ENV] || 'https://console.vega.xyz';
const newest = useMemo(() => {
if (!APP_VERSION || !data) return undefined;
const newer = data.filter((r) => gt(r.tagName, APP_VERSION));
const valid =
// filter pre-releases on mainnet
VEGA_ENV === Networks.MAINNET
? newer?.filter((r) => !prerelease(parseTagName(r.tagName)))
: newer;
return valid.sort((a, b) => (gt(a.tagName, b.tagName) ? -1 : 1))[0];
}, [APP_VERSION, VEGA_ENV, data]);
if (!visible || !newest) {
return null;
}
return (
<NotificationBanner
intent={Intent.Warning}
onClose={() => {
setVisible(false);
}}
>
<div className="uppercase mb-1">
<ExternalLink href={CANONICAL_URL}>
{t('Upgrade to the latest version of Console')}
</ExternalLink>
</div>
<div data-testid="bookmark-message">
<a
className="underline"
href={newest.htmlUrl}
rel="noreferrer nofollow noopener"
target="_blank"
>
{t("View what's changed")}
</a>{' '}
{t(' or bookmark')}{' '}
<a className="underline" href={CANONICAL_URL}>
{t('console.vega.xyz')}
</a>{' '}
<CopyWithTooltip text={CANONICAL_URL}>
<button title={t('Copy %s', CANONICAL_URL)}>
<span className="sr-only">{t('Copy %s', CANONICAL_URL)}</span>
<VegaIcon size={14} name={VegaIconNames.COPY} />
</button>
</CopyWithTooltip>{' '}
{'to always see the latest version.'}
</div>
</NotificationBanner>
);
};
@@ -38,7 +38,7 @@ export const FundingContainer = ({ marketId }: { marketId: string }) => {
if (edge.node.endTime) {
acc?.push({
endTime: fromNanoSeconds(edge.node.endTime),
fundingRate: Number(edge.node.fundingRate),
fundingRate: Number(edge.node.fundingRate) * 100,
});
}
return acc;
@@ -51,5 +51,11 @@ export const FundingContainer = ({ marketId }: { marketId: string }) => {
if (!data || !values?.rows.length) {
return <Splash> {t('No funding history data')}</Splash>;
}
return <LineChart data={values} theme={theme} />;
return (
<LineChart
data={values}
theme={theme}
priceFormat={(fundingRate) => `${fundingRate.toFixed(4)}%`}
/>
);
};
@@ -0,0 +1,9 @@
import { Outlet } from 'react-router-dom';
export const LayoutCentered = () => {
return (
<div className="mx-auto lg:min-w-[700px] min-w-[300px] max-w-[700px] px-4 lg:px-8 py-8 lg:py-16">
<Outlet />
</div>
);
};
@@ -1,7 +1,6 @@
import { Outlet, Routes, Route } from 'react-router-dom';
import { Sidebar, SidebarContent, useSidebar } from '../sidebar';
import classNames from 'classnames';
import { Routes as AppRoutes } from '../../pages/client-router';
import { MarketHeader } from '../market-header';
import { LiquidityHeader } from '../liquidity-header';
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
@@ -23,8 +22,8 @@ export const LayoutWithSidebar = () => {
<div className={gridClasses}>
<div className="col-span-full">
<Routes>
<Route path={AppRoutes.MARKET} element={<MarketHeader />} />
<Route path={AppRoutes.LIQUIDITY} element={<LiquidityHeader />} />
<Route path="markets/:marketId" element={<MarketHeader />} />
<Route path="liquidity/:marketId" element={<LiquidityHeader />} />
</Routes>
</div>
<main
@@ -12,7 +12,7 @@ import {
Indicator,
KeyValueTable,
KeyValueTableRow,
Link,
Link as UILink,
} from '@vegaprotocol/ui-toolkit';
import BigNumber from 'bignumber.js';
import { useCheckLiquidityStatus } from '@vegaprotocol/liquidity';
@@ -23,6 +23,8 @@ import {
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { DocsLinks } from '@vegaprotocol/environment';
import { Link } from 'react-router-dom';
import { Links } from '../../lib/links';
interface Props {
marketId?: string;
@@ -100,51 +102,51 @@ export const MarketLiquiditySupplied = ({
const description = marketId ? (
<section data-testid="liquidity-supplied-tooltip">
<KeyValueTable>
<KeyValueTableRow>
<span>{t('Supplied stake')}</span>
<span>
{market?.suppliedStake
? addDecimalsFormatNumber(
new BigNumber(market?.suppliedStake).toString(),
assetDecimals
)
: '-'}
</span>
</KeyValueTableRow>
<KeyValueTableRow>
<span>{t('Target stake')}</span>
<span>
{market?.targetStake
? addDecimalsFormatNumber(
new BigNumber(market?.targetStake).toString(),
assetDecimals
)
: '-'}
</span>
</KeyValueTableRow>
</KeyValueTable>
<br />
<div className="flex flex-col gap-2">
<Link
href={`/#/liquidity/${marketId}`}
data-testid="view-liquidity-link"
>
{t('View liquidity provision table')}
</Link>
{DocsLinks && (
<ExternalLink href={DocsLinks.LIQUIDITY} className="mt-2">
{t('Learn about providing liquidity')}
</ExternalLink>
)}
<div className="mb-2">
<KeyValueTable>
<KeyValueTableRow>
<span>{t('Supplied stake')}</span>
<span>
{market?.suppliedStake
? addDecimalsFormatNumber(
new BigNumber(market?.suppliedStake).toString(),
assetDecimals
)
: '-'}
</span>
</KeyValueTableRow>
<KeyValueTableRow>
<span>{t('Target stake')}</span>
<span>
{market?.targetStake
? addDecimalsFormatNumber(
new BigNumber(market?.targetStake).toString(),
assetDecimals
)
: '-'}
</span>
</KeyValueTableRow>
</KeyValueTable>
</div>
{showMessage && (
<p className="mt-4">
<p className="mb-2">
{t(
'The market has sufficient liquidity but there are not enough priced limit orders in the order book, which are required to deploy liquidity commitment pegged orders.'
)}
</p>
)}
<div className="flex flex-col gap-2">
<Link to={Links.LIQUIDITY(marketId)} data-testid="view-liquidity-link">
<UILink>{t('View liquidity provision table')}</UILink>
</Link>
</div>
{DocsLinks && (
<div>
<ExternalLink href={DocsLinks.LIQUIDITY} className="mt-2">
{t('Learn about providing liquidity')}
</ExternalLink>
</div>
)}
</section>
) : (
'-'
@@ -5,7 +5,7 @@ import { MarketSelector } from '../../components/market-selector/market-selector
import { MarketHeaderStats } from '../../client-pages/market/market-header-stats';
import { useMarket, useMarketList } from '@vegaprotocol/markets';
import { useState } from 'react';
import { MarketProductPill } from '@vegaprotocol/datagrid';
import { ProductTypeShortName } from '@vegaprotocol/types';
export const MarketHeader = () => {
const { marketId } = useParams();
@@ -28,11 +28,13 @@ export const MarketHeader = () => {
<HeaderTitle>
<span>
{data.tradableInstrument.instrument.code}
<MarketProductPill
productType={
data.tradableInstrument.instrument.product.__typename
}
/>
<span className="ml-2 text-xs uppercase text-muted">
{' '}
{data.tradableInstrument.instrument.product.__typename &&
ProductTypeShortName[
data.tradableInstrument.instrument.product.__typename
]}{' '}
</span>
</span>
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} size={14} />
</HeaderTitle>
@@ -1,8 +1,8 @@
import classNames from 'classnames';
import { Link } from 'react-router-dom';
import { Routes } from '../../pages/client-router';
import { t } from '@vegaprotocol/i18n';
import { VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
import { Links } from '../../lib/links';
// Make sure these match the available __typename properties on product
export const Product = {
@@ -55,7 +55,7 @@ export const ProductSelector = ({
);
})}
<Link
to={Routes.MARKETS}
to={Links.MARKETS()}
className="flex items-center ml-auto text-sm gap-2"
title={t('See all markets')}
>
@@ -5,6 +5,7 @@ import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { Navbar } from './navbar';
import { useGlobalStore } from '../../stores';
import { ENV, FLAGS } from '@vegaprotocol/environment';
jest.mock('@vegaprotocol/proposals', () => ({
ProtocolUpgradeCountdown: () => null,
@@ -47,6 +48,14 @@ describe('Navbar', () => {
beforeAll(() => {
useGlobalStore.setState({ marketId });
const mockedFLAGS = jest.mocked(FLAGS);
mockedFLAGS.REFERRALS = true;
const mockedENV = jest.mocked(ENV);
mockedENV.VEGA_TOKEN_URL = 'governance';
});
afterAll(() => {
jest.clearAllMocks();
});
it('should be properly rendered', () => {
@@ -57,6 +66,7 @@ describe('Navbar', () => {
['/markets/all', 'Markets'],
[`/markets/${marketId}`, 'Trading'],
['/portfolio', 'Portfolio'],
['/referrals', 'Referrals'],
[expect.stringContaining('governance'), 'Governance'],
];
@@ -89,6 +99,7 @@ describe('Navbar', () => {
['/markets/all', 'Markets'],
[`/markets/${marketId}`, 'Trading'],
['/portfolio', 'Portfolio'],
['/referrals', 'Referrals'],
[expect.stringContaining('governance'), 'Governance'],
];
const links = menu.getAllByRole('link');
+13 -11
View File
@@ -6,6 +6,7 @@ import {
Networks,
DApp,
useLinks,
FLAGS,
} from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n';
import { useGlobalStore } from '../../stores';
@@ -15,7 +16,7 @@ import * as N from '@radix-ui/react-navigation-menu';
import * as D from '@radix-ui/react-dialog';
import { NavLink } from 'react-router-dom';
import { Links, Routes } from '../../pages/client-router';
import { Links } from '../../lib/links';
import classNames from 'classnames';
import { VegaWalletMenu } from '../vega-wallet';
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
@@ -140,12 +141,6 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
const { VEGA_ENV, VEGA_NETWORKS, GITHUB_FEEDBACK_URL } = useEnvironment();
const marketId = useGlobalStore((store) => store.marketId);
// If we have a stored marketId make Trade link go to that market
// otherwise always go to /markets/all
const tradingPath = marketId
? Links[Routes.MARKET](marketId)
: Links[Routes.MARKET]('');
return (
<div className="lg:flex lg:h-full gap-3">
<NavbarList>
@@ -171,20 +166,27 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
<NavbarListDivider />
<NavbarList>
<NavbarItem>
<NavbarLink to={Links[Routes.MARKETS]()} onClick={onClick}>
<NavbarLink to={Links.MARKETS()} onClick={onClick}>
{t('Markets')}
</NavbarLink>
</NavbarItem>
<NavbarItem>
<NavbarLink to={tradingPath} onClick={onClick}>
<NavbarLink to={Links.MARKET(marketId || '')} onClick={onClick}>
{t('Trading')}
</NavbarLink>
</NavbarItem>
<NavbarItem>
<NavbarLink to={Links[Routes.PORTFOLIO]()} onClick={onClick}>
<NavbarLink to={Links.PORTFOLIO()} onClick={onClick}>
{t('Portfolio')}
</NavbarLink>
</NavbarItem>
{FLAGS.REFERRALS && (
<NavbarItem>
<NavbarLink to={Links.REFERRALS()} onClick={onClick}>
{t('Referrals')}
</NavbarLink>
</NavbarItem>
)}
<NavbarItem>
<NavbarLinkExternal to={useLinks(DApp.Governance)()}>
{t('Governance')}
@@ -209,7 +211,7 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
</NavbarSubItem>
)}
<NavbarSubItem>
<NavbarLink to={Links[Routes.DISCLAIMER]()} onClick={onClick}>
<NavbarLink to={Links.DISCLAIMER()} onClick={onClick}>
{t('Disclaimer')}
</NavbarLink>
</NavbarSubItem>
@@ -11,7 +11,7 @@ import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { VegaIconNames } from '@vegaprotocol/ui-toolkit';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { Routes as AppRoutes } from '../../pages/client-router';
import { Routes as AppRoutes } from '../../lib/links';
jest.mock('../node-health', () => ({
NodeHealthContainer: () => <span data-testid="node-health" />,
+28 -22
View File
@@ -13,10 +13,9 @@ import { NodeHealthContainer } from '../node-health';
import { Settings } from '../settings';
import { Tooltip } from '../../components/tooltip';
import { WithdrawContainer } from '../withdraw-container';
import { Routes as AppRoutes } from '../../pages/client-router';
import { GetStarted } from '../welcome-dialog';
import { useVegaWallet, useViewAsDialog } from '@vegaprotocol/wallet';
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
import { GetStarted } from '../welcome-dialog';
export enum ViewType {
Order = 'Order',
@@ -51,6 +50,28 @@ type SidebarView =
type: ViewType.Settings;
};
const MarketSidebarButtons = () => {
const currentRouteId = useGetCurrentRouteId();
return (
<>
<SidebarDivider />
<SidebarButton
view={ViewType.Order}
icon={VegaIconNames.TICKET}
tooltip={t('Order')}
routeId={currentRouteId}
/>
<SidebarButton
view={ViewType.Info}
icon={VegaIconNames.BREAKDOWN}
tooltip={t('Market specification')}
routeId={currentRouteId}
/>
</>
);
};
export const Sidebar = () => {
const currentRouteId = useGetCurrentRouteId();
const navClasses = 'flex lg:flex-col items-center gap-2 lg:gap-4 p-1';
@@ -81,34 +102,19 @@ export const Sidebar = () => {
{/* buttons for specific routes */}
<Routes>
<Route
path={AppRoutes.MARKETS}
path="markets/all"
// render nothing for markets/all, otherwise markets/:marketId will match with markets/all
element={null}
/>
<Route
// render nothing for portfolio
path={AppRoutes.PORTFOLIO}
path="portfolio"
element={null}
/>
<Route path="markets/:marketId" element={<MarketSidebarButtons />} />
<Route
path={AppRoutes.MARKET}
element={
<>
<SidebarDivider />
<SidebarButton
view={ViewType.Order}
icon={VegaIconNames.TICKET}
tooltip={t('Order')}
routeId={currentRouteId}
/>
<SidebarButton
view={ViewType.Info}
icon={VegaIconNames.BREAKDOWN}
tooltip={t('Market specification')}
routeId={currentRouteId}
/>
</>
}
path="liquidity/:marketId"
element={<MarketSidebarButtons />}
/>
</Routes>
</nav>
@@ -15,7 +15,7 @@ import {
useGetOnboardingStep,
useOnboardingStore,
} from './use-get-onboarding-step';
import { Links, Routes } from '../../pages/client-router';
import { Links, Routes } from '../../lib/links';
import { useGlobalStore } from '../../stores';
import { useSidebar, ViewType } from '../sidebar';
@@ -27,8 +27,8 @@ const GetStartedButton = ({ step }: { step: OnboardingStep }) => {
const dismiss = useOnboardingStore((store) => store.dismiss);
const setDialogOpen = useOnboardingStore((store) => store.setDialogOpen);
const marketId = useGlobalStore((store) => store.marketId);
const openVegaWalletDialog = useVegaWalletDialogStore(
(store) => store.openVegaWalletDialog
const setWalletDialogOpen = useOnboardingStore(
(store) => store.setWalletDialogOpen
);
const setViews = useSidebar((store) => store.setViews);
@@ -40,7 +40,7 @@ const GetStartedButton = ({ step }: { step: OnboardingStep }) => {
if (step <= OnboardingStep.ONBOARDING_CONNECT_STEP) {
return (
<TradingButton {...buttonProps} onClick={() => openVegaWalletDialog()}>
<TradingButton {...buttonProps} onClick={() => setWalletDialogOpen(true)}>
{t('Connect')}
</TradingButton>
);
@@ -48,17 +48,18 @@ const GetStartedButton = ({ step }: { step: OnboardingStep }) => {
return (
<TradingAnchorButton
{...buttonProps}
href={Links[Routes.DEPOSIT]()}
href={Links.DEPOSIT()}
onClick={() => setDialogOpen(false)}
>
{t('Deposit')}
</TradingAnchorButton>
);
} else if (step >= OnboardingStep.ONBOARDING_ORDER_STEP) {
const link = marketId ? Links.MARKET(marketId) : Links.HOME();
return (
<TradingAnchorButton
{...buttonProps}
href={marketId ? Links[Routes.MARKET](marketId) : Links[Routes.HOME]()}
href={link}
onClick={() => {
setViews({ type: ViewType.Order }, Routes.MARKET);
dismiss();
@@ -70,7 +71,7 @@ const GetStartedButton = ({ step }: { step: OnboardingStep }) => {
}
return (
<TradingButton {...buttonProps} onClick={() => openVegaWalletDialog()}>
<TradingButton {...buttonProps} onClick={() => setWalletDialogOpen(true)}>
{t('Get started')}
</TradingButton>
);
@@ -1,12 +1,12 @@
import { t } from '@vegaprotocol/i18n';
import { VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
import { Routes } from '../../pages/client-router';
import { Link } from 'react-router-dom';
import { Links } from '../../lib/links';
export const RiskMessage = () => {
return (
<>
<div className="bg-vega-light-100 dark:bg-vega-dark-100 p-6 mb-6">
<div className="p-6 mb-6 bg-vega-light-100 dark:bg-vega-dark-100">
<ul className="list-[square] ml-4">
<li className="mb-1">
{t(
@@ -27,7 +27,7 @@ export const RiskMessage = () => {
{t(
'By using the Vega Console, you acknowledge that you have read and understood the'
)}{' '}
<Link className="underline" to={Routes.DISCLAIMER} target="_blank">
<Link className="underline" to={Links.DISCLAIMER()} target="_blank">
<span className="flex items-center gap-1">
<span>{t('Vega Console Disclaimer')}</span>
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} />
@@ -12,16 +12,20 @@ import { useGlobalStore } from '../../stores';
const ONBOARDING_STORAGE_KEY = 'vega_onboarding';
export const useOnboardingStore = create<{
dialogOpen: boolean;
walletDialogOpen: boolean;
dismissed: boolean;
dismiss: () => void;
setDialogOpen: (isOpen: boolean) => void;
setWalletDialogOpen: (isOpen: boolean) => void;
}>()(
persist(
(set) => ({
dialogOpen: true,
walletDialogOpen: false,
dismissed: false,
dismiss: () => set({ dismissed: true }),
setDialogOpen: (isOpen) => set({ dialogOpen: isOpen }),
setWalletDialogOpen: (isOpen) => set({ walletDialogOpen: isOpen }),
}),
{
name: ONBOARDING_STORAGE_KEY,
@@ -1,7 +1,7 @@
import { t } from '@vegaprotocol/i18n';
import { GetStarted } from './get-started';
import { TradingAnchorButton } from '@vegaprotocol/ui-toolkit';
import { Links, Routes } from '../../pages/client-router';
import { Links } from '../../lib/links';
import { Networks, useEnvironment } from '@vegaprotocol/environment';
import type { ReactNode } from 'react';
import { useTopTradedMarkets } from '../../lib/hooks/use-top-traded-markets';
@@ -15,9 +15,7 @@ export const WelcomeDialogContent = () => {
const { data } = useTopTradedMarkets();
const marketId = data && data[0]?.id;
const link = marketId
? Links[Routes.MARKET](marketId)
: Links[Routes.MARKETS]();
const link = marketId ? Links.MARKET(marketId) : Links.MARKETS();
const lead =
VEGA_ENV === Networks.MAINNET
@@ -3,30 +3,54 @@ import { t } from '@vegaprotocol/i18n';
import { useEnvironment } from '@vegaprotocol/environment';
import { WelcomeDialogContent } from './welcome-dialog-content';
import { useOnboardingStore } from './use-get-onboarding-step';
import { VegaConnectDialog } from '@vegaprotocol/wallet';
import { Connectors } from '../../lib/vega-connectors';
import { RiskMessage } from './risk-message';
export const WelcomeDialog = () => {
const { VEGA_ENV } = useEnvironment();
const dismissed = useOnboardingStore((store) => store.dismissed);
const dialogOpen = useOnboardingStore((store) => store.dialogOpen);
const dismiss = useOnboardingStore((store) => store.dismiss);
const walletDialogOpen = useOnboardingStore(
(store) => store.walletDialogOpen
);
const setWalletDialogOpen = useOnboardingStore(
(store) => store.setWalletDialogOpen
);
const content = walletDialogOpen ? (
<VegaConnectDialog
connectors={Connectors}
riskMessage={<RiskMessage />}
onClose={() => setWalletDialogOpen(false)}
contentOnly
/>
) : (
<WelcomeDialogContent />
);
const onClose = walletDialogOpen ? () => setWalletDialogOpen(false) : dismiss;
const title = walletDialogOpen ? null : (
<span className="font-alpha calt" data-testid="welcome-title">
{t('Console')}{' '}
<span className="text-vega-clight-100 dark:text-vega-cdark-100">
{VEGA_ENV}
</span>
</span>
);
return (
<Dialog
open={dismissed ? false : dialogOpen}
title={
<span className="font-alpha calt" data-testid="welcome-title">
{t('Console')}{' '}
<span className="text-vega-clight-100 dark:text-vega-cdark-100">
{VEGA_ENV}
</span>
</span>
}
title={title}
size="medium"
onChange={() => dismiss()}
onChange={onClose}
intent={Intent.None}
dataTestId="welcome-dialog"
>
<WelcomeDialogContent />
{content}
</Dialog>
);
};
@@ -3,12 +3,10 @@ import { matchRoutes, useLocation } from 'react-router-dom';
export const useGetCurrentRouteId = () => {
const location = useLocation();
const currentRoute = matchRoutes(routerConfig, location);
const lastRoute = currentRoute?.pop();
const matches = matchRoutes(routerConfig, location);
const lastRoute = matches ? matches[matches.length - 1] : undefined;
if (lastRoute) {
const {
route: { id },
} = lastRoute;
const id = lastRoute.route.id;
return id || '';
}
return '';
@@ -1,12 +1,12 @@
import { useNavigate } from 'react-router-dom';
import { useCallback } from 'react';
import { Links, Routes } from '../../pages/client-router';
import { Links } from '../../lib/links';
export const useMarketClickHandler = (replace = false) => {
const navigate = useNavigate();
return (selectedId: string, metaKey?: boolean) => {
const link = Links[Routes.MARKET](selectedId);
const link = Links.MARKET(selectedId);
if (metaKey) {
window.open(`/#${link}`, '_blank');
} else {
+43
View File
@@ -0,0 +1,43 @@
import trimEnd from 'lodash/trimEnd';
// Make all route paths 'absolute' for easier
// href creation
export const Routes = {
HOME: '/',
MARKETS: '/markets/all',
MARKET: '/markets/:marketId',
LIQUIDITY: '/liquidity/:marketId',
PORTFOLIO: '/portfolio',
DISCLAIMER: '/disclaimer',
ASSETS: '/portfolio/assets',
DEPOSIT: '/portfolio/assets/deposit',
WITHDRAW: '/portfolio/assets/withdraw',
TRANSFER: '/portfolio/assets/transfer',
REFERRALS: '/referrals',
REFERRALS_APPLY_CODE: '/referrals/apply-code',
REFERRALS_CREATE_CODE: '/referrals/create-code',
TEAMS: '/teams',
} as const;
type ConsoleLinks = {
[R in keyof typeof Routes]: (...args: string[]) => string;
};
export const Links: ConsoleLinks = {
HOME: () => Routes.HOME,
MARKET: (marketId: string) =>
trimEnd(Routes.MARKET.replace(':marketId', marketId)),
MARKETS: () => Routes.MARKETS,
PORTFOLIO: () => Routes.PORTFOLIO,
LIQUIDITY: (marketId: string) =>
trimEnd(Routes.LIQUIDITY.replace(':marketId', marketId)),
DISCLAIMER: () => Routes.DISCLAIMER,
ASSETS: () => Routes.ASSETS,
DEPOSIT: () => Routes.DEPOSIT,
WITHDRAW: () => Routes.WITHDRAW,
TRANSFER: () => Routes.TRANSFER,
REFERRALS: () => Routes.REFERRALS,
REFERRALS_APPLY_CODE: () => Routes.REFERRALS_APPLY_CODE,
REFERRALS_CREATE_CODE: () => Routes.REFERRALS_CREATE_CODE,
TEAMS: () => Routes.TEAMS,
};
+2 -3
View File
@@ -38,7 +38,7 @@ import { AppLoader, DynamicLoader } from '../components/app-loader';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { activeOrdersProvider } from '@vegaprotocol/orders';
import { useTelemetryApproval } from '../lib/hooks/use-telemetry-approval';
import { AnnouncementBanner, UpgradeBanner } from '../components/banner';
import { AnnouncementBanner } from '../components/banner';
import { Navbar } from '../components/navbar';
import classNames from 'classnames';
import {
@@ -48,8 +48,8 @@ import {
} from '@vegaprotocol/proposals';
import { ViewingBanner } from '../components/viewing-banner';
import { NavHeader } from '../components/navbar/nav-header';
import { Routes as AppRoutes } from './client-router';
import { Telemetry } from '../components/telemetry';
import { Routes as AppRoutes } from '../lib/links';
const DEFAULT_TITLE = t('Welcome to Vega trading!');
@@ -115,7 +115,6 @@ function AppBody({ Component }: AppProps) {
/>
<ProtocolUpgradeInProgressNotification />
<ViewingBanner />
<UpgradeBanner showVersionChange={true} />
</div>
<div data-testid={`pathname-${location.pathname}`}>
<Component />
+100 -85
View File
@@ -1,137 +1,152 @@
import { Suspense } from 'react';
import type { RouteObject } from 'react-router-dom';
import { Outlet, useRoutes } from 'react-router-dom';
import dynamic from 'next/dynamic';
import { Navigate, Outlet, useRoutes } from 'react-router-dom';
import { lazy, Suspense } from 'react';
import { t } from '@vegaprotocol/i18n';
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
import trimEnd from 'lodash/trimEnd';
import { LayoutWithSidebar } from '../components/layouts';
import { LayoutCentered } from '../components/layouts/layout-centered';
import { Home } from '../client-pages/home';
import { Liquidity } from '../client-pages/liquidity';
import { MarketsPage } from '../client-pages/markets';
import { Disclaimer } from '../client-pages/disclaimer';
import { Assets } from '../client-pages/assets';
import { Deposit } from '../client-pages/deposit';
import { Withdraw } from '../client-pages/withdraw';
import { Transfer } from '../client-pages/transfer';
import { Routes } from '../lib/links';
import { LayoutWithSky } from '../client-pages/referrals/layout';
import { Referrals } from '../client-pages/referrals/referrals';
import { ReferralStatistics } from '../client-pages/referrals/referral-statistics';
import { ApplyCodeForm } from '../client-pages/referrals/apply-code-form';
import { CreateCodeContainer } from '../client-pages/referrals/create-code-form';
import { NotFound as ReferralNotFound } from '../client-pages/referrals/error-boundary';
import { compact } from 'lodash';
import { FLAGS } from '@vegaprotocol/environment';
const LazyHome = dynamic(() => import('../client-pages/home'), {
ssr: false,
});
// These must remain dynamically imported as pennant cannot be compiled by nextjs due to ESM
// Using dynamic imports is a workaround for this until pennant is published as ESM
const MarketPage = lazy(() => import('../client-pages/market'));
const Portfolio = lazy(() => import('../client-pages/portfolio'));
const LazyLiquidity = dynamic(() => import('../client-pages/liquidity'), {
ssr: false,
});
const NotFound = () => (
<Splash>
<p>{t('Page not found')}</p>
</Splash>
);
const LazyMarkets = dynamic(() => import('../client-pages/markets'), {
ssr: false,
});
const LazyMarket = dynamic(() => import('../client-pages/market'), {
ssr: false,
});
const LazyPortfolio = dynamic(() => import('../client-pages/portfolio'), {
ssr: false,
});
const LazyDisclaimer = dynamic(() => import('../client-pages/disclaimer'), {
ssr: false,
});
export enum Routes {
HOME = '/',
MARKET = '/markets/:marketId',
MARKETS = '/markets/all',
PORTFOLIO = '/portfolio',
LIQUIDITY = '/liquidity/:marketId',
DISCLAIMER = '/disclaimer',
DEPOSIT = '/deposit',
WITHDRAW = '/withdraw',
TRANSFER = '/transfer',
}
type ConsoleLinks = { [r in Routes]: (...args: string[]) => string };
export const Links: ConsoleLinks = {
[Routes.HOME]: () => Routes.HOME,
[Routes.MARKET]: (marketId: string) =>
trimEnd(Routes.MARKET.replace(':marketId', marketId)),
[Routes.MARKETS]: () => Routes.MARKETS,
[Routes.PORTFOLIO]: () => Routes.PORTFOLIO,
[Routes.LIQUIDITY]: (marketId: string) =>
trimEnd(Routes.LIQUIDITY.replace(':marketId', marketId)),
[Routes.DISCLAIMER]: () => Routes.DISCLAIMER,
[Routes.DEPOSIT]: () => Routes.DEPOSIT,
[Routes.WITHDRAW]: () => Routes.WITHDRAW,
[Routes.TRANSFER]: () => Routes.TRANSFER,
};
export const routerConfig: RouteObject[] = [
export const routerConfig: RouteObject[] = compact([
// Pages that don't use the LayoutWithSidebar must come first
// to ensure they are matched before the catch all route '/*'
{
path: 'disclaimer',
element: <LayoutCentered />,
id: Routes.DISCLAIMER,
children: [{ index: true, element: <Disclaimer /> }],
},
// Referrals routing (the pages should be available if the feature flag is on)
FLAGS.REFERRALS
? {
path: Routes.REFERRALS,
element: <LayoutWithSky />,
children: [
{
element: <Referrals />,
children: [
{
index: true,
element: <ReferralStatistics />,
},
{
path: Routes.REFERRALS_CREATE_CODE,
element: <CreateCodeContainer />,
},
{
path: Routes.REFERRALS_APPLY_CODE,
element: <ApplyCodeForm />,
},
],
},
{
path: '*',
element: <ReferralNotFound />,
},
],
}
: undefined,
// All other pages will use the sidebar
{
path: '/*',
element: <LayoutWithSidebar />,
children: [
// all pages that require the Layout component (Sidebar)
{
index: true,
element: <LazyHome />,
element: <Home />,
id: Routes.HOME,
},
{
path: 'markets',
element: <Outlet />,
children: [
{
index: true,
element: <Navigate to="all" />,
},
{
path: 'all',
element: <LazyMarkets />,
element: <MarketsPage />,
id: Routes.MARKETS,
},
{
path: ':marketId',
element: <LazyMarket />,
element: <MarketPage />,
id: Routes.MARKET,
},
],
},
{
path: 'portfolio',
element: <LazyPortfolio />,
id: Routes.PORTFOLIO,
},
{
path: 'liquidity',
element: <Outlet />,
children: [
{
path: ':marketId',
element: <LazyLiquidity />,
id: Routes.LIQUIDITY,
index: true,
element: <Portfolio />,
id: Routes.PORTFOLIO,
},
{
path: 'assets',
element: <Assets />,
id: Routes.ASSETS,
children: [
{ index: true, element: <Navigate to="deposit" /> },
{ path: 'deposit', element: <Deposit />, id: Routes.DEPOSIT },
{ path: 'withdraw', element: <Withdraw />, id: Routes.WITHDRAW },
{ path: 'transfer', element: <Transfer />, id: Routes.TRANSFER },
],
},
],
},
{
path: 'liquidity/:marketId',
element: <Liquidity />,
id: Routes.LIQUIDITY,
},
// NotFound page is here so its caught within parent '/*' route
{
path: '*',
element: <NotFound />,
},
],
},
{
path: Routes.DISCLAIMER,
element: <LazyDisclaimer />,
},
{ path: Routes.DEPOSIT, element: <Deposit /> },
{ path: Routes.WITHDRAW, element: <Withdraw /> },
{ path: Routes.TRANSFER, element: <Transfer /> },
{
path: '*',
element: (
<Splash>
<p>{t('Not found')}</p>
</Splash>
),
},
];
]);
export const ClientRouter = () => {
const routes = useRoutes(routerConfig);
return (
<Suspense
fallback={
<div className="flex items-center justify-center w-full h-full">
<Splash>
<Loader />
</div>
</Splash>
}
>
{routes}
+2 -2
View File
@@ -3,8 +3,8 @@ import { useUpdateNetworkParametersToasts } from '@vegaprotocol/proposals';
import { useVegaTransactionToasts } from '@vegaprotocol/web3';
import { useEthereumTransactionToasts } from '@vegaprotocol/web3';
import { useEthereumWithdrawApprovalsToasts } from '@vegaprotocol/web3';
import { Routes } from './client-router';
import { useReadyToWithdrawalToasts } from '@vegaprotocol/withdraws';
import { Links } from '../lib/links';
export const ToastsManager = () => {
useUpdateNetworkParametersToasts();
@@ -12,7 +12,7 @@ export const ToastsManager = () => {
useEthereumTransactionToasts();
useEthereumWithdrawApprovalsToasts();
useReadyToWithdrawalToasts({
withdrawalsLink: `${Routes.PORTFOLIO}`,
withdrawalsLink: Links.PORTFOLIO(),
});
const toasts = useToasts((store) => store.toasts);
Binary file not shown.

After

Width:  |  Height:  |  Size: 614 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 KiB

+31 -1
View File
@@ -13,7 +13,37 @@ module.exports = {
],
darkMode: 'class',
theme: {
extend: theme,
extend: {
...theme,
colors: {
transparent: 'transparent',
current: 'currentColor',
...theme.colors,
},
backgroundImage: {
...theme.backgroundImage,
rainbow:
'linear-gradient(103.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
'rainbow-shifted':
'linear-gradient(103.47deg, #0075FF 1.68%, #8028FF 47.49%, #FF077F 100%)',
highlight:
'linear-gradient(170deg, var(--tw-gradient-from), transparent var(--tw-gradient-to-position))',
},
keyframes: {
...theme.keyframes,
shake: {
'0%': { transform: 'translateX(0)' },
'25%': { transform: 'translateX(5px)' },
'50%': { transform: 'translateX(-5px)' },
'75%': { transform: 'translateX(5px)' },
'100%': { transform: 'translateX(0)' },
},
},
animation: {
...theme.animation,
shake: 'shake 200ms linear',
},
},
},
plugins: [vegaCustomClasses],
};
+7 -1
View File
@@ -312,7 +312,6 @@ export const AccountTable = ({
]);
const data = rowData?.filter((data) => data.asset.id !== pinnedAsset?.id);
return (
<AgGrid
{...props}
@@ -321,6 +320,13 @@ export const AccountTable = ({
rowData={data}
defaultColDef={defaultColDef}
columnDefs={colDefs}
overlayNoRowsTemplate={
// account for the pinned asset is filtered out to prevent duplicate
// data in the pinned row and the main table rows. AgGrid will not
// consider the pinned row when determining whether to show the no
// rows template or not so we need to override it
rowData?.length ? '<span />' : props.overlayNoRowsTemplate
}
getRowHeight={getPinnedAssetRowHeight}
pinnedTopRowData={pinnedRow ? [pinnedRow] : undefined}
/>
@@ -13,7 +13,7 @@ import { createLog } from './logging';
import { getMarkets } from './get-markets';
import { createWalletClient } from './wallet-client';
import { createEthereumWallet } from './ethereum-wallet';
import { ASSET_ID_FOR_MARKET } from './contants';
import { ASSET_ID_FOR_MARKET } from './constants';
const log = createLog('create-market');
@@ -4,7 +4,7 @@ import { createLog } from './logging';
import type { ProposalSubmissionBody } from '@vegaprotocol/wallet';
import { getProposal } from './get-proposal';
import { sendVegaTx } from './wallet-client';
import { ASSET_ID_FOR_MARKET, ASSET_SYMBOL } from './contants';
import { ASSET_ID_FOR_MARKET, ASSET_SYMBOL } from './constants';
const log = createLog('propose-market');
+5 -1
View File
@@ -29,4 +29,8 @@ const hasNotFoundGraphQLErrors = (errors: GraphQLErrors, path?: string[]) => {
};
export const marketDataErrorPolicyGuard = (errors: GraphQLErrors) =>
errors.every((e) => e.message.match(/no market data for market:/i));
errors.every(
(e) =>
e.message.match(/no market data for market:/i) ||
e.message.match(/Conditions list is empty/)
);
@@ -414,6 +414,9 @@ function compileFeatureFlags(): FeatureFlags {
process.env['NX_METAMASK_SNAPS']
) as string
),
REFERRALS: TRUTHY.includes(
windowOrDefault('NX_REFERRALS', process.env['NX_REFERRALS']) as string
),
};
const EXPLORER_FLAGS = {
EXPLORER_ASSETS: TRUTHY.includes(
+3 -3
View File
@@ -1,7 +1,7 @@
import trim from 'lodash/trim';
import { useCallback } from 'react';
import { Networks } from '../types';
import { useEnvironment } from './use-environment';
import { ENV, useEnvironment } from './use-environment';
import { stripFullStops } from '@vegaprotocol/utils';
const VEGA_DOCS_URL =
@@ -84,8 +84,7 @@ export const DocsLinks = VEGA_DOCS_URL
: undefined;
export const useLinks = (dapp: DApp, network?: Net) => {
const { VEGA_ENV, VEGA_EXPLORER_URL, VEGA_TOKEN_URL, VEGA_CONSOLE_URL } =
useEnvironment();
const { VEGA_ENV, VEGA_EXPLORER_URL, VEGA_TOKEN_URL, VEGA_CONSOLE_URL } = ENV;
const fallback = {
[DApp.Explorer]: VEGA_EXPLORER_URL,
[DApp.Governance]: VEGA_TOKEN_URL,
@@ -175,4 +174,5 @@ export const ExternalLinks = {
export const TokenStaticLinks = {
PROPOSAL_PAGE: ':tokenUrl/proposals/:proposalId',
UPDATE_PROPOSAL_PAGE: ':tokenUrl/proposals/propose/update-market',
ASSOCIATE: 'token/associate',
};
+1
View File
@@ -23,6 +23,7 @@ export type CosmicElevatorFlags = Pick<
| 'SUCCESSOR_MARKETS'
| 'PRODUCT_PERPETUALS'
| 'METAMASK_SNAPS'
| 'REFERRALS'
>;
export type Configuration = z.infer<typeof tomlConfigSchema>;
export const CUSTOM_NODE_KEY = 'custom' as const;
@@ -78,6 +78,7 @@ const COSMIC_ELEVATOR_FLAGS = {
ICEBERG_ORDERS: z.optional(z.boolean()),
PRODUCT_PERPETUALS: z.optional(z.boolean()),
METAMASK_SNAPS: z.optional(z.boolean()),
REFERRALS: z.optional(z.boolean()),
};
const EXPLORER_FLAGS = {
@@ -157,6 +157,12 @@ query MarketInfo($marketId: ID!) {
scalingFactor
}
}
liquiditySLAParameters {
priceRange
commitmentMinTimeFraction
performanceHysteresisEpochs
slaCompetitionFactor
}
tradableInstrument {
instrument {
id
File diff suppressed because one or more lines are too long
@@ -14,6 +14,7 @@ import {
Link as UILink,
Splash,
AccordionItem,
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import { generatePath, Link } from 'react-router-dom';
@@ -29,6 +30,8 @@ import {
KeyDetailsInfoPanel,
LiquidityInfoPanel,
LiquidityMonitoringParametersInfoPanel,
LiquidityPriceRangeInfoPanel,
LiquiditySLAParametersInfoPanel,
MarketPriceInfoPanel,
MarketVolumeInfoPanel,
MetadataInfoPanel,
@@ -265,6 +268,26 @@ export const MarketInfoAccordion = ({
title={t('Liquidity monitoring parameters')}
content={<LiquidityMonitoringParametersInfoPanel market={market} />}
/>
<AccordionItem
itemId="liquidity-price-range"
title={t('Liquidity price range')}
content={<LiquidityPriceRangeInfoPanel market={market} />}
/>
<AccordionItem
itemId="liquidity-sla-parameters"
title={
<span>
<Tooltip
description={t(
'SLA protocol = a part of the Vega protocol that creates similar incentives within the decentralised system to those achieved by a Service Level Agreement between parties in traditional finance. The SLA protocol involves no discussion, agreement, or contracts between parties but instead relies upon rules and an economic mechanism implemented in code running on the network'
)}
>
<span>{t('Liquidity SLA protocol')}</span>
</Tooltip>
</span>
}
content={<LiquiditySLAParametersInfoPanel market={market} />}
/>
<AccordionItem
itemId="liquidity"
title={t('Liquidity')}
@@ -1,6 +1,7 @@
import {
makeDataProvider,
makeDerivedDataProvider,
marketDataErrorPolicyGuard,
} from '@vegaprotocol/data-provider';
import type {
MarketInfoQuery,
@@ -30,6 +31,7 @@ export const marketInfoProvider = makeDataProvider<
>({
query: MarketInfoDocument,
getData,
errorPolicyGuard: marketDataErrorPolicyGuard,
});
export const marketInfoWithDataProvider = makeDerivedDataProvider<
@@ -15,6 +15,7 @@ import {
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import {
addDecimalsFormatNumber,
formatNumber,
formatNumberPercentage,
getDateTimeFormat,
@@ -58,6 +59,10 @@ import { useSuccessorMarketProposalDetailsQuery } from '@vegaprotocol/proposals'
import { getQuoteName, getAsset } from '../../market-utils';
import classNames from 'classnames';
import compact from 'lodash/compact';
import {
NetworkParams,
useNetworkParams,
} from '@vegaprotocol/network-parameters';
import type { DataSourceFragment } from './__generated__/MarketInfo';
import { formatDuration } from 'date-fns';
@@ -654,6 +659,193 @@ export const LiquidityMonitoringParametersInfoPanel = ({
return <MarketInfoTable data={marketData} parentData={parentMarketData} />;
};
export const LiquidityPriceRangeInfoPanel = ({
market,
parentMarket,
}: MarketInfoProps) => {
const marketLpPriceRange = market.liquiditySLAParameters?.priceRange;
const parentMarketLpPriceRange =
parentMarket?.liquiditySLAParameters?.priceRange;
const quoteUnit =
('quoteName' in market.tradableInstrument.instrument.product &&
market?.tradableInstrument.instrument.product?.quoteName) ||
'';
const parentQuoteUnit =
(parentMarket &&
'quoteName' in parentMarket.tradableInstrument.instrument.product &&
parentMarket?.tradableInstrument.instrument.product?.quoteName) ||
'';
const liquidityPriceRange =
marketLpPriceRange &&
formatNumberPercentage(new BigNumber(marketLpPriceRange).times(100));
const parentLiquidityPriceRange =
parentMarket && parentMarketLpPriceRange
? formatNumberPercentage(
new BigNumber(parentMarketLpPriceRange).times(100)
)
: null;
const { data } = useDataProvider({
dataProvider: marketDataProvider,
variables: { marketId: market.id },
});
const { data: parentMarketData } = useDataProvider({
dataProvider: marketDataProvider,
variables: { marketId: parentMarket?.id || '' },
skip: !parentMarket,
});
let parentData;
if (parentMarket && parentMarketData && quoteUnit === parentQuoteUnit) {
parentData = {
liquidityPriceRange: `${parentLiquidityPriceRange} of mid price`,
lowestPrice:
parentMarketLpPriceRange &&
parentMarketData?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.minus(parentMarketLpPriceRange)
.times(parentMarketData.midPrice)
.toString(),
parentMarket.decimalPlaces
)} ${quoteUnit}`,
highestPrice:
parentMarketLpPriceRange &&
parentMarketData?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.plus(parentMarketLpPriceRange)
.times(parentMarketData.midPrice)
.toString(),
parentMarket.decimalPlaces
)} ${quoteUnit}`,
};
}
return (
<>
<p className="text-xs mb-2 border-l-2 pl-2">
{`For liquidity orders to count towards a commitment, they must be
within the liquidity monitoring bounds.`}
</p>
<MarketInfoTable
data={{
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
lowestPrice:
marketLpPriceRange &&
data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.minus(marketLpPriceRange)
.times(data.midPrice)
.toString(),
market.decimalPlaces
)} ${quoteUnit}`,
highestPrice:
marketLpPriceRange &&
data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.plus(marketLpPriceRange)
.times(data.midPrice)
.toString(),
market.decimalPlaces
)} ${quoteUnit}`,
}}
parentData={parentData}
/>
<p className="text-xs mb-2 border-l-2 pl-2 mt-2">
{`The liquidity price range is a ${liquidityPriceRange} difference from the mid
price.`}
</p>
</>
);
};
const fromNanoSecondsToSeconds = (nanoseconds: number | string) =>
t('%ss', [new BigNumber(nanoseconds).dividedBy(1e9).toString()]);
export const LiquiditySLAParametersInfoPanel = ({
market,
parentMarket,
}: MarketInfoProps) => {
const marketData = {
performanceHysteresisEpochs:
market.liquiditySLAParameters?.performanceHysteresisEpochs,
SLACompetitionFactor:
market.liquiditySLAParameters?.slaCompetitionFactor &&
formatNumberPercentage(
new BigNumber(
market.liquiditySLAParameters?.slaCompetitionFactor
).times(100)
),
commitmentMinimumTimeFraction:
market.liquiditySLAParameters?.commitmentMinTimeFraction &&
formatNumberPercentage(
new BigNumber(
market.liquiditySLAParameters?.commitmentMinTimeFraction
).times(100)
),
};
const parentMarketData = parentMarket
? {
performanceHysteresisEpochs:
parentMarket.liquiditySLAParameters?.performanceHysteresisEpochs,
slaCompetitionFactor:
parentMarket.liquiditySLAParameters?.slaCompetitionFactor,
commitmentMinimumTimeFraction:
parentMarket.liquiditySLAParameters?.commitmentMinTimeFraction,
}
: undefined;
const { params: networkParams } = useNetworkParams([
NetworkParams.market_liquidity_bondPenaltyParameter,
NetworkParams.market_liquidity_nonPerformanceBondPenaltySlope,
NetworkParams.market_liquidity_sla_nonPerformanceBondPenaltyMax,
NetworkParams.market_liquidity_maximumLiquidityFeeFactorLevel,
NetworkParams.market_liquidity_stakeToCcyVolume,
NetworkParams.validators_epoch_length,
NetworkParams.market_liquidity_earlyExitPenalty,
NetworkParams.market_liquidity_probabilityOfTrading_tau_scaling,
NetworkParams.market_liquidity_minimum_probabilityOfTrading_lpOrders,
NetworkParams.market_liquidity_feeCalculationTimeStep,
]);
const marketNetworkParamData = {
epochLength: networkParams['validators_epoch_length'],
bondPenaltyParameter:
networkParams['market_liquidity_bondPenaltyParameter'],
nonPerformanceBondPenaltySlope:
networkParams['market_liquidity_nonPerformanceBondPenaltySlope'],
nonPerformanceBondPenaltyMax:
networkParams['market_liquidity_sla_nonPerformanceBondPenaltyMax'],
maximumLiquidityFeeFactorLevel:
networkParams['market_liquidity_maximumLiquidityFeeFactorLevel'],
stakeToCCYVolume: networkParams['market_liquidity_stakeToCcyVolume'],
earlyExitPenalty: networkParams['market_liquidity_earlyExitPenalty'],
probabilityOfTradingTauScaling:
networkParams['market_liquidity_probabilityOfTrading_tau_scaling'],
minimumProbabilityOfTradingLPOrders:
networkParams['market_liquidity_minimum_probabilityOfTrading_lpOrders'],
feeCalculationTimeStep:
networkParams['market_liquidity_feeCalculationTimeStep'] &&
fromNanoSecondsToSeconds(
networkParams['market_liquidity_feeCalculationTimeStep']
),
};
return (
<>
<MarketInfoTable data={marketData} parentData={parentMarketData} />
<MarketInfoTable data={marketNetworkParamData} unformatted={true} />
</>
);
};
export const LiquidityInfoPanel = ({ market, children }: MarketInfoProps) => {
const asset = getAsset(market);
const { data } = useDataProvider({
@@ -101,6 +101,12 @@ export const marketInfoQuery = (
},
__typename: 'LiquidityMonitoringParameters',
},
liquiditySLAParameters: {
priceRange: '0.95',
commitmentMinTimeFraction: '0.5',
performanceHysteresisEpochs: 4,
slaCompetitionFactor: '0.5',
},
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
@@ -106,4 +106,43 @@ export const tooltipMapping: Record<string, ReactNode> = {
insurancePoolFraction: t(
'The fraction of the insurance pool balance that is carried over from the parent market to the successor.'
),
commitmentMinimumTimeFraction: t(
`Specifies the minimum fraction of time LPs must spend 'on the book' providing their committed liquidity. This is a market parameter.`
),
feeCalculationTimeStep: t(
'How often the quality of liquidity supplied by each liquidity provider is evaluated and the fees arising from that period are earmarked for specific providers. This is a market parameter. '
),
performanceHysteresisEpochs: t(
'Number of epochs over which past performance will continue to affect rewards. This is a market parameter.'
),
SLACompetitionFactor: t(
`Maximum fraction of an LP's accrued fees that an LP would lose to liquidity providers that achieved a higher SLA performance than them. This is a market parameter. `
),
bondPenaltyParameter: t(
'Used to calculate the penalty to liquidity providers when they cannot support their open position with the assets in their margin and general accounts. This is a network parameter.'
),
nonPerformanceBondPenaltySlope: t(
'A sliding penalty for how much an LP bond is slashed if an LP fails to reach the minimum SLA. This is a network parameter.'
),
nonPerformanceBondPenaltyMax: t(
`The maximum amount, as a fraction, that an LP's bond can be slashed by if they fail to reach the minimum SLA. This is a network parameter.`
),
maximumLiquidityFeeFactorLevel: t(
'Maximum value that a proposed fee amount can be, which is submitted as part of the LP commitment transaction. Note that a value of 0.05 = 5%. This is a network parameter.'
),
stakeToCCYVolume: t(
`Multiplier used to translate an LP's commitment amount to their liquidity obligation. This is a network parameter.`
),
epochLength: t(
'How long an epoch is. LP rewards from liquidity fees are paid out once per epoch. How much they receive depends on whether they met the liquidity SLA and their previous performance in recent epochs. This is a network parameter.'
),
earlyExitPenalty: t(
`How much an LP forfeits of their bond if they reduce their commitment while the market is below target stake, expressed as a factor. If set to 0 there is no penalty for early exit. If set to 1 an LP's entire bond is forfeited when an LP removes their full commitment. This is a network parameter.`
),
probabilityOfTradingTauScaling: t(
`Determines how the probability of trading is scaled from the risk model, and is used to measure the relative competitiveness of an LP's supplied volume. This is a network parameter.`
),
minimumProbabilityOfTradingLPOrders: t(
'The lower bound for the probability of trading calculation, used to measure liquidity available on a market to determine if LPs are meeting their commitment. This is a network parameter.'
),
};
+2
View File
@@ -2,6 +2,7 @@ import { useYesterday } from '@vegaprotocol/react-helpers';
import {
makeDataProvider,
makeDerivedDataProvider,
marketDataErrorPolicyGuard,
useDataProvider,
} from '@vegaprotocol/data-provider';
import type {
@@ -43,6 +44,7 @@ export const marketsProvider = makeDataProvider<
query: MarketsDocument,
getData,
fetchPolicy: 'cache-first',
errorPolicyGuard: marketDataErrorPolicyGuard,
});
export const marketsMapProvider = makeDerivedDataProvider<

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