diff --git a/README.md b/README.md index c2176f202..4f8dadac9 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ To run tests locally using your own wallets you can add the following environmen In CI linting, formatting and also run. These checks can be seen in the [CI workflow file](.github/workflows//test.yml). - To fix linting errors locally run `yarn nx lint --fix` -- To fix formatting errors local run `yarn nx format` +- To fix formatting errors local run `yarn nx format:write` - For either command you may use `--all` to run across the entire repository ### Further help with Nx diff --git a/apps/explorer-e2e/tsconfig.json b/apps/explorer-e2e/tsconfig.json index b3c03f183..7ebd6b0de 100644 --- a/apps/explorer-e2e/tsconfig.json +++ b/apps/explorer-e2e/tsconfig.json @@ -10,7 +10,7 @@ "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, + "noPropertyAccessFromIndexSignature": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true }, diff --git a/apps/explorer/src/app/app.tsx b/apps/explorer/src/app/app.tsx index dc60cb1d8..9cdd09834 100644 --- a/apps/explorer/src/app/app.tsx +++ b/apps/explorer/src/app/app.tsx @@ -2,7 +2,10 @@ import { useState, useEffect, useMemo } from 'react'; import { useLocation } from 'react-router-dom'; import { ApolloProvider } from '@apollo/client'; import { ThemeContext } from '@vegaprotocol/react-helpers'; -import { useThemeSwitcher } from '@vegaprotocol/react-helpers'; +import { + useThemeSwitcher, + EnvironmentProvider, +} from '@vegaprotocol/react-helpers'; import { createClient } from './lib/apollo-client'; import { Nav } from './components/nav'; import { Header } from './components/header'; @@ -23,27 +26,29 @@ function App() { const client = useMemo(() => createClient(DATA_SOURCES.dataNodeUrl), []); return ( - - - -
-
-
-
- - - + + + + ); } diff --git a/apps/explorer/tsconfig.json b/apps/explorer/tsconfig.json index d5aff9e2e..e4e8e4ee8 100644 --- a/apps/explorer/tsconfig.json +++ b/apps/explorer/tsconfig.json @@ -11,8 +11,7 @@ "noPropertyAccessFromIndexSignature": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, - "lib": ["es5", "es6", "dom", "dom.iterable"], - "resolveJsonModule": true + "lib": ["es5", "es6", "dom", "dom.iterable"] }, "files": [], "include": [], diff --git a/apps/simple-trading-app/src/app/app.tsx b/apps/simple-trading-app/src/app/app.tsx index 4ed571a78..aeb99149f 100644 --- a/apps/simple-trading-app/src/app/app.tsx +++ b/apps/simple-trading-app/src/app/app.tsx @@ -9,6 +9,7 @@ import { VegaManageDialog, VegaWalletProvider, } from '@vegaprotocol/wallet'; +import { EnvironmentProvider } from '@vegaprotocol/react-helpers'; import { VegaWalletConnectButton } from './components/vega-wallet-connect-button'; import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit'; import { Connectors } from './lib/vega-connectors'; @@ -37,51 +38,53 @@ function App() { }, [location]); return ( - - - - -
-
- - -
- - setVegaWallet((x) => ({ ...x, connect: open })) - } - setManageDialog={(open) => - setVegaWallet((x) => ({ ...x, manage: open })) - } + + + + + +
+
+ - + +
+ + setVegaWallet((x) => ({ ...x, connect: open })) + } + setManageDialog={(open) => + setVegaWallet((x) => ({ ...x, manage: open })) + } + /> + +
+ +
+ + + setVegaWallet((x) => ({ ...x, connect: open })) + } + /> + + setVegaWallet((x) => ({ ...x, manage: open })) + } + />
- -
- - - setVegaWallet((x) => ({ ...x, connect: open })) - } - /> - - setVegaWallet((x) => ({ ...x, manage: open })) - } - /> -
- - - - + + + + + ); } diff --git a/apps/simple-trading-app/src/app/components/deal-ticket/deal-ticket-steps.tsx b/apps/simple-trading-app/src/app/components/deal-ticket/deal-ticket-steps.tsx index a68270fc2..1f102cabe 100644 --- a/apps/simple-trading-app/src/app/components/deal-ticket/deal-ticket-steps.tsx +++ b/apps/simple-trading-app/src/app/components/deal-ticket/deal-ticket-steps.tsx @@ -1,40 +1,54 @@ import * as React from 'react'; -import type { FormEvent } from 'react'; +import { useForm, Controller } from 'react-hook-form'; import Box from '@mui/material/Box'; import { Stepper } from '../stepper'; -import type { Order, DealTicketQuery_market } from '@vegaprotocol/deal-ticket'; +import type { DealTicketQuery_market, Order } from '@vegaprotocol/deal-ticket'; +import { Button, InputError } from '@vegaprotocol/ui-toolkit'; import { ExpirySelector, SideSelector, - SubmitButton, TimeInForceSelector, TypeSelector, - useOrderState, + getDefaultOrder, + useOrderValidation, useOrderSubmit, - DealTicketLimitForm, - DealTicketMarketForm, + DealTicketAmount, } from '@vegaprotocol/deal-ticket'; import { - OrderSide, OrderTimeInForce, OrderType, VegaTxStatus, } from '@vegaprotocol/wallet'; -import { addDecimal } from '@vegaprotocol/react-helpers'; +import { t, addDecimal, toDecimal } from '@vegaprotocol/react-helpers'; interface DealTicketMarketProps { market: DealTicketQuery_market; } -const DEFAULT_ORDER: Order = { - type: OrderType.Market, - side: OrderSide.Buy, - size: '1', - timeInForce: OrderTimeInForce.IOC, -}; - export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { - const [order, updateOrder] = useOrderState(DEFAULT_ORDER); + const { + register, + control, + handleSubmit, + watch, + formState: { errors }, + } = useForm({ + mode: 'onChange', + defaultValues: getDefaultOrder(market), + }); + + const step = toDecimal(market.positionDecimalPlaces); + const orderType = watch('type'); + const orderTimeInForce = watch('timeInForce'); + + const invalidText = useOrderValidation({ + step, + market, + orderType, + orderTimeInForce, + fieldErrors: errors, + }); + const { submit, transaction } = useOrderSubmit(market); const transactionStatus = @@ -43,39 +57,14 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { ? 'pending' : 'default'; - let ticket = null; - - if (order.type === OrderType.Market) { - ticket = ( - updateOrder({ size })} - price={ - market.depth.lastTrade - ? addDecimal(market.depth.lastTrade.price, market.decimalPlaces) - : undefined - } - quoteName={market.tradableInstrument.instrument.product.quoteName} - /> - ); - } else if (order.type === OrderType.Limit) { - ticket = ( - updateOrder({ size })} - onPriceChange={(price) => updateOrder({ price })} - /> - ); - } else { - throw new Error('Invalid ticket type'); - } - - const handleSubmit = (e: FormEvent): Promise => { - e.preventDefault(); - return submit(order); - }; + const onSubmit = React.useCallback( + (order: Order) => { + if (transactionStatus !== 'pending') { + submit(order); + } + }, + [transactionStatus, submit] + ); const steps = [ { @@ -87,9 +76,12 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { label: 'Select Order Type', description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`, component: ( - updateOrder({ type })} + ( + + )} /> ), }, @@ -97,9 +89,12 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { label: 'Select Market Position', description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`, component: ( - updateOrder({ side })} + ( + + )} /> ), }, @@ -107,27 +102,49 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { label: 'Select Order Size', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - component: ticket, + component: ( + + ), }, { label: 'Select Time In Force', description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`, component: ( <> - updateOrder({ timeInForce })} + ( + + )} /> - {order.timeInForce === OrderTimeInForce.GTT && ( - { - if (date) { - updateOrder({ expiration: date }); - } - }} - /> - )} + {orderType === OrderType.Limit && + orderTimeInForce === OrderTimeInForce.GTT && ( + ( + + )} + /> + )} ), }, @@ -136,11 +153,22 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`, component: ( - + {invalidText && ( + + {invalidText} + + )} + ), disabled: true, @@ -148,7 +176,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { ]; return ( -
+ ); diff --git a/apps/simple-trading-app/tsconfig.json b/apps/simple-trading-app/tsconfig.json index 9657042e4..1572e1c47 100644 --- a/apps/simple-trading-app/tsconfig.json +++ b/apps/simple-trading-app/tsconfig.json @@ -8,7 +8,7 @@ "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, + "noPropertyAccessFromIndexSignature": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true }, diff --git a/apps/static/src/assets/mainnet-tranches.json b/apps/static/src/assets/mainnet-tranches.json index a58585b24..d96ff0f00 100644 --- a/apps/static/src/assets/mainnet-tranches.json +++ b/apps/static/src/assets/mainnet-tranches.json @@ -488,7 +488,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "97499.58", "total_removed": "0", - "locked_amount": "71824.744464790495556796", + "locked_amount": "71359.360754532949904994", "deposits": [ { "amount": "97499.58", @@ -521,7 +521,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "135173.4239508", "total_removed": "0", - "locked_amount": "98172.02565853694305378077588", + "locked_amount": "97535.92647176062142134244004", "deposits": [ { "amount": "135173.4239508", @@ -554,7 +554,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "32499.86", "total_removed": "0", - "locked_amount": "30215.429649344600035924", + "locked_amount": "30019.65075918605161088", "deposits": [ { "amount": "32499.86", @@ -587,7 +587,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "10833.29", "total_removed": "0", - "locked_amount": "9834.8291472726030138", + "locked_amount": "9771.105018319376583514", "deposits": [ { "amount": "10833.29", @@ -675,7 +675,7 @@ "tranche_end": "2022-11-01T00:00:00.000Z", "total_added": "22500", "total_removed": "0", - "locked_amount": "18790.38156702898575", + "locked_amount": "18545.82059556159525", "deposits": [ { "amount": "15000", @@ -761,7 +761,7 @@ "tranche_end": "2023-06-02T00:00:00.000Z", "total_added": "1939928.38", "total_removed": "0", - "locked_amount": "1939928.38", + "locked_amount": "1938140.454506446441067284", "deposits": [ { "amount": "1852091.69", @@ -814,7 +814,7 @@ "tranche_end": "2022-06-02T00:00:00.000Z", "total_added": "1121510.3963", "total_removed": "922703.8062907670614", - "locked_amount": "10251.1276633719903559980853", + "locked_amount": "0", "deposits": [ { "amount": "7187.236", @@ -1777,7 +1777,7 @@ "tranche_end": "2022-09-30T00:00:00.000Z", "total_added": "60916.66666633337", "total_removed": "17568.575895506846757997", - "locked_amount": "19003.432880158768918954969915924", + "locked_amount": "18691.0451412597139137896684208311", "deposits": [ { "amount": "2833.333333", @@ -3206,8 +3206,8 @@ "tranche_id": 10, "tranche_start": "2021-07-15T23:37:11.000Z", "tranche_end": "2021-07-15T23:37:11.000Z", - "total_added": "3425768.150000000000000001", - "total_removed": "3417578.640000000000000001", + "total_added": "3475768.150000000000000001", + "total_removed": "3467578.640000000000000001", "locked_amount": "0", "deposits": [ { @@ -3230,6 +3230,11 @@ "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", "tx": "0x353c9a2464262be10f3a07acaf2be06dd90749c60da1af070ff053d2dcc2f8a2" }, + { + "amount": "50000", + "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", + "tx": "0xf96efc6a81c0e18f7d760f060797dbb213b4b472855fc8abd578e0be183d1d6f" + }, { "amount": "1", "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", @@ -3617,6 +3622,11 @@ "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", "tx": "0x499106f146fbaa9dd63bfbd3e6452dcdd5d845371c81e64962587c0b8bb43d10" }, + { + "amount": "50000", + "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", + "tx": "0x3a7c5f9a15ec899a68ad41701bfafd6f3c8ce55954dbeaeb343680378e6c00c0" + }, { "amount": "1", "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", @@ -3961,6 +3971,12 @@ "tranche_id": 10, "tx": "0x353c9a2464262be10f3a07acaf2be06dd90749c60da1af070ff053d2dcc2f8a2" }, + { + "amount": "50000", + "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", + "tranche_id": 10, + "tx": "0xf96efc6a81c0e18f7d760f060797dbb213b4b472855fc8abd578e0be183d1d6f" + }, { "amount": "1", "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", @@ -3999,6 +4015,12 @@ "tranche_id": 10, "tx": "0x499106f146fbaa9dd63bfbd3e6452dcdd5d845371c81e64962587c0b8bb43d10" }, + { + "amount": "50000", + "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", + "tranche_id": 10, + "tx": "0x3a7c5f9a15ec899a68ad41701bfafd6f3c8ce55954dbeaeb343680378e6c00c0" + }, { "amount": "1", "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", @@ -4018,8 +4040,8 @@ "tx": "0xac16a4ce688d40a482a59914d68c3a676592f8804ee8f0781b66a4ba5ccfbdfc" } ], - "total_tokens": "279451", - "withdrawn_tokens": "279451", + "total_tokens": "329451", + "withdrawn_tokens": "329451", "remaining_tokens": "0" }, { @@ -5017,9 +5039,9 @@ "tranche_id": 11, "tranche_start": "2021-09-03T00:00:00.000Z", "tranche_end": "2022-09-03T00:00:00.000Z", - "total_added": "14473.000000000000000003", + "total_added": "15073.000000000000000003", "total_removed": "2897.73152892253", - "locked_amount": "3753.6048590816850461007780566971080671", + "locked_amount": "3826.6258515664639083007616186263318113", "deposits": [ { "amount": "10", @@ -5606,6 +5628,51 @@ "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", "tx": "0xb5ce5dbf53dc455d902f8be045d73604ac520aad1819209281568c36f2a67fb8" }, + { + "amount": "35", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tx": "0x29c7f3a1d2cb3d38c1a71ff16ae5a49ec04396efcf3b5a5af5a7b7644e2790b9" + }, + { + "amount": "300", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tx": "0x34f9438d653258c7f2a13d5b9895de67e071db8f4e6f4f871b41700537b78296" + }, + { + "amount": "80", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tx": "0x4841c1749a749f260071c6083a57fd4ac81a1f89c6ae5fdb3923c7dc2ccea784" + }, + { + "amount": "10", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tx": "0xb3effa4c0d44cc0618748d64a49772033316fd416b4543fef7e64a4995123234" + }, + { + "amount": "80", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tx": "0x7ae3f7b39317bbe75034811f513f27a895cdacc645d6ea528c1230bb7713ddef" + }, + { + "amount": "30", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tx": "0x9af4905761376f50e57da3a5c5fc976d09cf171d3e160dcf16f833971d5c4ef4" + }, + { + "amount": "25", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tx": "0x7a19b511ce85a24a6a67526c4037abe394bd58552ef66efdcc5c1473d7ca2db5" + }, + { + "amount": "30", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tx": "0xf4c9400f35f2c0791980f2a40e944225cdeb90cb61336e145f9fc49136134591" + }, + { + "amount": "10", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tx": "0x32dc4ad84f622b72d89d01b2411c999ded247ed19821418691957d9f90da180a" + }, { "amount": "25", "user": "0xc6A53Dbb3423555C990Fc842A28CF58edC35DC73", @@ -8929,12 +8996,66 @@ "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", "tranche_id": 11, "tx": "0xb5ce5dbf53dc455d902f8be045d73604ac520aad1819209281568c36f2a67fb8" + }, + { + "amount": "35", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tranche_id": 11, + "tx": "0x29c7f3a1d2cb3d38c1a71ff16ae5a49ec04396efcf3b5a5af5a7b7644e2790b9" + }, + { + "amount": "300", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tranche_id": 11, + "tx": "0x34f9438d653258c7f2a13d5b9895de67e071db8f4e6f4f871b41700537b78296" + }, + { + "amount": "80", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tranche_id": 11, + "tx": "0x4841c1749a749f260071c6083a57fd4ac81a1f89c6ae5fdb3923c7dc2ccea784" + }, + { + "amount": "10", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tranche_id": 11, + "tx": "0xb3effa4c0d44cc0618748d64a49772033316fd416b4543fef7e64a4995123234" + }, + { + "amount": "80", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tranche_id": 11, + "tx": "0x7ae3f7b39317bbe75034811f513f27a895cdacc645d6ea528c1230bb7713ddef" + }, + { + "amount": "30", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tranche_id": 11, + "tx": "0x9af4905761376f50e57da3a5c5fc976d09cf171d3e160dcf16f833971d5c4ef4" + }, + { + "amount": "25", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tranche_id": 11, + "tx": "0x7a19b511ce85a24a6a67526c4037abe394bd58552ef66efdcc5c1473d7ca2db5" + }, + { + "amount": "30", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tranche_id": 11, + "tx": "0xf4c9400f35f2c0791980f2a40e944225cdeb90cb61336e145f9fc49136134591" + }, + { + "amount": "10", + "user": "0x4cf8879dC68ebe9F003E6231CB8B704FAbEA8d9c", + "tranche_id": 11, + "tx": "0x32dc4ad84f622b72d89d01b2411c999ded247ed19821418691957d9f90da180a" } ], "withdrawals": [], - "total_tokens": "10", + "total_tokens": "610", "withdrawn_tokens": "0", - "remaining_tokens": "10" + "remaining_tokens": "610" }, { "address": "0xc6A53Dbb3423555C990Fc842A28CF58edC35DC73", @@ -12786,7 +12907,7 @@ "tranche_end": "2023-06-05T00:00:00.000Z", "total_added": "3732368.4671", "total_removed": "74162.9780761646031", - "locked_amount": "3019082.347375474584450246", + "locked_amount": "3002748.41446940756547250008", "deposits": [ { "amount": "1998.95815", @@ -15450,8 +15571,8 @@ "tranche_start": "2021-11-05T00:00:00.000Z", "tranche_end": "2023-05-05T00:00:00.000Z", "total_added": "14597706.0446472999", - "total_removed": "1562375.666880815858067983", - "locked_amount": "9054416.05714107182492323023185274", + "total_removed": "1563001.535509480008878233", + "locked_amount": "9000945.53475187470322777308704175", "deposits": [ { "amount": "129284.449", @@ -15790,6 +15911,11 @@ "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", "tx": "0x47879bd74b0adbf7cbfd0ea1e0175bcc202ac5c224dacf94d7a4ef6a2f1de9a0" }, + { + "amount": "625.86862866415081025", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x3f1666dc9c401996a37b4543b7945d14f6d66561cd1d0a84caa30b92fc55408e" + }, { "amount": "58127.81687116447134108", "user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8", @@ -17195,6 +17321,12 @@ "tranche_id": 3, "tx": "0x47879bd74b0adbf7cbfd0ea1e0175bcc202ac5c224dacf94d7a4ef6a2f1de9a0" }, + { + "amount": "625.86862866415081025", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x3f1666dc9c401996a37b4543b7945d14f6d66561cd1d0a84caa30b92fc55408e" + }, { "amount": "673.86655774325828525", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -18217,8 +18349,8 @@ } ], "total_tokens": "359123.469575", - "withdrawn_tokens": "136362.15277444105946275", - "remaining_tokens": "222761.31680055894053725" + "withdrawn_tokens": "136988.021403105210273", + "remaining_tokens": "222135.448171894789727" }, { "address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB", @@ -19189,8 +19321,8 @@ "tranche_start": "2021-10-05T00:00:00.000Z", "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "5778205.3912159303", - "total_removed": "1270541.085579567787916742", - "locked_amount": "3260551.14128864886179085042406401", + "total_removed": "1292362.811321297942666742", + "locked_amount": "3239424.61450565009103150955191263", "deposits": [ { "amount": "552496.6455", @@ -19349,6 +19481,11 @@ "user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D", "tx": "0xb6a0d0df674d88b02c3cbfcd26df1c379545ea24ff8fa5a0f35810e7606a687d" }, + { + "amount": "21821.72574173015475", + "user": "0xdbC5d439F373EB646345e1c67D1d46231ACE7dD3", + "tx": "0x8e9f65bfea45a61e4f20108bc0ad1ce2bdeba8e355c7b1d4e024a3ffd73065a4" + }, { "amount": "7013.412182841867109", "user": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75", @@ -19844,6 +19981,12 @@ } ], "withdrawals": [ + { + "amount": "21821.72574173015475", + "user": "0xdbC5d439F373EB646345e1c67D1d46231ACE7dD3", + "tranche_id": 4, + "tx": "0x8e9f65bfea45a61e4f20108bc0ad1ce2bdeba8e355c7b1d4e024a3ffd73065a4" + }, { "amount": "74521.210878260278004", "user": "0xdbC5d439F373EB646345e1c67D1d46231ACE7dD3", @@ -19852,8 +19995,8 @@ } ], "total_tokens": "220999.0582", - "withdrawn_tokens": "74521.210878260278004", - "remaining_tokens": "146477.847321739721996" + "withdrawn_tokens": "96342.936619990432754", + "remaining_tokens": "124656.121580009567246" }, { "address": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D", @@ -20221,10 +20364,15 @@ "tranche_id": 5, "tranche_start": "2022-06-05T00:00:00.000Z", "tranche_end": "2023-06-05T00:00:00.000Z", - "total_added": "469355.6199999996", + "total_added": "472355.6199999996", "total_removed": "0", - "locked_amount": "469355.6199999996", + "locked_amount": "472355.6199999996", "deposits": [ + { + "amount": "3000", + "user": "0xD18ffAa4a1d16f9eD9d3BE4078738Eeda3f160FD", + "tx": "0xca9ae1a4cdf8f152cc4f139b62ed65a266c39fc6d0180dc1237feee0d46eb0d3" + }, { "amount": "22500", "user": "0x3b208631B70e4a98bBee864effc7908501305c1f", @@ -26838,6 +26986,21 @@ ], "withdrawals": [], "users": [ + { + "address": "0xD18ffAa4a1d16f9eD9d3BE4078738Eeda3f160FD", + "deposits": [ + { + "amount": "3000", + "user": "0xD18ffAa4a1d16f9eD9d3BE4078738Eeda3f160FD", + "tranche_id": 5, + "tx": "0xca9ae1a4cdf8f152cc4f139b62ed65a266c39fc6d0180dc1237feee0d46eb0d3" + } + ], + "withdrawals": [], + "total_tokens": "3000", + "withdrawn_tokens": "0", + "remaining_tokens": "3000" + }, { "address": "0x3b208631B70e4a98bBee864effc7908501305c1f", "deposits": [ @@ -45856,8 +46019,8 @@ "tranche_start": "2021-12-05T00:00:00.000Z", "tranche_end": "2022-06-05T00:00:00.000Z", "total_added": "171288.42", - "total_removed": "16804.8745535697803", - "locked_amount": "4389.09147635835649595952", + "total_removed": "17067.9263679026803", + "locked_amount": "2506.83382533958609789446", "deposits": [ { "amount": "250", @@ -50161,6 +50324,21 @@ "user": "0x4f829afFDe62De9a7E819c475D20556EdC85971f", "tx": "0x5ec25c61dab464ed2d1caeb79d6172e60b0965bed21d9293c1c0424e83268118" }, + { + "amount": "185.58552414", + "user": "0xcB7C51a63110F2669D33cadf593E838e7EdD8007", + "tx": "0x0d774d5fcf278d1b33eb7942a6c350b2303693d90d67e733132de00d97589a78" + }, + { + "amount": "39.1320029504", + "user": "0x2e745Bf52Bd236dA8C4944d82233da08BAE49DA1", + "tx": "0x1a5ccef5c59ceb3f82e1d4121ef16b29590e7f07139f6a34690c3e3a85d139d0" + }, + { + "amount": "38.3342872425", + "user": "0x27049a430Df8b89Ae4f899b0383B0C876F9cAcEb", + "tx": "0x2dadd46cff92cdcb974ba556776f69b136a526e05391e07618503526ef3667e0" + }, { "amount": "252.08931115", "user": "0xE245503f8a33eBDDD718915132869C9Ba9df37A8", @@ -51319,10 +51497,17 @@ "tx": "0xb59405747c8088945a412703637a7b422f3639439ec2ee15e180c0a2a0d71ee4" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "39.1320029504", + "user": "0x2e745Bf52Bd236dA8C4944d82233da08BAE49DA1", + "tranche_id": 6, + "tx": "0x1a5ccef5c59ceb3f82e1d4121ef16b29590e7f07139f6a34690c3e3a85d139d0" + } + ], "total_tokens": "40", - "withdrawn_tokens": "0", - "remaining_tokens": "40" + "withdrawn_tokens": "39.1320029504", + "remaining_tokens": "0.8679970496" }, { "address": "0x505180B5570Ef6E607aA42DB4b67B5E7a8253C5c", @@ -58611,6 +58796,12 @@ } ], "withdrawals": [ + { + "amount": "38.3342872425", + "user": "0x27049a430Df8b89Ae4f899b0383B0C876F9cAcEb", + "tranche_id": 6, + "tx": "0x2dadd46cff92cdcb974ba556776f69b136a526e05391e07618503526ef3667e0" + }, { "amount": "41.3456291975", "user": "0x27049a430Df8b89Ae4f899b0383B0C876F9cAcEb", @@ -58643,8 +58834,8 @@ } ], "total_tokens": "250", - "withdrawn_tokens": "207.9011656725", - "remaining_tokens": "42.0988343275" + "withdrawn_tokens": "246.235452915", + "remaining_tokens": "3.764547085" }, { "address": "0x42bC480928828C57c39649A7D10e41227b6d5E4F", @@ -63624,6 +63815,12 @@ } ], "withdrawals": [ + { + "amount": "185.58552414", + "user": "0xcB7C51a63110F2669D33cadf593E838e7EdD8007", + "tranche_id": 6, + "tx": "0x0d774d5fcf278d1b33eb7942a6c350b2303693d90d67e733132de00d97589a78" + }, { "amount": "58.3807266225", "user": "0xcB7C51a63110F2669D33cadf593E838e7EdD8007", @@ -63632,8 +63829,8 @@ } ], "total_tokens": "250", - "withdrawn_tokens": "58.3807266225", - "remaining_tokens": "191.6192733775" + "withdrawn_tokens": "243.9662507625", + "remaining_tokens": "6.0337492375" }, { "address": "0x4d53f5e09adeAD6288477a37eede4522aacBBfdF", diff --git a/apps/static/src/assets/stagnet1-tranches.json b/apps/static/src/assets/stagnet1-tranches.json index b9a4cb98d..883180732 100644 --- a/apps/static/src/assets/stagnet1-tranches.json +++ b/apps/static/src/assets/stagnet1-tranches.json @@ -38,7 +38,7 @@ "tranche_end": "2022-11-26T13:48:10.000Z", "total_added": "100", "total_removed": "0", - "locked_amount": "49.106503678335867", + "locked_amount": "48.558558472856417", "deposits": [ { "amount": "100", @@ -242,7 +242,7 @@ "tranche_end": "2022-10-12T00:53:20.000Z", "total_added": "100", "total_removed": "0", - "locked_amount": "36.63031773211568", + "locked_amount": "36.08237252663623", "deposits": [ { "amount": "100", diff --git a/apps/stats/src/app.tsx b/apps/stats/src/app.tsx index 8fbdfafa5..66430467d 100644 --- a/apps/stats/src/app.tsx +++ b/apps/stats/src/app.tsx @@ -3,6 +3,7 @@ import { DATA_SOURCES } from './config'; import { Header } from './components/header'; import { StatsManager } from '@vegaprotocol/network-stats'; import { ThemeContext } from '@vegaprotocol/react-helpers'; +import { EnvironmentProvider } from '@vegaprotocol/react-helpers'; import { useThemeSwitcher } from '@vegaprotocol/react-helpers'; const envName = DATA_SOURCES.envName; @@ -14,19 +15,21 @@ function App() { const [theme, toggleTheme] = useThemeSwitcher(); return ( - -
-
-
- + + +
+
+
+ +
-
- + + ); } diff --git a/apps/stats/tsconfig.json b/apps/stats/tsconfig.json index 9657042e4..1572e1c47 100644 --- a/apps/stats/tsconfig.json +++ b/apps/stats/tsconfig.json @@ -8,7 +8,7 @@ "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, + "noPropertyAccessFromIndexSignature": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true }, diff --git a/apps/token/src/app.tsx b/apps/token/src/app.tsx index c1ebcbe04..aaa961d8e 100644 --- a/apps/token/src/app.tsx +++ b/apps/token/src/app.tsx @@ -20,37 +20,40 @@ import { Web3Provider } from '@vegaprotocol/web3'; import { Connectors } from './lib/web3-connectors'; import { VegaWalletDialogs } from './components/vega-wallet-dialogs'; import { VegaWalletProvider } from '@vegaprotocol/wallet'; +import { EnvironmentProvider } from '@vegaprotocol/react-helpers'; function App() { const sideBar = React.useMemo(() => [, ], []); return ( - - - - - - - - <> -
- - - - - -
- - - -
-
-
-
-
-
-
+ + + + + + + + + <> +
+ + + + + +
+ + + +
+
+
+
+
+
+
+
); diff --git a/apps/token/src/components/add-locked-token/add-locked-token.tsx b/apps/token/src/components/add-locked-token/add-locked-token.tsx index 9e98f8285..275e0aa76 100644 --- a/apps/token/src/components/add-locked-token/add-locked-token.tsx +++ b/apps/token/src/components/add-locked-token/add-locked-token.tsx @@ -1,12 +1,13 @@ import { useTranslation } from 'react-i18next'; -import { ADDRESSES } from '../../config'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { useAddAssetSupported } from '../../hooks/use-add-asset-to-wallet'; import vegaVesting from '../../images/vega_vesting.png'; import { AddTokenButtonLink } from '../add-token-button/add-token-button'; import { Callout } from '@vegaprotocol/ui-toolkit'; export const AddLockedTokenAddress = () => { + const { ADDRESSES } = useEnvironment(); const { t } = useTranslation(); const addSupported = useAddAssetSupported(); return ( diff --git a/apps/token/src/components/balance-manager/balance-manager.tsx b/apps/token/src/components/balance-manager/balance-manager.tsx index c3cb18b84..4f7e57dee 100644 --- a/apps/token/src/components/balance-manager/balance-manager.tsx +++ b/apps/token/src/components/balance-manager/balance-manager.tsx @@ -2,7 +2,7 @@ import * as Sentry from '@sentry/react'; import { useWeb3React } from '@web3-react/core'; import React from 'react'; -import { ADDRESSES } from '../../config'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { AppStateActionType, useAppState, @@ -17,6 +17,7 @@ interface BalanceManagerProps { } export const BalanceManager = ({ children }: BalanceManagerProps) => { + const { ADDRESSES } = useEnvironment(); const contracts = useContracts(); const { account } = useWeb3React(); const { appDispatch } = useAppState(); @@ -55,7 +56,13 @@ export const BalanceManager = ({ children }: BalanceManagerProps) => { }; updateBalances(); - }, [appDispatch, contracts?.token, contracts?.vesting, account]); + }, [ + appDispatch, + contracts?.token, + contracts?.vesting, + account, + ADDRESSES.stakingBridge, + ]); // This use effect hook is very expensive and is kept separate to prevent expensive reloading of data. React.useEffect(() => { diff --git a/apps/token/src/components/transaction-button/transaction-button.tsx b/apps/token/src/components/transaction-button/transaction-button.tsx index 1eaec2ec7..cee44867a 100644 --- a/apps/token/src/components/transaction-button/transaction-button.tsx +++ b/apps/token/src/components/transaction-button/transaction-button.tsx @@ -3,7 +3,8 @@ import { useTranslation } from 'react-i18next'; import type { TransactionState } from '../../hooks/transaction-reducer'; import { TxState } from '../../hooks/transaction-reducer'; import { truncateMiddle } from '../../lib/truncate-middle'; -import { Button, EtherscanLink } from '@vegaprotocol/ui-toolkit'; +import { Button, Link } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { Error, HandUp, Tick } from '../icons'; import { Loader } from '../loader'; import { StatefulButton } from '../stateful-button'; @@ -122,6 +123,7 @@ export const TransactionButtonFooter = ({ txHash, message, }: TransactionButtonFooterProps) => { + const { ETHERSCAN_URL } = useEnvironment(); const { t } = useTranslation(); if (message) { @@ -142,7 +144,12 @@ export const TransactionButtonFooter = ({

{t('transaction')} - + + {truncateMiddle(txHash)} +

); diff --git a/apps/token/src/components/transaction-callout/transaction-complete.tsx b/apps/token/src/components/transaction-callout/transaction-complete.tsx index 6f44403a1..dcb8263ee 100644 --- a/apps/token/src/components/transaction-callout/transaction-complete.tsx +++ b/apps/token/src/components/transaction-callout/transaction-complete.tsx @@ -1,6 +1,7 @@ import { Callout, Intent } from '@vegaprotocol/ui-toolkit'; import { useTranslation } from 'react-i18next'; -import { EtherscanLink } from '@vegaprotocol/ui-toolkit'; +import { Link } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import type { ReactElement } from 'react'; export const TransactionComplete = ({ @@ -14,6 +15,7 @@ export const TransactionComplete = ({ footer?: ReactElement | string; body?: ReactElement | string; }) => { + const { ETHERSCAN_URL } = useEnvironment(); const { t } = useTranslation(); return ( {body &&

{body}

}

- + + {hash} +

{footer &&

{footer}

}
diff --git a/apps/token/src/components/transaction-callout/transaction-error.tsx b/apps/token/src/components/transaction-callout/transaction-error.tsx index 4ddf9b584..22be01b1a 100644 --- a/apps/token/src/components/transaction-callout/transaction-error.tsx +++ b/apps/token/src/components/transaction-callout/transaction-error.tsx @@ -1,8 +1,8 @@ import { Button, Callout, Intent } from '@vegaprotocol/ui-toolkit'; import { useTranslation } from 'react-i18next'; -import { EtherscanLink } from '@vegaprotocol/ui-toolkit'; -import type { Error } from '../icons'; +import { Link } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; export interface TransactionErrorProps { error: Error | null; @@ -15,6 +15,7 @@ export const TransactionError = ({ hash, onActionClick, }: TransactionErrorProps) => { + const { ETHERSCAN_URL } = useEnvironment(); const { t } = useTranslation(); return ( @@ -22,7 +23,12 @@ export const TransactionError = ({

{error ? error.message : t('Something went wrong')}

{hash ? (

- + + {hash} +

) : null} diff --git a/apps/token/src/components/transaction-callout/transaction-pending.tsx b/apps/token/src/components/transaction-callout/transaction-pending.tsx index f9e3cf1cd..4a2f291bc 100644 --- a/apps/token/src/components/transaction-callout/transaction-pending.tsx +++ b/apps/token/src/components/transaction-callout/transaction-pending.tsx @@ -1,7 +1,8 @@ import React from 'react'; import { Callout } from '@vegaprotocol/ui-toolkit'; import { useTranslation } from 'react-i18next'; -import { EtherscanLink } from '@vegaprotocol/ui-toolkit'; +import { Link } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; export const TransactionPending = ({ hash, @@ -18,6 +19,7 @@ export const TransactionPending = ({ footer?: React.ReactElement | string; body?: React.ReactElement | string; }) => { + const { ETHERSCAN_URL } = useEnvironment(); const { t } = useTranslation(); const remainingConfirmations = React.useMemo(() => { if (requiredConfirmations) { @@ -38,7 +40,12 @@ export const TransactionPending = ({ {body &&

{body}

}

- + + {hash} +

{footer &&

{footer}

}
diff --git a/apps/token/src/components/transactions-modal/transactions-modal.tsx b/apps/token/src/components/transactions-modal/transactions-modal.tsx index 57acc30e6..6a9887ba0 100644 --- a/apps/token/src/components/transactions-modal/transactions-modal.tsx +++ b/apps/token/src/components/transactions-modal/transactions-modal.tsx @@ -1,5 +1,6 @@ import type { TxData } from '@vegaprotocol/smart-contracts'; -import { Dialog, EtherscanLink } from '@vegaprotocol/ui-toolkit'; +import { Dialog, Link } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -28,6 +29,7 @@ const TransactionModalStatus = ({ }) => {children}; export const TransactionModal = () => { + const { ETHERSCAN_URL } = useEnvironment(); const { t } = useTranslation(); const { transactions } = useContracts(); const { appState, appDispatch } = useAppState(); @@ -76,16 +78,20 @@ export const TransactionModal = () => { - {transactions.map((t) => { + {transactions.map((transaction) => { return ( - + - + + {truncateMiddle(transaction.tx.hash)} + + + + {renderStatus(transaction)} - {renderStatus(t)} ); })} diff --git a/apps/token/src/components/vega-wallet/hooks.ts b/apps/token/src/components/vega-wallet/hooks.ts index 16dbedefa..044f4b8f3 100644 --- a/apps/token/src/components/vega-wallet/hooks.ts +++ b/apps/token/src/components/vega-wallet/hooks.ts @@ -6,7 +6,6 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { AccountType } from '../../__generated__/globalTypes'; -import { ADDRESSES } from '../../config'; import noIcon from '../../images/token-no-icon.png'; import vegaBlack from '../../images/vega_black.png'; import { BigNumber } from '../../lib/bignumber'; @@ -18,6 +17,7 @@ import type { DelegationsVariables, } from './__generated__/Delegations'; import { useVegaWallet } from '@vegaprotocol/wallet'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; const DELEGATIONS_QUERY = gql` query Delegations($partyId: ID!) { @@ -60,6 +60,7 @@ const DELEGATIONS_QUERY = gql` `; export const usePollForDelegations = () => { + const { ADDRESSES } = useEnvironment(); const { t } = useTranslation(); const { keypair } = useVegaWallet(); const client = useApolloClient(); @@ -227,7 +228,7 @@ export const usePollForDelegations = () => { clearInterval(interval); mounted = false; }; - }, [client, keypair?.pub, t]); + }, [client, keypair?.pub, t, ADDRESSES.vegaTokenAddress]); return { delegations, currentStakeAvailable, delegatedNodes, accounts }; }; diff --git a/apps/token/src/config/ethereum.ts b/apps/token/src/config/ethereum.ts deleted file mode 100644 index f9f7e8e0f..000000000 --- a/apps/token/src/config/ethereum.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { EthereumChainId } from '@vegaprotocol/smart-contracts'; -import { - EnvironmentConfig, - EthereumChainIds, -} from '@vegaprotocol/smart-contracts'; - -import type { Networks } from './vega'; - -type VegaContracts = typeof EnvironmentConfig[Networks]; - -const appChainId = Number(process.env['NX_ETHEREUM_CHAIN_ID'] || 3); - -export const APP_ENV = process.env['NX_VEGA_ENV'] as Networks; - -const Addresses: Record = { - 1: EnvironmentConfig.MAINNET, - 3: EnvironmentConfig[APP_ENV], -}; - -export type { EthereumChainId }; -export { EthereumChainIds }; - -/** Contract addresses for the different contracts in the VEGA ecosystem */ -export const ADDRESSES = Addresses[appChainId]; - -/** - * The Chain ID the environment is configured for. - * Normally this is 0x3 (Ropsten) for dev and 0x1 (Mainnet) for prod - */ -export const APP_CHAIN_ID = appChainId; diff --git a/apps/token/src/config/index.ts b/apps/token/src/config/index.ts index a20c07baa..9df05ee55 100644 --- a/apps/token/src/config/index.ts +++ b/apps/token/src/config/index.ts @@ -1,5 +1,4 @@ export * from './flags'; -export * from './ethereum'; export * from './links'; export * from './network-params'; export * from './vega'; diff --git a/apps/token/src/config/vega.ts b/apps/token/src/config/vega.ts index 636af4612..c5bd9f4d9 100644 --- a/apps/token/src/config/vega.ts +++ b/apps/token/src/config/vega.ts @@ -1,11 +1,4 @@ -export enum Networks { - CUSTOM = 'CUSTOM', - TESTNET = 'TESTNET', - STAGNET = 'STAGNET', - STAGNET2 = 'STAGNET2', - DEVNET = 'DEVNET', - MAINNET = 'MAINNET', -} +import { Networks } from '@vegaprotocol/smart-contracts'; interface VegaNode { url: string; diff --git a/apps/token/src/contexts/contracts/contracts-provider.tsx b/apps/token/src/contexts/contracts/contracts-provider.tsx index 3fc6bd745..df74c5459 100644 --- a/apps/token/src/contexts/contracts/contracts-provider.tsx +++ b/apps/token/src/contexts/contracts/contracts-provider.tsx @@ -10,9 +10,9 @@ import { Splash } from '@vegaprotocol/ui-toolkit'; import { useWeb3React } from '@web3-react/core'; import uniqBy from 'lodash/uniqBy'; import React from 'react'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { SplashLoader } from '../../components/splash-loader'; -import { ADDRESSES, APP_ENV } from '../../config'; import type { ContractsContextShape } from './contracts-context'; import { ContractsContext } from './contracts-context'; import { defaultProvider } from '../../lib/web3-connectors'; @@ -21,6 +21,7 @@ import { defaultProvider } from '../../lib/web3-connectors'; * Provides Vega Ethereum contract instances to its children. */ export const ContractsProvider = ({ children }: { children: JSX.Element }) => { + const { ADDRESSES, VEGA_ENV } = useEnvironment(); const { provider: activeProvider, account } = useWeb3React(); const [txs, setTxs] = React.useState([]); const [contracts, setContracts] = React.useState { signer ), // @ts-ignore Cant accept JsonRpcProvider provider - staking: new VegaStaking(APP_ENV, provider, signer), + staking: new VegaStaking(VEGA_ENV, provider, signer), // @ts-ignore Cant accept JsonRpcProvider provider - vesting: new VegaVesting(APP_ENV, provider, signer), + vesting: new VegaVesting(VEGA_ENV, provider, signer), // @ts-ignore Cant accept JsonRpcProvider provider - claim: new VegaClaim(APP_ENV, provider, signer), + claim: new VegaClaim(VEGA_ENV, provider, signer), erc20Bridge: new VegaErc20Bridge( - APP_ENV, + VEGA_ENV, // @ts-ignore Cant accept JsonRpcProvider provider provider, signer ), }); } - }, [activeProvider, account]); + }, [activeProvider, account, ADDRESSES.vegaTokenAddress, VEGA_ENV]); React.useEffect(() => { if (!contracts) return; diff --git a/apps/token/src/hooks/use-add-asset-to-wallet.ts b/apps/token/src/hooks/use-add-asset-to-wallet.ts index 5129c7e6a..886fc50ef 100644 --- a/apps/token/src/hooks/use-add-asset-to-wallet.ts +++ b/apps/token/src/hooks/use-add-asset-to-wallet.ts @@ -1,9 +1,9 @@ +import React from 'react'; import * as Sentry from '@sentry/react'; import { useWeb3React } from '@web3-react/core'; import { MetaMask } from '@web3-react/metamask'; -import React from 'react'; - -import { APP_ENV, Networks } from '../config'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; +import { Networks } from '@vegaprotocol/smart-contracts'; export const useAddAssetSupported = () => { const { connector } = useWeb3React(); @@ -19,6 +19,7 @@ export const useAddAssetToWallet = ( decimals: number, image: string ) => { + const { VEGA_ENV } = useEnvironment(); const { provider } = useWeb3React(); const addSupported = useAddAssetSupported(); const add = React.useCallback(async () => { @@ -35,10 +36,10 @@ export const useAddAssetToWallet = ( address, symbol: `${symbol}${ // Add the environment if not mainnet - APP_ENV === Networks.MAINNET + VEGA_ENV === Networks.MAINNET ? '' : // Remove NET as VEGA(TESTNET) is too long - ` ${APP_ENV.replace('NET', '')}` + ` ${VEGA_ENV.replace('NET', '')}` }`, decimals, image, @@ -48,7 +49,7 @@ export const useAddAssetToWallet = ( } catch (error) { Sentry.captureException(error); } - }, [address, decimals, image, provider, symbol]); + }, [address, decimals, image, provider, symbol, VEGA_ENV]); return React.useMemo(() => { return { diff --git a/apps/token/src/hooks/use-refresh-balances.ts b/apps/token/src/hooks/use-refresh-balances.ts index 629f24b4a..79887e6ae 100644 --- a/apps/token/src/hooks/use-refresh-balances.ts +++ b/apps/token/src/hooks/use-refresh-balances.ts @@ -2,7 +2,7 @@ import * as Sentry from '@sentry/react'; import { useVegaWallet } from '@vegaprotocol/wallet'; import React from 'react'; -import { ADDRESSES } from '../config'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { AppStateActionType, useAppState, @@ -10,6 +10,7 @@ import { import { useContracts } from '../contexts/contracts/contracts-context'; export const useRefreshBalances = (address: string) => { + const { ADDRESSES } = useEnvironment(); const { appDispatch } = useAppState(); const { keypair } = useVegaWallet(); const { token, staking, vesting } = useContracts(); @@ -44,5 +45,13 @@ export const useRefreshBalances = (address: string) => { } catch (err) { Sentry.captureException(err); } - }, [address, appDispatch, keypair?.pub, staking, token, vesting]); + }, [ + address, + appDispatch, + keypair?.pub, + staking, + token, + vesting, + ADDRESSES.stakingBridge, + ]); }; diff --git a/apps/token/src/hooks/use-tranches.ts b/apps/token/src/hooks/use-tranches.ts index b1bca1045..ba379dbf4 100644 --- a/apps/token/src/hooks/use-tranches.ts +++ b/apps/token/src/hooks/use-tranches.ts @@ -1,7 +1,7 @@ import { useFetch } from '@vegaprotocol/react-helpers'; import type { Networks, Tranche } from '@vegaprotocol/smart-contracts'; import React, { useEffect } from 'react'; -import { APP_ENV } from '../config'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { BigNumber } from '../lib/bignumber'; @@ -15,8 +15,9 @@ const TRANCHES_URLS: { [N in Networks]: string } = { }; export function useTranches() { + const { VEGA_ENV } = useEnvironment(); const [tranches, setTranches] = React.useState(null); - const url = React.useMemo(() => TRANCHES_URLS[APP_ENV], []); + const url = React.useMemo(() => TRANCHES_URLS[VEGA_ENV], [VEGA_ENV]); const { state: { data, loading, error }, } = useFetch(url); diff --git a/apps/token/src/routes/claim/complete.tsx b/apps/token/src/routes/claim/complete.tsx index 3dc81236a..d0b0b9f39 100644 --- a/apps/token/src/routes/claim/complete.tsx +++ b/apps/token/src/routes/claim/complete.tsx @@ -1,11 +1,7 @@ -import { - Callout, - Intent, - EtherscanLink, - Button, -} from '@vegaprotocol/ui-toolkit'; +import { Callout, Intent, Link, Button } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { Trans, useTranslation } from 'react-i18next'; -import { Link } from 'react-router-dom'; +import { Link as RouteLink } from 'react-router-dom'; import type { BigNumber } from '../../lib/bignumber'; import { formatNumber } from '../../lib/format-number'; @@ -22,6 +18,7 @@ export const Complete = ({ commitTxHash: string | null; claimTxHash: string | null; }) => { + const { ETHERSCAN_URL } = useEnvironment(); const { t } = useTranslation(); return ( @@ -38,18 +35,28 @@ export const Complete = ({ {commitTxHash && (

{t('Link transaction')}:{' '} - + + {commitTxHash} +

)} {claimTxHash && (

{t('Claim transaction')}:{' '} - + + {claimTxHash} +

)} - + - + ); }; diff --git a/apps/token/src/routes/contracts/index.tsx b/apps/token/src/routes/contracts/index.tsx index 208f8a209..87ce6e9d0 100644 --- a/apps/token/src/routes/contracts/index.tsx +++ b/apps/token/src/routes/contracts/index.tsx @@ -1,8 +1,11 @@ -import { EtherscanLink } from '@vegaprotocol/ui-toolkit'; +import { useTranslation } from 'react-i18next'; +import { Link } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { Heading } from '../../components/heading'; -import { ADDRESSES } from '../../config'; const Contracts = () => { + const { ADDRESSES, ETHERSCAN_URL } = useEnvironment(); + const { t } = useTranslation(); return (
@@ -10,7 +13,12 @@ const Contracts = () => { {Object.entries(ADDRESSES).map(([key, value]) => (
{key}:
- + + {value} +
))}
diff --git a/apps/token/src/routes/home/token-details/token-details.tsx b/apps/token/src/routes/home/token-details/token-details.tsx index 2f4412afb..c2dfc34ba 100644 --- a/apps/token/src/routes/home/token-details/token-details.tsx +++ b/apps/token/src/routes/home/token-details/token-details.tsx @@ -1,13 +1,8 @@ import { useTranslation } from 'react-i18next'; -import { - Callout, - EtherscanLink, - Intent, - Splash, -} from '@vegaprotocol/ui-toolkit'; +import { Callout, Link, Intent, Splash } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { KeyValueTable, KeyValueTableRow } from '@vegaprotocol/ui-toolkit'; -import { ADDRESSES } from '../../../config'; import { useTranches } from '../../../hooks/use-tranches'; import type { BigNumber } from '../../../lib/bignumber'; import { formatNumber } from '../../../lib/format-number'; @@ -21,6 +16,7 @@ export const TokenDetails = ({ totalSupply: BigNumber; totalStaked: BigNumber; }) => { + const { ADDRESSES, ETHERSCAN_URL } = useEnvironment(); const { t } = useTranslation(); const { tranches, loading, error } = useTranches(); @@ -45,21 +41,25 @@ export const TokenDetails = ({ {t('Token address').toUpperCase()} - + href={`${ETHERSCAN_URL}/address/${ADDRESSES.vegaTokenAddress}`} + > + {ADDRESSES.vegaTokenAddress} + {t('Vesting contract'.toUpperCase())} - + href={`${ETHERSCAN_URL}/address/${ADDRESSES.vestingAddress}`} + > + {ADDRESSES.vestingAddress} + {t('Total supply').toUpperCase()} diff --git a/apps/token/src/routes/redemption/tranche/index.tsx b/apps/token/src/routes/redemption/tranche/index.tsx index f5f2e9df3..f9477aae5 100644 --- a/apps/token/src/routes/redemption/tranche/index.tsx +++ b/apps/token/src/routes/redemption/tranche/index.tsx @@ -3,7 +3,7 @@ import { Trans, useTranslation } from 'react-i18next'; import { Link, useParams, useOutletContext } from 'react-router-dom'; import { TransactionCallout } from '../../../components/transaction-callout'; -import { ADDRESSES } from '../../../config'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { useAppState } from '../../../contexts/app-state/app-state-context'; import { useContracts } from '../../../contexts/contracts/contracts-context'; import { @@ -25,6 +25,7 @@ export const RedeemFromTranche = () => { address: string; }>(); const { vesting } = useContracts(); + const { ADDRESSES } = useEnvironment(); const { t } = useTranslation(); const { appState: { lien, totalVestedBalance, trancheBalances, totalLockedBalance }, diff --git a/apps/token/src/routes/staking/associate/associate-transaction.tsx b/apps/token/src/routes/staking/associate/associate-transaction.tsx index 8ef0ee5fe..ab9a290fd 100644 --- a/apps/token/src/routes/staking/associate/associate-transaction.tsx +++ b/apps/token/src/routes/staking/associate/associate-transaction.tsx @@ -1,12 +1,8 @@ -import { - Button, - Callout, - EtherscanLink, - Intent, -} from '@vegaprotocol/ui-toolkit'; +import { Button, Callout, Link, Intent } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import { Link } from 'react-router-dom'; +import { Link as RouteLink } from 'react-router-dom'; import { TransactionCallout } from '../../../components/transaction-callout'; import type { @@ -35,6 +31,7 @@ export const AssociateTransaction = ({ requiredConfirmations: number; linking: PartyStakeLinkings_party_stake_linkings | null; }) => { + const { ETHERSCAN_URL } = useEnvironment(); const { t } = useTranslation(); const remainingConfirmations = React.useMemo(() => { @@ -71,7 +68,12 @@ export const AssociateTransaction = ({ })}

- + + {state.txData.hash} +

{t('pendingAssociationText', { @@ -90,11 +92,11 @@ export const AssociateTransaction = ({ { vegaKey } )} completeFooter={ - + - + } pendingHeading={t('Associating Tokens')} pendingBody={t( diff --git a/apps/token/src/routes/staking/associate/wallet-associate.tsx b/apps/token/src/routes/staking/associate/wallet-associate.tsx index 27f40c53a..099cd2c27 100644 --- a/apps/token/src/routes/staking/associate/wallet-associate.tsx +++ b/apps/token/src/routes/staking/associate/wallet-associate.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { TokenInput } from '../../../components/token-input'; -import { ADDRESSES } from '../../../config'; import { AppStateActionType, useAppState, @@ -13,6 +12,7 @@ import { useTransaction } from '../../../hooks/use-transaction'; import { BigNumber } from '../../../lib/bignumber'; import { AssociateInfo } from './associate-info'; import type { VegaKeyExtended } from '@vegaprotocol/wallet'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; export const WalletAssociate = ({ perform, @@ -27,6 +27,7 @@ export const WalletAssociate = ({ vegaKey: VegaKeyExtended; address: string; }) => { + const { ADDRESSES } = useEnvironment(); const { t } = useTranslation(); const { appDispatch, @@ -56,7 +57,13 @@ export const WalletAssociate = ({ } }; run(); - }, [address, appDispatch, approveState.txState, token]); + }, [ + address, + appDispatch, + approveState.txState, + token, + ADDRESSES.stakingBridge, + ]); let pageContent = null; diff --git a/apps/token/src/routes/staking/staking.tsx b/apps/token/src/routes/staking/staking.tsx index 1fcf4a043..74dfedef2 100644 --- a/apps/token/src/routes/staking/staking.tsx +++ b/apps/token/src/routes/staking/staking.tsx @@ -1,10 +1,11 @@ import { Button, Callout, Intent } from '@vegaprotocol/ui-toolkit'; import { useWeb3React } from '@web3-react/core'; import { Trans, useTranslation } from 'react-i18next'; -import { Link } from 'react-router-dom'; +import { Link as RouteLink } from 'react-router-dom'; import { BulletHeader } from '../../components/bullet-header'; -import { EtherscanLink } from '@vegaprotocol/ui-toolkit'; +import { Link } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { Links } from '../../config'; import { AppStateActionType, @@ -29,14 +30,9 @@ export const Staking = ({ data }: { data?: StakingQueryResult }) => {

{t('stakingDescription3')}

{t('stakingDescription4')}

- + {t('readMoreStaking')} - +

@@ -65,6 +61,7 @@ export const Staking = ({ data }: { data?: StakingQueryResult }) => { }; export const StakingStepConnectWallets = () => { + const { ETHERSCAN_URL } = useEnvironment(); const { t } = useTranslation(); const { account } = useWeb3React(); const { keypair } = useVegaWallet(); @@ -75,7 +72,12 @@ export const StakingStepConnectWallets = () => {

{t('Connected Ethereum address')}  - + + {account} +

{t('stakingVegaWalletConnected', { @@ -94,7 +96,7 @@ export const StakingStepConnectWallets = () => { components={{ vegaWalletLink: ( // eslint-disable-next-line jsx-a11y/anchor-has-content - + ), }} /> @@ -171,17 +173,17 @@ export const StakingStepAssociate = ({ title={t('stakingHasAssociated', { tokens: formatNumber(associated) })} >

- + - +

- + - +
); } @@ -189,11 +191,11 @@ export const StakingStepAssociate = ({ return ( <>

{t('stakingStep2Text')}

- + - + ); }; diff --git a/apps/token/src/routes/staking/validator-table.tsx b/apps/token/src/routes/staking/validator-table.tsx index abf90a52f..557551422 100644 --- a/apps/token/src/routes/staking/validator-table.tsx +++ b/apps/token/src/routes/staking/validator-table.tsx @@ -1,7 +1,8 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; -import { EtherscanLink } from '@vegaprotocol/ui-toolkit'; +import { Link } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { KeyValueTable, KeyValueTableRow } from '@vegaprotocol/ui-toolkit'; import { BigNumber } from '../../lib/bignumber'; import { formatNumber } from '../../lib/format-number'; @@ -22,6 +23,7 @@ export const ValidatorTable = ({ stakedTotal, stakeThisEpoch, }: ValidatorTableProps) => { + const { ETHERSCAN_URL } = useEnvironment(); const { t } = useTranslation(); const stakePercentage = React.useMemo(() => { const total = new BigNumber(stakedTotal); @@ -56,10 +58,12 @@ export const ValidatorTable = ({ {t('ETHEREUM ADDRESS')} - + + {node.ethereumAdddress} + diff --git a/apps/token/src/routes/tranches/tranche-label.spex.tsx b/apps/token/src/routes/tranches/tranche-label.spex.tsx index f246f951f..e391cca1c 100644 --- a/apps/token/src/routes/tranches/tranche-label.spex.tsx +++ b/apps/token/src/routes/tranches/tranche-label.spex.tsx @@ -1,6 +1,10 @@ import { render } from '@testing-library/react'; -import { ADDRESSES, EthereumChainIds } from '../../config'; +import { + EthereumChainIds, + EnvironmentConfig, + Networks, +} from '@vegaprotocol/smart-contracts'; import type { TrancheLabelProps } from './tranche-label'; import { TrancheLabel } from './tranche-label'; @@ -9,7 +13,7 @@ let props: TrancheLabelProps; beforeEach(() => { props = { chainId: EthereumChainIds.Mainnet, - contract: ADDRESSES.vestingAddress, + contract: EnvironmentConfig[Networks.MAINNET].vestingAddress, id: 5, }; }); diff --git a/apps/token/src/routes/tranches/tranche-label.tsx b/apps/token/src/routes/tranches/tranche-label.tsx index 8f46d9a10..54154e7f5 100644 --- a/apps/token/src/routes/tranches/tranche-label.tsx +++ b/apps/token/src/routes/tranches/tranche-label.tsx @@ -1,5 +1,6 @@ -import { ADDRESSES, EthereumChainIds } from '../../config'; -import type { EthereumChainId } from '../../config'; +import type { EthereumChainId } from '@vegaprotocol/smart-contracts'; +import { EthereumChainIds } from '@vegaprotocol/smart-contracts'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; const TRANCHE_LABELS: Record = { '5': ['Coinlist Option 1', 'Community Whitelist'], @@ -26,6 +27,7 @@ export interface TrancheLabelProps { * @param id The tranche ID on this contract */ export const TrancheLabel = ({ contract, chainId, id }: TrancheLabelProps) => { + const { ADDRESSES } = useEnvironment(); // Only mainnet tranches on the known vesting contract have useful name if ( chainId && diff --git a/apps/token/src/routes/tranches/tranche.tsx b/apps/token/src/routes/tranches/tranche.tsx index 72daa2d2f..3a429be92 100644 --- a/apps/token/src/routes/tranches/tranche.tsx +++ b/apps/token/src/routes/tranches/tranche.tsx @@ -1,4 +1,7 @@ -import type { Tranche as ITranche } from '@vegaprotocol/smart-contracts'; +import type { + Tranche as ITranche, + EthereumChainId, +} from '@vegaprotocol/smart-contracts'; import { useWeb3React } from '@web3-react/core'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -6,9 +9,8 @@ import { useParams } from 'react-router'; import { Navigate } from 'react-router-dom'; import { useOutletContext } from 'react-router-dom'; -import { EtherscanLink } from '@vegaprotocol/ui-toolkit'; -import type { EthereumChainId } from '../../config'; -import { ADDRESSES } from '../../config'; +import { Link } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { BigNumber } from '../../lib/bignumber'; import { formatNumber } from '../../lib/format-number'; import { TrancheItem } from '../redemption/tranche-item'; @@ -27,6 +29,7 @@ const TrancheProgressContents = ({ export const Tranche = () => { const tranches = useOutletContext(); + const { ADDRESSES, ETHERSCAN_URL } = useEnvironment(); const { t } = useTranslation(); const { trancheId } = useParams<{ trancheId: string }>(); const { chainId } = useWeb3React(); @@ -81,7 +84,12 @@ export const Tranche = () => { const locked = user.remaining_tokens.times(lockedData?.locked || 0); return (
  • - + + {user.address} + {t('Locked')} {t('Unlocked')} diff --git a/apps/token/src/routes/tranches/tranches.tsx b/apps/token/src/routes/tranches/tranches.tsx index 6e75325b3..fed3d559a 100644 --- a/apps/token/src/routes/tranches/tranches.tsx +++ b/apps/token/src/routes/tranches/tranches.tsx @@ -1,15 +1,14 @@ import { useOutletContext } from 'react-router-dom'; -import type { Tranche } from '@vegaprotocol/smart-contracts'; +import type { Tranche, EthereumChainId } from '@vegaprotocol/smart-contracts'; import { useWeb3React } from '@web3-react/core'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import type { EthereumChainId } from '../../config'; -import { ADDRESSES } from '../../config'; import { TrancheItem } from '../redemption/tranche-item'; import { TrancheLabel } from './tranche-label'; import { VestingChart } from './vesting-chart'; import { Button } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; const trancheMinimum = 10; @@ -17,6 +16,7 @@ const shouldShowTranche = (t: Tranche) => !t.total_added.isLessThanOrEqualTo(trancheMinimum); export const Tranches = () => { + const { ADDRESSES } = useEnvironment(); const tranches = useOutletContext(); const [showAll, setShowAll] = React.useState(false); const { t } = useTranslation(); diff --git a/apps/token/src/routes/withdrawals/index.tsx b/apps/token/src/routes/withdrawals/index.tsx index fb5685f2f..5894bafd6 100644 --- a/apps/token/src/routes/withdrawals/index.tsx +++ b/apps/token/src/routes/withdrawals/index.tsx @@ -4,7 +4,8 @@ import orderBy from 'lodash/orderBy'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import { EtherscanLink } from '@vegaprotocol/ui-toolkit'; +import { Link } from '@vegaprotocol/ui-toolkit'; +import { useEnvironment } from '@vegaprotocol/react-helpers'; import { Heading } from '../../components/heading'; import { KeyValueTable, KeyValueTableRow } from '@vegaprotocol/ui-toolkit'; import { SplashLoader } from '../../components/splash-loader'; @@ -99,6 +100,7 @@ interface WithdrawalProps { } export const Withdrawal = ({ withdrawal, complete }: WithdrawalProps) => { + const { ETHERSCAN_URL } = useEnvironment(); const { t } = useTranslation(); const renderStatus = ({ @@ -148,12 +150,12 @@ export const Withdrawal = ({ withdrawal, complete }: WithdrawalProps) => { {t('toEthereum')} - + + {truncateMiddle(withdrawal.details?.receiverAddress ?? '')} + @@ -169,10 +171,12 @@ export const Withdrawal = ({ withdrawal, complete }: WithdrawalProps) => { {t('withdrawalTransaction', { foreignChain: 'Ethereum' })} {withdrawal.txHash ? ( - + + {truncateMiddle(withdrawal.txHash)} + ) : ( '-' )} diff --git a/apps/token/tsconfig.json b/apps/token/tsconfig.json index 94e8cb37d..1572e1c47 100644 --- a/apps/token/tsconfig.json +++ b/apps/token/tsconfig.json @@ -10,8 +10,7 @@ "noImplicitOverride": true, "noPropertyAccessFromIndexSignature": false, "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "resolveJsonModule": true + "noFallthroughCasesInSwitch": true }, "files": [], "include": [], diff --git a/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts b/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts index 5ffcbae8e..961d17d0f 100644 --- a/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts +++ b/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts @@ -10,6 +10,7 @@ export const generateDealTicketQuery = ( market: { id: 'market-id', decimalPlaces: 2, + positionDecimalPlaces: 1, state: MarketState.Active, tradingMode: MarketTradingMode.Continuous, tradableInstrument: { diff --git a/apps/trading-e2e/src/support/mocks/generate-market-list.ts b/apps/trading-e2e/src/support/mocks/generate-market-list.ts new file mode 100644 index 000000000..d8dd065ff --- /dev/null +++ b/apps/trading-e2e/src/support/mocks/generate-market-list.ts @@ -0,0 +1,77 @@ +import merge from 'lodash/merge'; +import type { PartialDeep } from 'type-fest'; +import type { MarketList, MarketList_markets } from '@vegaprotocol/market-list'; + +export const generateMarketList = ( + override?: PartialDeep +): MarketList => { + const markets: MarketList_markets[] = [ + { + id: 'market-id', + decimalPlaces: 5, + data: { + market: { + id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35', + __typename: 'Market', + }, + markPrice: '4612690058', + __typename: 'MarketData', + }, + tradableInstrument: { + instrument: { + name: 'BTC/USD Monthly', + code: 'BTCUSD.MF21', + metadata: { + __typename: 'InstrumentMetadata', + tags: ['tag1'], + }, + __typename: 'Instrument', + }, + __typename: 'TradableInstrument', + }, + marketTimestamps: { + __typename: 'MarketTimestamps', + open: '', + close: '', + }, + candles: [{ __typename: 'Candle', open: '100', close: '100' }], + __typename: 'Market', + }, + { + id: 'test-market-suspended', + decimalPlaces: 2, + data: { + market: { + id: '34d95e10faa00c21d19d382d6d7e6fc9722a96985369f0caec041b0f44b775ed', + __typename: 'Market', + }, + markPrice: '8441', + __typename: 'MarketData', + }, + tradableInstrument: { + instrument: { + name: 'SOL/USD', + code: 'SOLUSD', + metadata: { + __typename: 'InstrumentMetadata', + tags: ['tag1'], + }, + __typename: 'Instrument', + }, + __typename: 'TradableInstrument', + }, + marketTimestamps: { + __typename: 'MarketTimestamps', + open: '', + close: '', + }, + candles: [{ __typename: 'Candle', open: '100', close: '100' }], + __typename: 'Market', + }, + ]; + const defaultResult = { + markets, + }; + + return merge(defaultResult, override); +}; diff --git a/apps/trading-e2e/src/support/pages/withdrawals-page.ts b/apps/trading-e2e/src/support/pages/withdrawals-page.ts index 431419ffb..94bcd8d4b 100644 --- a/apps/trading-e2e/src/support/pages/withdrawals-page.ts +++ b/apps/trading-e2e/src/support/pages/withdrawals-page.ts @@ -31,7 +31,7 @@ export default class WithdrawalsPage extends BasePage { validateConnectWalletText() { cy.getByTestId(this.connectVegaWalletText).should( 'have.text', - 'Please connect your Vega wallet' + 'Connect your Vega wallet' ); } diff --git a/apps/trading-e2e/src/support/step_definitions/common.step.ts b/apps/trading-e2e/src/support/step_definitions/common.step.ts index 15005b24c..132a6fa2d 100644 --- a/apps/trading-e2e/src/support/step_definitions/common.step.ts +++ b/apps/trading-e2e/src/support/step_definitions/common.step.ts @@ -1,9 +1,18 @@ import { Given } from 'cypress-cucumber-preprocessor/steps'; +import { hasOperationName } from '..'; +import { generateMarketList } from '../mocks/generate-market-list'; import BasePage from '../pages/base-page'; const basePage = new BasePage(); Given('I am on the homepage', () => { + cy.mockGQL('MarketsList', (req) => { + if (hasOperationName(req, 'MarketsList')) { + req.reply({ + body: { data: generateMarketList() }, + }); + } + }); cy.visit('/'); basePage.closeDialog(); }); diff --git a/apps/trading-e2e/tsconfig.json b/apps/trading-e2e/tsconfig.json index be6a16f51..9f157b52e 100644 --- a/apps/trading-e2e/tsconfig.json +++ b/apps/trading-e2e/tsconfig.json @@ -11,7 +11,7 @@ "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, + "noPropertyAccessFromIndexSignature": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true }, diff --git a/apps/trading/components/vega-wallet-container/index.ts b/apps/trading/components/vega-wallet-container/index.ts new file mode 100644 index 000000000..58aa4c53c --- /dev/null +++ b/apps/trading/components/vega-wallet-container/index.ts @@ -0,0 +1 @@ +export * from './vega-wallet-container'; diff --git a/apps/trading/components/vega-wallet-container/vega-wallet-container.spec.tsx b/apps/trading/components/vega-wallet-container/vega-wallet-container.spec.tsx new file mode 100644 index 000000000..d56ed31e2 --- /dev/null +++ b/apps/trading/components/vega-wallet-container/vega-wallet-container.spec.tsx @@ -0,0 +1,27 @@ +import { render, screen } from '@testing-library/react'; +import { VegaWalletContainer } from './vega-wallet-container'; +import type { VegaWalletContextShape } from '@vegaprotocol/wallet'; +import { VegaWalletContext } from '@vegaprotocol/wallet'; +import type { PartialDeep } from 'type-fest'; + +const generateJsx = (context: PartialDeep) => { + return ( + + +
    + + + ); +}; + +describe('VegaWalletContainer', () => { + it('doesnt render children if not connected', () => { + render(generateJsx({ keypair: null })); + expect(screen.queryByTestId('child')).not.toBeInTheDocument(); + }); + + it('renders children if connected', () => { + render(generateJsx({ keypair: { pub: '0x123' } })); + expect(screen.getByTestId('child')).toBeInTheDocument(); + }); +}); diff --git a/apps/trading/components/vega-wallet-container/vega-wallet-container.tsx b/apps/trading/components/vega-wallet-container/vega-wallet-container.tsx new file mode 100644 index 000000000..badf3bc71 --- /dev/null +++ b/apps/trading/components/vega-wallet-container/vega-wallet-container.tsx @@ -0,0 +1,34 @@ +import type { ReactNode } from 'react'; +import { t } from '@vegaprotocol/react-helpers'; +import { Button, Splash } from '@vegaprotocol/ui-toolkit'; +import { useVegaWallet } from '@vegaprotocol/wallet'; +import { useGlobalStore } from '../../stores'; + +interface VegaWalletContainerProps { + children: ReactNode; +} + +export const VegaWalletContainer = ({ children }: VegaWalletContainerProps) => { + const store = useGlobalStore(); + const { keypair } = useVegaWallet(); + + if (!keypair) { + return ( + +
    +

    + {t('Connect your Vega wallet')} +

    + +
    +
    + ); + } + + return <>{children}; +}; diff --git a/apps/trading/components/web3-container/web3-container.tsx b/apps/trading/components/web3-container/web3-container.tsx index 78ccd7ec8..2b777c8b2 100644 --- a/apps/trading/components/web3-container/web3-container.tsx +++ b/apps/trading/components/web3-container/web3-container.tsx @@ -108,11 +108,7 @@ export const Web3Content = ({ const { isActive, error, connector, chainId } = useWeb3React(); useEffect(() => { - if ( - connector?.connectEagerly && - // Dont eager connect if this is a cypress test run - 'Cypress' in window - ) { + if (connector?.connectEagerly) { connector.connectEagerly(); } }, [connector]); diff --git a/apps/trading/pages/_app.page.tsx b/apps/trading/pages/_app.page.tsx index f0045aa95..3396dc2af 100644 --- a/apps/trading/pages/_app.page.tsx +++ b/apps/trading/pages/_app.page.tsx @@ -7,81 +7,85 @@ import { VegaManageDialog, VegaWalletProvider, } from '@vegaprotocol/wallet'; +import { EnvironmentProvider } from '@vegaprotocol/react-helpers'; import { Connectors } from '../lib/vega-connectors'; -import { useMemo, useState } from 'react'; +import { useMemo } from 'react'; import { createClient } from '../lib/apollo-client'; import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit'; import { ApolloProvider } from '@apollo/client'; import { AppLoader } from '../components/app-loader'; import { VegaWalletConnectButton } from '../components/vega-wallet-connect-button'; import './styles.css'; +import { useGlobalStore } from '../stores'; function VegaTradingApp({ Component, pageProps }: AppProps) { const client = useMemo(() => createClient(process.env['NX_VEGA_URL']), []); - const [vegaWallet, setVegaWallet] = useState({ - connect: false, - manage: false, - }); + const store = useGlobalStore(); const [theme, toggleTheme] = useThemeSwitcher(); return ( - - - - - - - {t('Welcome to Vega trading!')} - - - -
    -
    - -
    - - setVegaWallet((x) => ({ ...x, connect: open })) - } - setManageDialog={(open) => - setVegaWallet((x) => ({ ...x, manage: open })) - } - /> - + + + + + + + + {t('Welcome to Vega trading!')} + + + +
    +
    + +
    + { + store.setVegaWalletConnectDialog(open); + }} + setManageDialog={(open) => { + store.setVegaWalletManageDialog(open); + }} + /> + +
    +
    + {/* @ts-ignore conflict between @types/react and nextjs internal types */} + +
    + + store.setVegaWalletConnectDialog(open) + } + /> + + store.setVegaWalletManageDialog(open) + } + />
    -
    - {/* @ts-ignore conflict between @types/react and nextjs internal types */} - -
    - - setVegaWallet((x) => ({ ...x, connect: open })) - } - /> - - setVegaWallet((x) => ({ ...x, manage: open })) - } - /> -
    - - - - + + + + + ); } diff --git a/apps/trading/pages/index.page.tsx b/apps/trading/pages/index.page.tsx index f1a0811b7..ee52b352b 100644 --- a/apps/trading/pages/index.page.tsx +++ b/apps/trading/pages/index.page.tsx @@ -1,9 +1,10 @@ import { gql, useQuery } from '@apollo/client'; -import { LandingDialog } from '@vegaprotocol/market-list'; import { MarketTradingMode } from '@vegaprotocol/types'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import sortBy from 'lodash/sortBy'; -import MarketPage from './markets/[marketId].page'; +import { useRouter } from 'next/router'; +import { useEffect } from 'react'; +import { useGlobalStore } from '../stores'; import type { MarketsLanding } from './__generated__/MarketsLanding'; const MARKETS_QUERY = gql` @@ -29,24 +30,33 @@ const marketList = ({ markets }: MarketsLanding) => ); export function Index() { + const { replace } = useRouter(); // The default market selected in the platform behind the overlay // should be the oldest market that is currently trading in continuous mode(i.e. not in auction). const { data, error, loading } = useQuery(MARKETS_QUERY); - if (data && !error && !loading) { - const marketId = marketList(data)[0]?.id; - window.history.replaceState( - data, - '', - marketId ? `/markets/${marketId}` : '/markets' - ); - } + const setLandingDialog = useGlobalStore((state) => state.setLandingDialog); + + useEffect(() => { + if (data) { + const marketId = marketList(data)[0]?.id; + + // If a default market is found, go to it with the landing dialog open + if (marketId) { + setLandingDialog(true); + replace(`/markets/${marketId}`); + } + // Fallback to the markets list page + else { + replace('/markets'); + } + } + }, [data, replace, setLandingDialog]); + return ( - <> - - - - - + + {/* Render a loading and error state but we will redirect if markets are found */} + {null} + ); } diff --git a/apps/trading/pages/markets/[marketId].page.tsx b/apps/trading/pages/markets/[marketId].page.tsx index 321b3b88d..9231e6958 100644 --- a/apps/trading/pages/markets/[marketId].page.tsx +++ b/apps/trading/pages/markets/[marketId].page.tsx @@ -7,6 +7,8 @@ import debounce from 'lodash/debounce'; import { PageQueryContainer } from '../../components/page-query-container'; import { TradeGrid, TradePanels } from './trade-grid'; import { t } from '@vegaprotocol/react-helpers'; +import { useGlobalStore } from '../../stores'; +import { LandingDialog } from '@vegaprotocol/market-list'; // Top level page query const MARKET_QUERY = gql` @@ -21,6 +23,7 @@ const MARKET_QUERY = gql` const MarketPage = ({ id }: { id?: string }) => { const { query } = useRouter(); const { w } = useWindowSize(); + const store = useGlobalStore(); // Default to first marketId query item if found const marketId = @@ -48,10 +51,18 @@ const MarketPage = ({ id }: { id?: string }) => { return {t('Market not found')}; } - return w > 960 ? ( - - ) : ( - + return ( + <> + {w > 960 ? ( + + ) : ( + + )} + store.setLandingDialog(isOpen)} + /> + ); }} /> diff --git a/apps/trading/pages/portfolio/deposit/deposit-container.tsx b/apps/trading/pages/portfolio/deposit/deposit-container.tsx index feea5b361..81672dc62 100644 --- a/apps/trading/pages/portfolio/deposit/deposit-container.tsx +++ b/apps/trading/pages/portfolio/deposit/deposit-container.tsx @@ -3,7 +3,7 @@ import { gql } from '@apollo/client'; import { PageQueryContainer } from '../../../components/page-query-container'; import type { DepositPage } from './__generated__/DepositPage'; import { DepositManager } from '@vegaprotocol/deposits'; -import { t } from '@vegaprotocol/react-helpers'; +import { t, useEnvironment } from '@vegaprotocol/react-helpers'; import { Splash } from '@vegaprotocol/ui-toolkit'; import { ASSET_FRAGMENT } from '../../../lib/query-fragments'; @@ -28,6 +28,8 @@ export const DepositContainer = ({ ethereumConfig, assetId, }: DepositContainerProps) => { + const { VEGA_ENV } = useEnvironment(); + return ( query={DEPOSIT_PAGE_QUERY} @@ -46,6 +48,7 @@ export const DepositContainer = ({ requiredConfirmations={ethereumConfig.confirmations} assets={data.assets} initialAssetId={assetId} + isFaucetable={VEGA_ENV !== 'MAINNET'} /> ); }} diff --git a/apps/trading/pages/portfolio/withdraw/index.page.tsx b/apps/trading/pages/portfolio/withdraw/index.page.tsx index f2f9d2987..99ed4b17b 100644 --- a/apps/trading/pages/portfolio/withdraw/index.page.tsx +++ b/apps/trading/pages/portfolio/withdraw/index.page.tsx @@ -1,8 +1,9 @@ -import { Web3Container } from '../../../components/web3-container'; import { useRouter } from 'next/router'; import { useMemo } from 'react'; import { WithdrawPageContainer } from './withdraw-page-container'; import { t } from '@vegaprotocol/react-helpers'; +import { VegaWalletContainer } from '../../../components/vega-wallet-container'; +import { Web3Container } from '../../../components/web3-container'; const Withdraw = () => { const { query } = useRouter(); @@ -21,14 +22,16 @@ const Withdraw = () => { }, [query]); return ( - ( -
    -

    {t('Withdraw')}

    - -
    - )} - /> + + ( +
    +

    {t('Withdraw')}

    + +
    + )} + /> +
    ); }; diff --git a/apps/trading/pages/portfolio/withdraw/withdraw-page-container.tsx b/apps/trading/pages/portfolio/withdraw/withdraw-page-container.tsx index 10aae84f6..091e81d08 100644 --- a/apps/trading/pages/portfolio/withdraw/withdraw-page-container.tsx +++ b/apps/trading/pages/portfolio/withdraw/withdraw-page-container.tsx @@ -47,14 +47,6 @@ export const WithdrawPageContainer = ({ }: WithdrawPageContainerProps) => { const { keypair } = useVegaWallet(); - if (!keypair) { - return ( -

    - {t('Please connect your Vega wallet')} -

    - ); - } - return ( query={WITHDRAW_PAGE_QUERY} diff --git a/apps/trading/pages/portfolio/withdrawals/index.page.tsx b/apps/trading/pages/portfolio/withdrawals/index.page.tsx index 9c7c5b44c..6132d1f68 100644 --- a/apps/trading/pages/portfolio/withdrawals/index.page.tsx +++ b/apps/trading/pages/portfolio/withdrawals/index.page.tsx @@ -1,30 +1,26 @@ import { t } from '@vegaprotocol/react-helpers'; -import { AnchorButton, Splash } from '@vegaprotocol/ui-toolkit'; -import { useVegaWallet } from '@vegaprotocol/wallet'; +import { AnchorButton } from '@vegaprotocol/ui-toolkit'; +import { VegaWalletContainer } from '../../../components/vega-wallet-container'; import { Web3Container } from '../../../components/web3-container'; import { WithdrawalsPageContainer } from './withdrawals-page-container'; const Withdrawals = () => { - const { keypair } = useVegaWallet(); - - if (!keypair) { - return {t('Please connect Vega wallet')}; - } - return ( - ( -
    -
    -

    {t('Withdrawals')}

    - - {t('Start withdrawal')} - -
    - -
    - )} - /> + + ( +
    +
    +

    {t('Withdrawals')}

    + + {t('Start withdrawal')} + +
    + +
    + )} + /> +
    ); }; diff --git a/apps/trading/stores/global.ts b/apps/trading/stores/global.ts new file mode 100644 index 000000000..7ade770d5 --- /dev/null +++ b/apps/trading/stores/global.ts @@ -0,0 +1,26 @@ +import type { SetState } from 'zustand'; +import create from 'zustand'; + +interface GlobalStore { + vegaWalletConnectDialog: boolean; + setVegaWalletConnectDialog: (isOpen: boolean) => void; + vegaWalletManageDialog: boolean; + setVegaWalletManageDialog: (isOpen: boolean) => void; + landingDialog: boolean; + setLandingDialog: (isOpen: boolean) => void; +} + +export const useGlobalStore = create((set: SetState) => ({ + vegaWalletConnectDialog: false, + setVegaWalletConnectDialog: (isOpen: boolean) => { + set({ vegaWalletConnectDialog: isOpen }); + }, + vegaWalletManageDialog: false, + setVegaWalletManageDialog: (isOpen: boolean) => { + set({ vegaWalletManageDialog: isOpen }); + }, + landingDialog: false, + setLandingDialog: (isOpen: boolean) => { + set({ landingDialog: isOpen }); + }, +})); diff --git a/apps/trading/stores/index.ts b/apps/trading/stores/index.ts new file mode 100644 index 000000000..7afcc369b --- /dev/null +++ b/apps/trading/stores/index.ts @@ -0,0 +1 @@ +export * from './global'; diff --git a/apps/trading/tsconfig.json b/apps/trading/tsconfig.json index c7fff463e..7f7950c0a 100644 --- a/apps/trading/tsconfig.json +++ b/apps/trading/tsconfig.json @@ -9,7 +9,6 @@ "strict": true, "forceConsistentCasingInFileNames": true, "noEmit": true, - "resolveJsonModule": true, "isolatedModules": true, "incremental": true }, diff --git a/libs/accounts/tsconfig.json b/libs/accounts/tsconfig.json index 4c089585e..1eabf319c 100644 --- a/libs/accounts/tsconfig.json +++ b/libs/accounts/tsconfig.json @@ -8,7 +8,7 @@ "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, + "noPropertyAccessFromIndexSignature": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true }, diff --git a/libs/candles-chart/tsconfig.json b/libs/candles-chart/tsconfig.json index 4c089585e..1eabf319c 100644 --- a/libs/candles-chart/tsconfig.json +++ b/libs/candles-chart/tsconfig.json @@ -8,7 +8,7 @@ "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, + "noPropertyAccessFromIndexSignature": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true }, diff --git a/libs/cypress/tsconfig.json b/libs/cypress/tsconfig.json index e567ed7bb..9925cc663 100644 --- a/libs/cypress/tsconfig.json +++ b/libs/cypress/tsconfig.json @@ -17,7 +17,7 @@ "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, + "noPropertyAccessFromIndexSignature": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true } diff --git a/libs/deal-ticket/src/__generated__/DealTicketQuery.ts b/libs/deal-ticket/src/__generated__/DealTicketQuery.ts index 87f2d3922..efb10e5c5 100644 --- a/libs/deal-ticket/src/__generated__/DealTicketQuery.ts +++ b/libs/deal-ticket/src/__generated__/DealTicketQuery.ts @@ -72,6 +72,12 @@ export interface DealTicketQuery_market { * GBX (pence) 1 4 GBP 0.000001 ( 0.0001p) */ decimalPlaces: number; + /** + * positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64). + * i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes. + * 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market. + */ + positionDecimalPlaces: number; /** * Current state of the market */ diff --git a/libs/deal-ticket/src/components/deal-ticket-amount.tsx b/libs/deal-ticket/src/components/deal-ticket-amount.tsx new file mode 100644 index 000000000..bb4350421 --- /dev/null +++ b/libs/deal-ticket/src/components/deal-ticket-amount.tsx @@ -0,0 +1,33 @@ +import type { UseFormRegister } from 'react-hook-form'; +import { OrderType } from '@vegaprotocol/wallet'; +import type { Order } from '../utils/get-default-order'; +import { DealTicketMarketAmount } from './deal-ticket-market-amount'; +import { DealTicketLimitAmount } from './deal-ticket-limit-amount'; + +export interface DealTicketAmountProps { + orderType: OrderType; + step: number; + register: UseFormRegister; + quoteName: string; + price?: string; +} + +const getAmountComponent = (type: OrderType) => { + switch (type) { + case OrderType.Market: + return DealTicketMarketAmount; + case OrderType.Limit: + return DealTicketLimitAmount; + default: { + throw new Error('Invalid ticket type'); + } + } +}; + +export const DealTicketAmount = ({ + orderType, + ...props +}: DealTicketAmountProps) => { + const AmountComponent = getAmountComponent(orderType); + return ; +}; diff --git a/libs/deal-ticket/src/deal-ticket-container.tsx b/libs/deal-ticket/src/components/deal-ticket-container.tsx similarity index 95% rename from libs/deal-ticket/src/deal-ticket-container.tsx rename to libs/deal-ticket/src/components/deal-ticket-container.tsx index f6575e476..4f3c0f6e1 100644 --- a/libs/deal-ticket/src/deal-ticket-container.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-container.tsx @@ -4,7 +4,7 @@ import { DealTicketManager } from './deal-ticket-manager'; import type { DealTicketQuery, DealTicketQuery_market, -} from './__generated__/DealTicketQuery'; +} from '../__generated__/DealTicketQuery'; import { t } from '@vegaprotocol/react-helpers'; const DEAL_TICKET_QUERY = gql` @@ -12,6 +12,7 @@ const DEAL_TICKET_QUERY = gql` market(id: $marketId) { id decimalPlaces + positionDecimalPlaces state tradingMode tradableInstrument { diff --git a/libs/deal-ticket/src/deal-ticket-limit-form.tsx b/libs/deal-ticket/src/components/deal-ticket-limit-amount.tsx similarity index 51% rename from libs/deal-ticket/src/deal-ticket-limit-form.tsx rename to libs/deal-ticket/src/components/deal-ticket-limit-amount.tsx index 52a1ee3c1..98c262246 100644 --- a/libs/deal-ticket/src/deal-ticket-limit-form.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-limit-amount.tsx @@ -1,30 +1,32 @@ import { FormGroup, Input } from '@vegaprotocol/ui-toolkit'; +import { validateSize } from '../utils/validate-size'; +import type { DealTicketAmountProps } from './deal-ticket-amount'; -export interface DealTicketLimitFormProps { - quoteName: string; - price?: string; - size: string; - onSizeChange: (size: string) => void; - onPriceChange: (price: string) => void; -} +export type DealTicketLimitAmountProps = Omit< + DealTicketAmountProps, + 'orderType' +>; -export const DealTicketLimitForm = ({ - size, - price, - onSizeChange, - onPriceChange, +export const DealTicketLimitAmount = ({ + register, + step, quoteName, -}: DealTicketLimitFormProps) => { +}: DealTicketLimitAmountProps) => { return (
    onSizeChange(e.target.value)} className="w-full" type="number" + step={step} + min={step} data-testid="order-size" + {...register('size', { + required: true, + min: step, + validate: validateSize(step), + })} />
    @@ -32,11 +34,12 @@ export const DealTicketLimitForm = ({
    onPriceChange(e.target.value)} className="w-full" type="number" + step={step} + defaultValue={0} data-testid="order-price" + {...register('price', { required: true, min: 0 })} />
    diff --git a/libs/deal-ticket/src/deal-ticket-manager.tsx b/libs/deal-ticket/src/components/deal-ticket-manager.tsx similarity index 93% rename from libs/deal-ticket/src/deal-ticket-manager.tsx rename to libs/deal-ticket/src/components/deal-ticket-manager.tsx index f0d46eec8..9796acd54 100644 --- a/libs/deal-ticket/src/deal-ticket-manager.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-manager.tsx @@ -4,9 +4,9 @@ import { Dialog, Intent } from '@vegaprotocol/ui-toolkit'; import { OrderStatus } from '@vegaprotocol/types'; import { VegaTxStatus } from '@vegaprotocol/wallet'; import { DealTicket } from './deal-ticket'; -import { useOrderSubmit } from './use-order-submit'; import { OrderDialog } from './order-dialog'; -import type { DealTicketQuery_market } from './__generated__/DealTicketQuery'; +import { useOrderSubmit } from '../hooks/use-order-submit'; +import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery'; export interface DealTicketManagerProps { market: DealTicketQuery_market; diff --git a/libs/deal-ticket/src/deal-ticket-market-form.tsx b/libs/deal-ticket/src/components/deal-ticket-market-amount.tsx similarity index 55% rename from libs/deal-ticket/src/deal-ticket-market-form.tsx rename to libs/deal-ticket/src/components/deal-ticket-market-amount.tsx index 1e06a1903..763dc6d03 100644 --- a/libs/deal-ticket/src/deal-ticket-market-form.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-market-amount.tsx @@ -1,28 +1,33 @@ import { FormGroup, Input } from '@vegaprotocol/ui-toolkit'; +import { validateSize } from '../utils/validate-size'; +import type { DealTicketAmountProps } from './deal-ticket-amount'; -export interface DealTicketMarketFormProps { - quoteName?: string; - price?: string; - size: string; - onSizeChange: (size: string) => void; -} +export type DealTicketMarketAmountProps = Omit< + DealTicketAmountProps, + 'orderType' +>; -export const DealTicketMarketForm = ({ - size, - onSizeChange, +export const DealTicketMarketAmount = ({ + register, price, + step, quoteName, -}: DealTicketMarketFormProps) => { +}: DealTicketMarketAmountProps) => { return (
    onSizeChange(e.target.value)} className="w-full" type="number" + step={step} + min={step} data-testid="order-size" + {...register('size', { + required: true, + min: step, + validate: validateSize(step), + })} />
    diff --git a/libs/deal-ticket/src/deal-ticket.spec.tsx b/libs/deal-ticket/src/components/deal-ticket.spec.tsx similarity index 80% rename from libs/deal-ticket/src/deal-ticket.spec.tsx rename to libs/deal-ticket/src/components/deal-ticket.spec.tsx index e49a50383..4691d5adf 100644 --- a/libs/deal-ticket/src/deal-ticket.spec.tsx +++ b/libs/deal-ticket/src/components/deal-ticket.spec.tsx @@ -4,22 +4,17 @@ import { OrderType, } from '@vegaprotocol/wallet'; import { addDecimal } from '@vegaprotocol/react-helpers'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen, act } from '@testing-library/react'; import { DealTicket } from './deal-ticket'; -import type { Order } from './use-order-state'; -import type { DealTicketQuery_market } from './__generated__/DealTicketQuery'; +import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery'; +import type { Order } from '../utils/get-default-order'; import { MarketState, MarketTradingMode } from '@vegaprotocol/types'; -const order: Order = { - type: OrderType.Market, - size: '100', - timeInForce: OrderTimeInForce.FOK, - side: null, -}; const market: DealTicketQuery_market = { __typename: 'Market', id: 'market-id', decimalPlaces: 2, + positionDecimalPlaces: 1, tradingMode: MarketTradingMode.Continuous, state: MarketState.Active, tradableInstrument: { @@ -43,7 +38,7 @@ const market: DealTicketQuery_market = { const submit = jest.fn(); const transactionStatus = 'default'; -function generateJsx() { +function generateJsx(order?: Order) { return ( // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -57,21 +52,23 @@ function generateJsx() { ); } -it('Deal ticket defaults', () => { +it('Displays ticket defaults', () => { render(generateJsx()); // Assert defaults are used expect( - screen.getByTestId(`order-type-${order.type}-selected`) + screen.getByTestId(`order-type-${OrderType.Market}-selected`) ).toBeInTheDocument(); expect( screen.queryByTestId('order-side-SIDE_BUY-selected') - ).not.toBeInTheDocument(); + ).toBeInTheDocument(); expect( screen.queryByTestId('order-side-SIDE_SELL-selected') ).not.toBeInTheDocument(); - expect(screen.getByTestId('order-size')).toHaveDisplayValue(order.size); - expect(screen.getByTestId('order-tif')).toHaveValue(order.timeInForce); + expect(screen.getByTestId('order-size')).toHaveDisplayValue( + String(1 / Math.pow(10, market.positionDecimalPlaces)) + ); + expect(screen.getByTestId('order-tif')).toHaveValue(OrderTimeInForce.IOC); // Assert last price is shown expect(screen.getByTestId('last-price')).toHaveTextContent( @@ -82,18 +79,18 @@ it('Deal ticket defaults', () => { ); }); -it('Can edit deal ticket', () => { +it('Can edit deal ticket', async () => { render(generateJsx()); - // Asssert changing values - fireEvent.click(screen.getByTestId('order-side-SIDE_BUY')); - expect( - screen.getByTestId('order-side-SIDE_BUY-selected') - ).toBeInTheDocument(); + // BUY is selected by default + screen.getByTestId('order-side-SIDE_BUY-selected'); - fireEvent.change(screen.getByTestId('order-size'), { - target: { value: '200' }, + await act(async () => { + fireEvent.change(screen.getByTestId('order-size'), { + target: { value: '200' }, + }); }); + expect(screen.getByTestId('order-size')).toHaveDisplayValue('200'); fireEvent.change(screen.getByTestId('order-tif'), { diff --git a/libs/deal-ticket/src/components/deal-ticket.tsx b/libs/deal-ticket/src/components/deal-ticket.tsx new file mode 100644 index 000000000..df5d2f4c7 --- /dev/null +++ b/libs/deal-ticket/src/components/deal-ticket.tsx @@ -0,0 +1,126 @@ +import { useCallback } from 'react'; +import { useForm, Controller } from 'react-hook-form'; +import { OrderType, OrderTimeInForce } from '@vegaprotocol/wallet'; +import { t, addDecimal, toDecimal } from '@vegaprotocol/react-helpers'; +import { Button, InputError } from '@vegaprotocol/ui-toolkit'; +import { TypeSelector } from './type-selector'; +import { SideSelector } from './side-selector'; +import { DealTicketAmount } from './deal-ticket-amount'; +import { TimeInForceSelector } from './time-in-force-selector'; +import { ExpirySelector } from './expiry-selector'; +import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery'; +import type { Order } from '../utils/get-default-order'; +import { getDefaultOrder } from '../utils/get-default-order'; +import { useOrderValidation } from '../hooks/use-order-validation'; + +export type TransactionStatus = 'default' | 'pending'; + +export interface DealTicketProps { + market: DealTicketQuery_market; + submit: (order: Order) => void; + transactionStatus: TransactionStatus; + defaultOrder?: Order; +} + +export const DealTicket = ({ + market, + submit, + transactionStatus, +}: DealTicketProps) => { + const { + register, + control, + handleSubmit, + watch, + formState: { errors }, + } = useForm({ + mode: 'onChange', + defaultValues: getDefaultOrder(market), + }); + + const step = toDecimal(market.positionDecimalPlaces); + const orderType = watch('type'); + const orderTimeInForce = watch('timeInForce'); + const invalidText = useOrderValidation({ + step, + market, + orderType, + orderTimeInForce, + fieldErrors: errors, + }); + const isDisabled = transactionStatus === 'pending' || Boolean(invalidText); + + const onSubmit = useCallback( + (order: Order) => { + if (!isDisabled && !invalidText) { + submit(order); + } + }, + [isDisabled, invalidText, submit] + ); + + return ( +
    + ( + + )} + /> + ( + + )} + /> + + ( + + )} + /> + {orderType === OrderType.Limit && + orderTimeInForce === OrderTimeInForce.GTT && ( + ( + + )} + /> + )} + + {invalidText && ( + + {invalidText} + + )} + + ); +}; diff --git a/libs/deal-ticket/src/expiry-selector.tsx b/libs/deal-ticket/src/components/expiry-selector.tsx similarity index 76% rename from libs/deal-ticket/src/expiry-selector.tsx rename to libs/deal-ticket/src/components/expiry-selector.tsx index dd64fa8a1..1015c3507 100644 --- a/libs/deal-ticket/src/expiry-selector.tsx +++ b/libs/deal-ticket/src/components/expiry-selector.tsx @@ -1,14 +1,13 @@ import { FormGroup, Input } from '@vegaprotocol/ui-toolkit'; -import type { Order } from './use-order-state'; import { formatForInput } from '@vegaprotocol/react-helpers'; interface ExpirySelectorProps { - order: Order; + value?: Date; onSelect: (expiration: Date | null) => void; } -export const ExpirySelector = ({ order, onSelect }: ExpirySelectorProps) => { - const date = order.expiration ? new Date(order.expiration) : new Date(); +export const ExpirySelector = ({ value, onSelect }: ExpirySelectorProps) => { + const date = value ? new Date(value) : new Date(); const dateFormatted = formatForInput(date); const minDate = formatForInput(date); return ( diff --git a/libs/deal-ticket/src/order-dialog.tsx b/libs/deal-ticket/src/components/order-dialog.tsx similarity index 97% rename from libs/deal-ticket/src/order-dialog.tsx rename to libs/deal-ticket/src/components/order-dialog.tsx index d3bbe4926..17498ec8f 100644 --- a/libs/deal-ticket/src/order-dialog.tsx +++ b/libs/deal-ticket/src/components/order-dialog.tsx @@ -1,6 +1,6 @@ import { Icon, Loader } from '@vegaprotocol/ui-toolkit'; import type { ReactNode } from 'react'; -import type { OrderEvent_busEvents_event_Order } from './__generated__/OrderEvent'; +import type { OrderEvent_busEvents_event_Order } from '../__generated__/OrderEvent'; import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers'; import type { VegaTxState } from '@vegaprotocol/wallet'; import { VegaTxStatus } from '@vegaprotocol/wallet'; diff --git a/libs/deal-ticket/src/side-selector.tsx b/libs/deal-ticket/src/components/side-selector.tsx similarity index 77% rename from libs/deal-ticket/src/side-selector.tsx rename to libs/deal-ticket/src/components/side-selector.tsx index 764d18995..ea3999cf3 100644 --- a/libs/deal-ticket/src/side-selector.tsx +++ b/libs/deal-ticket/src/components/side-selector.tsx @@ -1,14 +1,13 @@ import { FormGroup } from '@vegaprotocol/ui-toolkit'; import { OrderSide } from '@vegaprotocol/wallet'; import { Toggle } from '@vegaprotocol/ui-toolkit'; -import type { Order } from './use-order-state'; interface SideSelectorProps { - order: Order; + value: OrderSide; onSelect: (side: OrderSide) => void; } -export const SideSelector = ({ order, onSelect }: SideSelectorProps) => { +export const SideSelector = ({ value, onSelect }: SideSelectorProps) => { const toggles = Object.entries(OrderSide).map(([label, value]) => ({ label, value, @@ -19,7 +18,7 @@ export const SideSelector = ({ order, onSelect }: SideSelectorProps) => { onSelect(e.target.value as OrderSide)} /> diff --git a/libs/deal-ticket/src/time-in-force-selector.tsx b/libs/deal-ticket/src/components/time-in-force-selector.tsx similarity index 76% rename from libs/deal-ticket/src/time-in-force-selector.tsx rename to libs/deal-ticket/src/components/time-in-force-selector.tsx index a9fe72786..6af307daa 100644 --- a/libs/deal-ticket/src/time-in-force-selector.tsx +++ b/libs/deal-ticket/src/components/time-in-force-selector.tsx @@ -1,28 +1,30 @@ import { FormGroup, Select } from '@vegaprotocol/ui-toolkit'; import { OrderTimeInForce, OrderType } from '@vegaprotocol/wallet'; -import type { Order } from './use-order-state'; interface TimeInForceSelectorProps { - order: Order; + value: OrderTimeInForce; + orderType: OrderType; onSelect: (tif: OrderTimeInForce) => void; } export const TimeInForceSelector = ({ - order, + value, + orderType, onSelect, }: TimeInForceSelectorProps) => { const options = - order.type === OrderType.Limit + orderType === OrderType.Limit ? Object.entries(OrderTimeInForce) : Object.entries(OrderTimeInForce).filter( - ([_, value]) => - value === OrderTimeInForce.FOK || value === OrderTimeInForce.IOC + ([_, timeInForce]) => + timeInForce === OrderTimeInForce.FOK || + timeInForce === OrderTimeInForce.IOC ); return (