Compare commits

...
Author SHA1 Message Date
Bill He 279e0d193a address nit 2023-10-02 18:06:44 -04:00
Bill He 95b3c54e0b remove alchemy 2023-09-27 16:31:06 -04:00
Bill He 4f57d4c7e0 Add all squid evm networks to wagmi 2023-09-27 15:14:35 -04:00
Bill 6c63e66bd6 bump abacus (#48)
* bump abacus

* bump again
2023-09-27 13:54:22 -04:00
Bill 50606a750f Add Rewards abacus transactions and trade form receipt (#47)
* temp

* add into reciept

* bump localization

* add tag
2023-09-25 17:45:46 -04:00
Bill fe46a4d927 Do not poll evm unless addressOrDenom is provided (#46) 2023-09-25 14:56:20 -04:00
Bill 68e5cb8680 Do not get token balance on withdraw (#45) 2023-09-22 17:12:54 -07:00
Bill dea36da7bf Use abacus for simulate transactions and balance polling (#43)
* Use abacus for simulate transactions and balance polling

* address comment

* use dydx gas token

* address nits
2023-09-22 14:21:42 -07:00
22 changed files with 346 additions and 316 deletions
+3 -3
View File
@@ -37,9 +37,9 @@
"@cosmjs/proto-signing": "^0.31.0",
"@cosmjs/stargate": "^0.31.0",
"@cosmjs/tendermint-rpc": "^0.31.0",
"@dydxprotocol/v4-abacus": "^0.5.0",
"@dydxprotocol/v4-abacus": "^0.5.12",
"@dydxprotocol/v4-client-js": "^0.36.1",
"@dydxprotocol/v4-localization": "^0.1.11",
"@dydxprotocol/v4-localization": "^0.1.12",
"@ethersproject/providers": "^5.7.2",
"@js-joda/core": "^5.5.3",
"@radix-ui/react-collapsible": "^1.0.3",
@@ -105,7 +105,7 @@
"reselect": "^4.1.8",
"styled-components": "^5.3.11",
"use-latest": "^1.2.1",
"viem": "^1.1.6",
"viem": "^1.12.2",
"wagmi": "^1.3.7"
},
"devDependencies": {
+85 -63
View File
@@ -27,14 +27,14 @@ dependencies:
specifier: ^0.31.0
version: 0.31.0
'@dydxprotocol/v4-abacus':
specifier: ^0.5.0
version: 0.5.0
specifier: ^0.5.12
version: 0.5.12
'@dydxprotocol/v4-client-js':
specifier: ^0.36.1
version: 0.36.1
'@dydxprotocol/v4-localization':
specifier: ^0.1.11
version: 0.1.11
specifier: ^0.1.12
version: 0.1.12
'@ethersproject/providers':
specifier: ^5.7.2
version: 5.7.2
@@ -231,11 +231,11 @@ dependencies:
specifier: ^1.2.1
version: 1.2.1(@types/react@18.2.14)(react@18.2.0)
viem:
specifier: ^1.1.6
version: 1.1.6(typescript@5.1.3)
specifier: ^1.12.2
version: 1.12.2(typescript@5.1.3)
wagmi:
specifier: ^1.3.7
version: 1.3.7(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3)(viem@1.1.6)
version: 1.3.7(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3)(viem@1.12.2)
devDependencies:
'@babel/core':
@@ -380,14 +380,14 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/@adraffy/ens-normalize@1.9.0:
resolution: {integrity: sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ==}
dev: false
/@adraffy/ens-normalize@1.9.2:
resolution: {integrity: sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg==}
dev: false
/@adraffy/ens-normalize@1.9.4:
resolution: {integrity: sha512-UK0bHA7hh9cR39V+4gl2/NnBBjoXIxkuWAPCaY4X7fbH4L/azIi7ilWOCjMUYfpJgraLUAqkRi2BqrjME8Rynw==}
dev: false
/@ampproject/remapping@2.2.1:
resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
engines: {node: '>=6.0.0'}
@@ -979,8 +979,8 @@ packages:
resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
dev: true
/@dydxprotocol/v4-abacus@0.5.0:
resolution: {integrity: sha512-K/aLJeOWzmToCn6p9vjBqfwn79/nuKxjZLSzaj1mKNxw25KBFh2q93njNbONFRA72zBElD0K+gw8J/skTpGg1Q==}
/@dydxprotocol/v4-abacus@0.5.12:
resolution: {integrity: sha512-OigoIjGtp0az1elkP84nc9qKYBVg5Fg4QEJFDn7J7oiUqVvwNggYNfnDsX77D8+K4DJ/rtbi2yZYsDE8OZMSoQ==}
dev: false
/@dydxprotocol/v4-client-js@0.36.1:
@@ -1010,8 +1010,8 @@ packages:
- utf-8-validate
dev: false
/@dydxprotocol/v4-localization@0.1.11:
resolution: {integrity: sha512-eW88t8KJuDT0fNEgaw615+n3gEYxDZYPeHhdBYquVDXjnkhLNznaH8ftmlLPVPyfu7o5aFeU/cw8ZiqRrf/Stw==}
/@dydxprotocol/v4-localization@0.1.12:
resolution: {integrity: sha512-EiP/8+6Nk9QBa6YSWsyzsZaXoVbz5o/KgUlMp1Cew6VWkXL6DkQY0oMIEEy21pv0zuu/woxhlbyXygpUIcpdMg==}
dev: false
/@dydxprotocol/v4-proto@0.2.1:
@@ -2032,6 +2032,12 @@ packages:
'@noble/hashes': 1.3.1
dev: false
/@noble/curves@1.2.0:
resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==}
dependencies:
'@noble/hashes': 1.3.2
dev: false
/@noble/ed25519@1.7.3:
resolution: {integrity: sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==}
dev: true
@@ -2049,6 +2055,11 @@ packages:
engines: {node: '>= 16'}
dev: false
/@noble/hashes@1.3.2:
resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==}
engines: {node: '>= 16'}
dev: false
/@noble/secp256k1@1.7.1:
resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==}
@@ -4647,7 +4658,7 @@ packages:
resolution: {integrity: sha512-gYw0ki/EAuV1oSyMxpqandHjnthZjYYy+YWpTAzf8BqfXM3ItcZLpjxfg+3+mXW8HIO+3jw6T9iiqEXsqHaMMw==}
dependencies:
'@safe-global/safe-gateway-typescript-sdk': 3.9.0
viem: 1.1.6(typescript@5.1.3)
viem: 1.12.2(typescript@5.1.3)
transitivePeerDependencies:
- bufferutil
- encoding
@@ -4660,7 +4671,7 @@ packages:
resolution: {integrity: sha512-XJbEPuaVc7b9n23MqlF6c+ToYIS3f7P2Sel8f3cSBQ9WORE4xrSuvhMpK9fDSFqJ7by/brc+rmJR/5HViRr0/w==}
dependencies:
'@safe-global/safe-gateway-typescript-sdk': 3.9.0
viem: 1.1.6(typescript@5.1.3)
viem: 1.12.2(typescript@5.1.3)
transitivePeerDependencies:
- bufferutil
- encoding
@@ -4681,6 +4692,10 @@ packages:
resolution: {integrity: sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==}
dev: false
/@scure/base@1.1.3:
resolution: {integrity: sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q==}
dev: false
/@scure/bip32@1.3.0:
resolution: {integrity: sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==}
dependencies:
@@ -4697,6 +4712,14 @@ packages:
'@scure/base': 1.1.1
dev: false
/@scure/bip32@1.3.2:
resolution: {integrity: sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==}
dependencies:
'@noble/curves': 1.2.0
'@noble/hashes': 1.3.2
'@scure/base': 1.1.3
dev: false
/@scure/bip39@1.2.0:
resolution: {integrity: sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==}
dependencies:
@@ -4707,7 +4730,7 @@ packages:
/@scure/bip39@1.2.1:
resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==}
dependencies:
'@noble/hashes': 1.3.1
'@noble/hashes': 1.3.2
'@scure/base': 1.1.1
dev: false
@@ -5408,6 +5431,12 @@ packages:
'@types/node': 20.3.1
dev: false
/@types/ws@8.5.6:
resolution: {integrity: sha512-8B5EO9jLVCy+B58PLHvLDuOD8DRVMgQzq8d55SjLCOn9kqGyqOvy27exVaTio1q1nX5zLu8/6N0n2ThSxOM6tg==}
dependencies:
'@types/node': 20.3.1
dev: false
/@typescript-eslint/eslint-plugin@5.60.0(@typescript-eslint/parser@5.60.0)(eslint@8.43.0)(typescript@5.1.3):
resolution: {integrity: sha512-78B+anHLF1TI8Jn/cD0Q00TBYdMgjdOn980JfAVa9yw5sop8nyTfVOQAv6LWywkOGLclDBtv5z3oxN4w7jxyNg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -5904,17 +5933,6 @@ packages:
pretty-format: 27.5.1
dev: true
/@wagmi/chains@1.2.0(typescript@5.1.3):
resolution: {integrity: sha512-dmDRipsE54JfyudOBkuhEexqQWcrZqxn/qiujG8SBzMh/az/AH5xlJSA+j1CPWTx9+QofSMF3B7A4gb6XRmSaQ==}
peerDependencies:
typescript: '>=5.0.4'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
typescript: 5.1.3
dev: false
/@wagmi/chains@1.4.0(typescript@5.1.3):
resolution: {integrity: sha512-9HwJrhcZ1TxyrCbE10y7s1eSiSiyfGam7AHIOLYExaOX+vpOZ+MNTt4orFEDbEpz1fxwJDPPI38lanAUix1OSA==}
peerDependencies:
@@ -5926,7 +5944,7 @@ packages:
typescript: 5.1.3
dev: false
/@wagmi/connectors@2.6.5(@wagmi/chains@1.4.0)(react@18.2.0)(typescript@5.1.3)(viem@1.1.6):
/@wagmi/connectors@2.6.5(@wagmi/chains@1.4.0)(react@18.2.0)(typescript@5.1.3)(viem@1.12.2):
resolution: {integrity: sha512-klF31togMDd0qQqEcLl5cCGxjMbL0RRXQ8I1vxmEa3KdGzw6Z3ICVzX7/bDfnNEZcOW7BKyAnZDq7rCt5jTOiw==}
peerDependencies:
'@wagmi/chains': '>=1.3.0'
@@ -5950,7 +5968,7 @@ packages:
abitype: 0.8.7(typescript@5.1.3)
eventemitter3: 4.0.7
typescript: 5.1.3
viem: 1.1.6(typescript@5.1.3)
viem: 1.12.2(typescript@5.1.3)
transitivePeerDependencies:
- '@react-native-async-storage/async-storage'
- bufferutil
@@ -5962,7 +5980,7 @@ packages:
- zod
dev: false
/@wagmi/core@1.3.6(@types/react@18.2.14)(react@18.2.0)(typescript@5.1.3)(viem@1.1.6):
/@wagmi/core@1.3.6(@types/react@18.2.14)(react@18.2.0)(typescript@5.1.3)(viem@1.12.2):
resolution: {integrity: sha512-TXv9ZlRR5aySfERFuWMuo+lKXC/CoqtxVJZVHPqhK1jY+nldMx3AvrWzzF4CccRaMYcVdvPFepvmxzq2A2VvWg==}
peerDependencies:
typescript: '>=5.0.4'
@@ -5972,11 +5990,11 @@ packages:
optional: true
dependencies:
'@wagmi/chains': 1.4.0(typescript@5.1.3)
'@wagmi/connectors': 2.6.5(@wagmi/chains@1.4.0)(react@18.2.0)(typescript@5.1.3)(viem@1.1.6)
'@wagmi/connectors': 2.6.5(@wagmi/chains@1.4.0)(react@18.2.0)(typescript@5.1.3)(viem@1.12.2)
abitype: 0.8.7(typescript@5.1.3)
eventemitter3: 4.0.7
typescript: 5.1.3
viem: 1.1.6(typescript@5.1.3)
viem: 1.12.2(typescript@5.1.3)
zustand: 4.4.1(@types/react@18.2.14)(react@18.2.0)
transitivePeerDependencies:
- '@react-native-async-storage/async-storage'
@@ -6677,6 +6695,20 @@ packages:
typescript: 5.1.3
dev: false
/abitype@0.9.8(typescript@5.1.3):
resolution: {integrity: sha512-puLifILdm+8sjyss4S+fsUN09obiT1g2YW6CtcQF+QDzxR0euzgEB29MZujC6zMk2a6SVmtttq1fc6+YFA7WYQ==}
peerDependencies:
typescript: '>=5.0.4'
zod: ^3 >=3.19.1
peerDependenciesMeta:
typescript:
optional: true
zod:
optional: true
dependencies:
typescript: 5.1.3
dev: false
/abort-controller@3.0.0:
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
engines: {node: '>=6.5'}
@@ -9986,12 +10018,12 @@ packages:
ws: 7.5.9
dev: false
/isomorphic-ws@5.0.0(ws@8.12.0):
/isomorphic-ws@5.0.0(ws@8.13.0):
resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==}
peerDependencies:
ws: '*'
dependencies:
ws: 8.12.0
ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)
dev: false
/it-all@1.0.6:
@@ -13520,21 +13552,24 @@ packages:
vfile-message: 3.1.4
dev: true
/viem@1.1.6(typescript@5.1.3):
resolution: {integrity: sha512-7nK3HMucLr1Yz0QnDXiD6viigKS6QeYD/YhRHpi3Bby/g0hCyZqK8+YJNtp3/Ri64tpl4kaTIeCScJWV2jqXHQ==}
/viem@1.12.2(typescript@5.1.3):
resolution: {integrity: sha512-aCaUCyg72ES+jK4s6tVYOMnOt4if71RwzgiUAUpAuaCgvHFfh9DCnwuEfwkxEZLE2vafOsirgJ3fcn7nsDVQoQ==}
peerDependencies:
typescript: '>=5.0.4'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@adraffy/ens-normalize': 1.9.0
'@noble/curves': 1.0.0
'@noble/hashes': 1.3.0
'@scure/bip32': 1.3.0
'@scure/bip39': 1.2.0
'@wagmi/chains': 1.2.0(typescript@5.1.3)
abitype: 0.8.7(typescript@5.1.3)
isomorphic-ws: 5.0.0(ws@8.12.0)
'@adraffy/ens-normalize': 1.9.4
'@noble/curves': 1.2.0
'@noble/hashes': 1.3.2
'@scure/bip32': 1.3.2
'@scure/bip39': 1.2.1
'@types/ws': 8.5.6
abitype: 0.9.8(typescript@5.1.3)
isomorphic-ws: 5.0.0(ws@8.13.0)
typescript: 5.1.3
ws: 8.12.0
ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)
transitivePeerDependencies:
- bufferutil
- utf-8-validate
@@ -13702,7 +13737,7 @@ packages:
- supports-color
dev: true
/wagmi@1.3.7(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3)(viem@1.1.6):
/wagmi@1.3.7(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3)(viem@1.12.2):
resolution: {integrity: sha512-n4Qwby0QB8/JSGjc0gGn4MWZ0BT229agEg6saPGS6VswmPjJLdkLq9qxKn1JptXxPREmb/ZvwHxU++3Z+gQJVA==}
peerDependencies:
react: '>=17.0.0'
@@ -13715,12 +13750,12 @@ packages:
'@tanstack/query-sync-storage-persister': 4.32.6
'@tanstack/react-query': 4.32.6(react-dom@18.2.0)(react@18.2.0)
'@tanstack/react-query-persist-client': 4.32.6(@tanstack/react-query@4.32.6)
'@wagmi/core': 1.3.6(@types/react@18.2.14)(react@18.2.0)(typescript@5.1.3)(viem@1.1.6)
'@wagmi/core': 1.3.6(@types/react@18.2.14)(react@18.2.0)(typescript@5.1.3)(viem@1.12.2)
abitype: 0.8.7(typescript@5.1.3)
react: 18.2.0
typescript: 5.1.3
use-sync-external-store: 1.2.0(react@18.2.0)
viem: 1.1.6(typescript@5.1.3)
viem: 1.12.2(typescript@5.1.3)
transitivePeerDependencies:
- '@react-native-async-storage/async-storage'
- '@types/react'
@@ -13945,19 +13980,6 @@ packages:
optional: true
dev: false
/ws@8.12.0:
resolution: {integrity: sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dev: false
/ws@8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10):
resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==}
engines: {node: '>=10.0.0'}
+8 -9
View File
@@ -69,8 +69,8 @@ export type NetworkConfig = {
export type ConnectNetworkEvent = CustomEvent<Partial<NetworkConfig>>;
// ------ State ------
export type AbacusApiState = Abacus.exchange.dydx.abacus.state.app.ApiState;
export const AbacusApiStatus = Abacus.exchange.dydx.abacus.state.app.ApiStatus;
export type AbacusApiState = Abacus.exchange.dydx.abacus.state.manager.ApiState;
export const AbacusApiStatus = Abacus.exchange.dydx.abacus.state.manager.ApiStatus;
const abacusApiStatuses = [...AbacusApiStatus.values()];
export type AbacusApiStatuses = (typeof abacusApiStatuses)[number];
export const Changes = Abacus.exchange.dydx.abacus.state.changes.Changes;
@@ -122,6 +122,7 @@ export const InputSelectionOption = Abacus.exchange.dydx.abacus.output.input.Sel
// ------ Wallet ------ //
export type Wallet = Abacus.exchange.dydx.abacus.output.Wallet;
export type AccountBalance = Abacus.exchange.dydx.abacus.output.AccountBalance;
export type Subaccount = Abacus.exchange.dydx.abacus.output.Subaccount;
export type SubaccountPosition = Abacus.exchange.dydx.abacus.output.SubaccountPosition;
export type SubaccountOrder = Abacus.exchange.dydx.abacus.output.SubaccountOrder;
@@ -138,7 +139,7 @@ export type SubaccountTransfers = Abacus.exchange.dydx.abacus.output.SubaccountT
// ------ Historical PnL ------ //
export type SubAccountHistoricalPNL = Abacus.exchange.dydx.abacus.output.SubaccountHistoricalPNL;
export type SubAccountHistoricalPNLs = Abacus.exchange.dydx.abacus.output.SubaccountHistoricalPNL[];
export const HistoricalPnlPeriod = Abacus.exchange.dydx.abacus.state.app.HistoricalPnlPeriod;
export const HistoricalPnlPeriod = Abacus.exchange.dydx.abacus.protocols.HistoricalPnlPeriod;
const historicalPnlPeriod = [...HistoricalPnlPeriod.values()] as const;
export type HistoricalPnlPeriods = (typeof historicalPnlPeriod)[number];
@@ -178,16 +179,14 @@ export const AbacusOrderSide = Abacus.exchange.dydx.abacus.output.input.OrderSid
export const AbacusPositionSide = Abacus.exchange.dydx.abacus.output.PositionSide;
export type AbacusPositionSides = Abacus.exchange.dydx.abacus.output.PositionSide;
export type SubaccountPlaceOrderPayload =
Abacus.exchange.dydx.abacus.state.app.V4SubaccountPlaceOrderPayload2;
export type SubaccountCancelOrderPayload =
Abacus.exchange.dydx.abacus.state.app.V4SubaccountCancelOrderPayload2;
export type HumanReadablePlaceOrderPayload =
Abacus.exchange.dydx.abacus.state.manager.HumanReadablePlaceOrderPayload;
export type HumanReadableCancelOrderPayload =
Abacus.exchange.dydx.abacus.state.manager.HumanReadableCancelOrderPayload;
export type HumanReadableWithdrawPayload =
Abacus.exchange.dydx.abacus.state.manager.HumanReadableWithdrawPayload;
export type HumanReadableTransferPayload =
Abacus.exchange.dydx.abacus.state.manager.HumanReadableTransferPayload;
// ------ Helpers ------ //
export const AbacusHelper = Abacus.exchange.dydx.abacus.utils.AbacusHelper;
+4
View File
@@ -94,6 +94,10 @@ export const tradeTooltips: TooltipStrings = {
title: stringGetter({ key: TOOLTIP_STRING_KEYS.MAINTENANCE_MARGIN_FRACTION_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.MAINTENANCE_MARGIN_FRACTION_BODY }),
}),
'max-reward': ({ stringGetter }) => ({
title: stringGetter({ key: TOOLTIP_STRING_KEYS.MAXIMUM_REWARDS_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.MAXIMUM_REWARDS_BODY }),
}),
'max-withdraw': ({ stringGetter }) => ({
title: stringGetter({ key: TOOLTIP_STRING_KEYS.MAX_WITHDRAW_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.MAX_WITHDRAW_BODY }),
+8 -2
View File
@@ -383,12 +383,18 @@ export const DYDX_CHAIN_INFO: Parameters<typeof suggestChain>[0] = {
features: [],
};
// TODO: export this type from abacus instead
export enum DydxChainAsset {
USDC = 'USDC',
DYDX = 'Dv4TNT',
USDC = 'usdc',
DYDX = 'dydx',
}
export const DYDX_CHAIN_ASSET_COIN_DENOM: Record<DydxChainAsset, string> = {
[DydxChainAsset.USDC]: USDC_DENOM,
[DydxChainAsset.DYDX]: DYDX_DENOM,
};
export const DYDX_CHAIN_ASSET_TAGS: Record<DydxChainAsset, string> = {
[DydxChainAsset.USDC]: 'USDC',
[DydxChainAsset.DYDX]: 'Dv4TNT',
};
+10 -8
View File
@@ -1,10 +1,12 @@
import { useCallback } from 'react';
import { useSelector } from 'react-redux';
import { shallowEqual, useSelector } from 'react-redux';
import { useBalance } from 'wagmi';
import { StargateClient } from '@cosmjs/stargate';
import { useQuery } from 'react-query';
import { formatUnits } from 'viem';
import { USDC_DENOM, DYDX_DENOM } from '@dydxprotocol/v4-client-js';
import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks';
import { QUANTUM_MULTIPLIER } from '@/constants/numbers';
import { EvmAddress } from '@/constants/wallets';
@@ -12,11 +14,10 @@ import { EvmAddress } from '@/constants/wallets';
import { convertBech32Address } from '@/lib/addressUtils';
import { MustBigNumber } from '@/lib/numbers';
import { getBalances } from '@/state/accountSelectors';
import { getSelectedNetwork } from '@/state/appSelectors';
import { useAccounts } from './useAccounts';
import { usePollNativeTokenBalance } from './usePollNativeTokenBalance';
import { usePollUSDCBalance } from './usePollUSDCBalance';
type UseAccountBalanceProps = {
// Token Items
@@ -36,10 +37,10 @@ type UseAccountBalanceProps = {
* 0xSquid uses this 0x address as the chain's default token.
* @todo We will need to add additional logic here if we 'useAccountBalance' on non-Squid related forms.
*/
const CHAIN_DEFAULT_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
export const CHAIN_DEFAULT_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
export const useAccountBalance = ({
addressOrDenom = CHAIN_DEFAULT_TOKEN_ADDRESS,
addressOrDenom,
assetSymbol,
bech32AddrPrefix,
chainId,
@@ -50,6 +51,7 @@ export const useAccountBalance = ({
const { evmAddress, dydxAddress } = useAccounts();
const selectedNetwork = useSelector(getSelectedNetwork);
const balances = useSelector(getBalances, shallowEqual);
const evmChainId = Number(CLIENT_NETWORK_CONFIGS[selectedNetwork].ethereumChainId);
const evmQuery = useBalance({
@@ -92,12 +94,12 @@ export const useAccountBalance = ({
const { formatted: evmBalance } = evmQuery.data || {};
const balance = !assetSymbol ? '0' : isCosmosChain ? cosmosQuery.data : evmBalance;
const nativeTokenCoinBalance = usePollNativeTokenBalance({ dydxAddress });
const nativeTokenCoinBalance = balances?.[DYDX_DENOM];
const nativeTokenBalance = MustBigNumber(nativeTokenCoinBalance?.amount)
.div(QUANTUM_MULTIPLIER)
.toNumber();
const usdcCoinBalance = usePollUSDCBalance({ dydxAddress });
const usdcCoinBalance = balances?.[USDC_DENOM];
const usdcBalance = MustBigNumber(usdcCoinBalance?.amount).div(QUANTUM_MULTIPLIER).toNumber();
return {
+4 -3
View File
@@ -6,7 +6,7 @@ import { LocalStorageKey } from '@/constants/localStorage';
import { type TransferNotifcation } from '@/constants/notifications';
import { useAccounts } from '@/hooks/useAccounts';
import { SQUID_ERROR_TYPES, useSquid } from '@/hooks/useSquid';
import { STATUS_ERROR_GRACE_PERIOD, useSquid } from '@/hooks/useSquid';
import { useLocalStorage } from './useLocalStorage';
const LocalNotificationsContext = createContext<
@@ -62,6 +62,7 @@ const useLocalNotificationsContext = () => {
txHash,
toChainId,
fromChainId,
triggeredAt,
status: currentStatus,
} of transferNotifications) {
try {
@@ -70,8 +71,8 @@ const useLocalNotificationsContext = () => {
const status = await squid?.getStatus({ transactionId: txHash, toChainId, fromChainId });
if (status) statuses[txHash] = status;
} catch (error) {
// ignore not found errors since the route might not be available yet
if (error?.errors?.length && error.errors[0].errorType !== SQUID_ERROR_TYPES.NotFoundError) {
// ignore errors for the first 120s since the status might not be available yet
if (!triggeredAt || Date.now() - triggeredAt > STATUS_ERROR_GRACE_PERIOD) {
statuses[txHash] = error;
}
}
-31
View File
@@ -1,31 +0,0 @@
import { useQuery } from 'react-query';
import { useAccounts } from '@/hooks';
import { DydxAddress } from '@/constants/wallets';
import { DYDX_DENOM } from '@dydxprotocol/v4-client-js';
const ACCOUNT_BALANCE_POLLING_INTERVAL = 60_000;
export const usePollNativeTokenBalance = ({
dydxAddress,
interval = ACCOUNT_BALANCE_POLLING_INTERVAL,
}: {
dydxAddress?: DydxAddress;
interval?: number;
}) => {
const { getAccountBalance } = useAccounts();
const { data } = useQuery({
enabled: dydxAddress !== undefined,
queryKey: ['usePollNativeTokenBalance', { dydxAddress }],
queryFn: async () => {
if (!dydxAddress) return;
return await getAccountBalance({ dydxAddress, denom: DYDX_DENOM });
},
refetchInterval: interval,
staleTime: interval,
});
return data;
};
-30
View File
@@ -1,30 +0,0 @@
import { useQuery } from 'react-query';
import { useAccounts } from '@/hooks';
import { DydxAddress } from '@/constants/wallets';
const ACCOUNT_BALANCE_POLLING_INTERVAL = 60_000;
export const usePollUSDCBalance = ({
dydxAddress,
interval = ACCOUNT_BALANCE_POLLING_INTERVAL,
}: {
dydxAddress?: DydxAddress;
interval?: number;
}) => {
const { getAccountBalance } = useAccounts();
const { data } = useQuery({
enabled: dydxAddress !== undefined,
queryKey: ['usePollUSDCBalance', { dydxAddress }],
queryFn: async () => {
if (!dydxAddress) return;
return await getAccountBalance({ dydxAddress });
},
refetchInterval: interval,
staleTime: interval,
});
return data;
};
+1 -3
View File
@@ -8,9 +8,7 @@ import { getSelectedNetwork } from '@/state/appSelectors';
export const NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
export enum SQUID_ERROR_TYPES {
NotFoundError = 'NotFoundError',
}
export const STATUS_ERROR_GRACE_PERIOD = 120_000;
const useSquidContext = () => {
const selectedNetwork = useSelector(getSelectedNetwork);
+12 -86
View File
@@ -1,5 +1,5 @@
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { useDispatch } from 'react-redux';
import { shallowEqual, useSelector, useDispatch } from 'react-redux';
import type { Nullable } from '@dydxprotocol/v4-abacus';
import Long from 'long';
import type { IndexedTx } from '@cosmjs/stargate';
@@ -11,10 +11,10 @@ import {
SubaccountClient,
DYDX_DENOM,
USDC_DENOM,
GAS_PRICE_DYDX_DENOM,
} from '@dydxprotocol/v4-client-js';
import type {
AccountBalance,
HumanReadablePlaceOrderPayload,
ParsingError,
SubAccountHistoricalPNLs,
@@ -26,6 +26,7 @@ import { QUANTUM_MULTIPLIER } from '@/constants/numbers';
import { DydxAddress } from '@/constants/wallets';
import { setSubaccount, setHistoricalPnl, removeUncommittedOrderClientId } from '@/state/account';
import { getBalances } from '@/state/accountSelectors';
import abacusStateManager from '@/lib/abacus';
import { track } from '@/lib/analytics';
@@ -34,7 +35,7 @@ import { log } from '@/lib/telemetry';
import { useAccounts } from './useAccounts';
import { useDydxClient } from './useDydxClient';
import { usePollUSDCBalance } from './usePollUSDCBalance';
type SubaccountContextType = ReturnType<typeof useSubaccountContext>;
const SubaccountContext = createContext<SubaccountContextType>({} as SubaccountContextType);
@@ -70,10 +71,8 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
const {
depositToSubaccount,
withdrawFromSubaccount,
simulateWithdrawFromSubaccount,
transferFromSubaccountToAddress,
transferNativeToken,
simulateTransferNativeToken,
sendSquidWithdrawFromSubaccount,
} = useMemo(
() => ({
@@ -95,31 +94,6 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
amount: number;
}) => await compositeClient?.withdrawFromSubaccount(subaccountClient, amount),
simulateWithdrawFromSubaccount: async ({
subaccountClient,
amount,
recipient,
}: {
subaccountClient: SubaccountClient;
amount: number;
recipient?: string;
}) => {
return await compositeClient?.simulate(
subaccountClient?.wallet,
() =>
new Promise((resolve) => {
const msg = compositeClient?.withdrawFromSubaccountMessage(
subaccountClient,
amount,
recipient
);
resolve([msg]);
}),
undefined
);
},
transferFromSubaccountToAddress: async ({
subaccountClient,
assetId = 0,
@@ -170,31 +144,6 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
Method.BroadcastTxCommit
),
simulateTransferNativeToken: async ({
subaccountClient,
amount,
recipient,
}: {
subaccountClient: SubaccountClient;
amount: number;
recipient: string;
}) =>
await compositeClient?.simulate(
subaccountClient?.wallet,
() =>
new Promise((resolve) => {
const msg = compositeClient?.validatorClient.post.composer.composeMsgSendToken(
subaccountClient.address,
recipient,
DYDX_DENOM,
Long.fromNumber(amount * QUANTUM_MULTIPLIER)
);
resolve([msg]);
}),
GAS_PRICE_DYDX_DENOM,
undefined
),
sendSquidWithdrawFromSubaccount: async ({
subaccountClient,
amount,
@@ -244,10 +193,10 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
// ------ Deposit/Withdraw Methods ------ //
const depositFunds = useCallback(
async (balance?: Coin) => {
async (balance: AccountBalance) => {
if (!localDydxWallet) return;
const amountAfterDust = MustBigNumber(balance?.amount)
const amountAfterDust = MustBigNumber(balance.amount)
.minus(AMOUNT_RESERVED_FOR_GAS_USDC) // keep 0.1 USDC in user's wallet for gas
.toString();
@@ -261,11 +210,14 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
[localDydxWallet, depositToSubaccount]
);
const balance = usePollUSDCBalance({ dydxAddress });
const balances = useSelector(getBalances, shallowEqual);
const usdcCoinBalance = balances?.[USDC_DENOM];
useEffect(() => {
depositFunds(balance);
}, [balance]);
if (usdcCoinBalance) {
depositFunds(usdcCoinBalance);
}
}, [usdcCoinBalance]);
const deposit = useCallback(
async (amount: Long) => {
@@ -304,30 +256,6 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
[subaccountClient, transferFromSubaccountToAddress, transferNativeToken]
);
const simulateTransfer = useCallback(
async (amount: number, recipient: string, coinDenom: string) => {
if (!subaccountClient) {
return;
}
return await (coinDenom === USDC_DENOM
? simulateWithdrawFromSubaccount
: simulateTransferNativeToken)({ subaccountClient, amount, recipient });
},
[subaccountClient, simulateWithdrawFromSubaccount, simulateTransferNativeToken]
);
const simulateWithdraw = useCallback(
async (amount: number) => {
if (!subaccountClient) {
return;
}
return await simulateWithdrawFromSubaccount({ subaccountClient, amount });
},
[subaccountClient, simulateWithdrawFromSubaccount]
);
const sendSquidWithdraw = useCallback(
async (amount: number, payload: string) => {
if (!subaccountClient) {
@@ -437,9 +365,7 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
requestFaucetFunds,
// Transfer Methods
simulateTransfer,
transfer,
simulateWithdraw,
sendSquidWithdraw,
// Trading Methods
+109
View File
@@ -14,6 +14,8 @@ import {
OrderSide,
OrderTimeInForce,
OrderExecution,
DYDX_DENOM,
GAS_PRICE_DYDX_DENOM,
} from '@dydxprotocol/v4-client-js';
import {
@@ -24,10 +26,13 @@ import {
type TransactionTypes,
type HumanReadablePlaceOrderPayload,
type HumanReadableCancelOrderPayload,
type HumanReadableWithdrawPayload,
type HumanReadableTransferPayload,
} from '@/constants/abacus';
import { DialogTypes } from '@/constants/dialogs';
import { UNCOMMITTED_ORDER_TIMEOUT_MS } from '@/constants/trade';
import { QUANTUM_MULTIPLIER } from '@/constants/numbers';
import { RootStore } from '@/state/_store';
import { addUncommittedOrderClientId, removeUncommittedOrderClientId } from '@/state/account';
@@ -229,6 +234,76 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
}
}
async simulateWithdrawTransaction(params: HumanReadableWithdrawPayload): Promise<string> {
if (!this.compositeClient || !this.localWallet) {
throw new Error('Missing compositeClient or localWallet');
}
const { subaccountNumber, amount } = params ?? {};
const compositeClient = this.compositeClient;
const subaccountClient = new SubaccountClient(this.localWallet, subaccountNumber);
try {
const tx = await compositeClient.simulate(
this.localWallet,
() =>
new Promise((resolve) => {
const msg = compositeClient.withdrawFromSubaccountMessage(subaccountClient, amount);
resolve([msg]);
}),
);
const parsedTx = this.parseToPrimitives(tx);
return JSON.stringify(parsedTx);
} catch (error) {
log('DydxChainTransactions/simulateWithdrawTransaction', error);
return JSON.stringify({
error,
});
}
}
async simulateTransferNativeTokenTransaction(params: HumanReadableTransferPayload): Promise<string> {
if (!this.compositeClient || !this.localWallet) {
throw new Error('Missing compositeClient or localWallet');
}
const { subaccountNumber, amount, recipient } = params ?? {};
const compositeClient = this.compositeClient;
const subaccountClient = new SubaccountClient(this.localWallet, subaccountNumber);
try {
const tx = await compositeClient.simulate(
this.localWallet,
() =>
new Promise((resolve) => {
const msg = compositeClient?.validatorClient.post.composer.composeMsgSendToken(
subaccountClient.address,
recipient,
DYDX_DENOM,
Long.fromNumber(amount * QUANTUM_MULTIPLIER)
);
resolve([msg]);
}),
GAS_PRICE_DYDX_DENOM,
);
const parsedTx = this.parseToPrimitives(tx);
return JSON.stringify(parsedTx);
} catch (error) {
log('DydxChainTransactions/simulateTransferNativeTokenTransaction', error);
return JSON.stringify({
error,
});
}
}
async transaction(
type: TransactionTypes,
paramsInJson: Abacus.Nullable<string>,
@@ -248,6 +323,16 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
callback(result);
break;
}
case TransactionType.simulateWithdraw: {
const result = await this.simulateWithdrawTransaction(params);
callback(result);
break;
}
case TransactionType.simulateTransferNativeToken: {
const result = await this.simulateTransferNativeTokenTransaction(params);
callback(result);
break;
}
default: {
break;
}
@@ -310,6 +395,30 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
const parsedUserStats = this.parseToPrimitives(userStats);
callback(JSON.stringify(parsedUserStats));
break;
case QueryType.GetAccountBalances:
if (!this.localWallet?.address) throw new Error('Missing localWallet');
const accountBalances = await this.compositeClient?.validatorClient.get.getAccountBalances(
this.localWallet.address
);
const parsedAccountBalances = this.parseToPrimitives(accountBalances);
callback(JSON.stringify(parsedAccountBalances));
break;
case QueryType.RewardsParams:
const rewardsParams = await this.compositeClient?.validatorClient.get.getRewardsParams();
const parsedRewardsParams = this.parseToPrimitives(rewardsParams);
callback(JSON.stringify(parsedRewardsParams));
break;
case QueryType.GetMarketPrice:
const price = await this.compositeClient?.validatorClient.get.getPrice(params.marketId);
const parsedPrice = this.parseToPrimitives(price);
callback(JSON.stringify(parsedPrice));
break;
case QueryType.GetDelegations:
const delegations =
await this.compositeClient?.validatorClient.get.getDelegatorDelegations(params.address);
const parseDelegations = this.parseToPrimitives(delegations);
callback(JSON.stringify(parseDelegations));
break;
// Do not implement Transfers (yet)
case QueryType.Transfers:
default:
+12
View File
@@ -1,6 +1,7 @@
import { kollections } from '@dydxprotocol/v4-abacus';
import type {
AccountBalance,
AbacusApiState,
AbacusNotification,
AbacusStateNotificationProtocol,
@@ -18,6 +19,7 @@ import { Changes } from '@/constants/abacus';
import type { RootStore } from '@/state/_store';
import {
setBalances,
setFills,
setFundingPayments,
setHistoricalPnl,
@@ -72,6 +74,16 @@ class AbacusStateNotifier implements AbacusStateNotificationProtocol {
);
}
if (changes.has(Changes.accountBalances)) {
if (updatedState.account?.balances) {
const balances: Record<string, AccountBalance> = {}
for (const { k, v } of updatedState.account.balances.toArray()) {
balances[k] = v;
}
dispatch(setBalances(balances));
}
}
if (changes.has(Changes.configs)) {
dispatch(setConfigs(updatedState.configs));
}
+34 -2
View File
@@ -10,7 +10,23 @@ import {
bscTestnet,
optimism,
optimismGoerli,
} from 'wagmi/chains';
base,
baseGoerli,
polygon,
polygonMumbai,
linea,
lineaTestnet,
mantle,
mantleTestnet,
moonbeam,
moonbaseAlpha,
filecoin,
filecoinHyperspace,
fantom,
fantomTestnet,
celo,
celoAlfajores,
} from 'viem/chains';
import { alchemyProvider } from 'wagmi/providers/alchemy';
import { jsonRpcProvider } from 'wagmi/providers/jsonRpc';
@@ -36,10 +52,26 @@ export const WAGMI_SUPPORTED_CHAINS: Chain[] = [
bscTestnet,
optimism,
optimismGoerli,
base,
baseGoerli,
polygon,
polygonMumbai,
linea,
lineaTestnet,
mantle,
mantleTestnet,
moonbeam,
moonbaseAlpha,
filecoin,
filecoinHyperspace,
fantom,
fantomTestnet,
celo,
celoAlfajores,
];
const { chains, publicClient, webSocketPublicClient } = configureChains(WAGMI_SUPPORTED_CHAINS, [
alchemyProvider({ apiKey: import.meta.env.VITE_ALCHEMY_API_KEY }),
// alchemyProvider({ apiKey: import.meta.env.VITE_ALCHEMY_API_KEY }),
jsonRpcProvider({
rpc: (chain) => ({ http: chain.rpcUrls.default.http[0] }),
}),
+6
View File
@@ -1,6 +1,7 @@
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
import type {
AccountBalance,
SubaccountFill,
Nullable,
Subaccount,
@@ -35,6 +36,7 @@ export type AccountState = {
wallet?: Nullable<Wallet>;
walletType?: WalletType;
historicalPnlPeriod?: HistoricalPnlPeriods;
balances?: Record<string, AccountBalance>;
};
const initialState: AccountState = {
@@ -149,6 +151,9 @@ export const accountSlice = createSlice({
viewedOrders: (state) => {
state.hasUnseenOrderUpdates = false;
},
setBalances: (state, action: PayloadAction<Record<string, AccountBalance>>) => {
state.balances = action.payload;
},
addUncommittedOrderClientId: (state, action: PayloadAction<number>) => {
state.uncommittedOrderClientIds.push(action.payload);
},
@@ -173,6 +178,7 @@ export const {
setWallet,
viewedFills,
viewedOrders,
setBalances,
addUncommittedOrderClientId,
removeUncommittedOrderClientId,
} = accountSlice.actions;
+5
View File
@@ -332,3 +332,8 @@ export const getUserStats = (state: RootState) => ({
makerVolume30D: state.account?.wallet?.user?.makerVolume30D,
takerVolume30D: state.account?.wallet?.user?.takerVolume30D,
});
/**
* @returns user wallet balances
*/
export const getBalances = (state: RootState) => state.account?.balances;
@@ -14,7 +14,7 @@ import { NumberSign } from '@/constants/numbers';
import type { EvmAddress } from '@/constants/wallets';
import { useAccounts, useDebounce, useStringGetter } from '@/hooks';
import { useAccountBalance } from '@/hooks/useAccountBalance';
import { useAccountBalance, CHAIN_DEFAULT_TOKEN_ADDRESS } from '@/hooks/useAccountBalance';
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
import { NATIVE_TOKEN_ADDRESS, useSquid } from '@/hooks/useSquid';
import { useWalletConnection } from '@/hooks/useWalletConnection';
@@ -86,7 +86,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
// Async Data
const { balance, queryStatus, isQueryFetching } = useAccountBalance({
addressOrDenom: sourceToken?.address || undefined,
addressOrDenom: sourceToken?.address || CHAIN_DEFAULT_TOKEN_ADDRESS,
assetSymbol: sourceToken?.symbol || undefined,
chainId: chainId,
decimals: sourceToken?.decimals || undefined,
@@ -217,7 +217,6 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
!requestPayload.data ||
!requestPayload.value ||
!requestPayload.gasLimit ||
!requestPayload.gasPrice ||
!requestPayload.routeType
) {
throw new Error('Missing request payload');
@@ -43,7 +43,7 @@ export const WithdrawForm = () => {
const [error, setError] = useState<Error | null>(null);
const [isLoading, setIsLoading] = useState(false);
const { simulateWithdraw, sendSquidWithdraw } = useSubaccount();
const { sendSquidWithdraw } = useSubaccount();
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
// User input
@@ -97,16 +97,10 @@ export const WithdrawForm = () => {
field: TransferInputField.usdcSize,
});
} else {
const stdFee = await simulateWithdraw(parseFloat(debouncedAmount));
const amount =
parseFloat(debouncedAmount) -
parseFloat(stdFee?.amount[0]?.amount || '0') / QUANTUM_MULTIPLIER;
abacusStateManager.setTransferValue({
value: amount.toString(),
value: debouncedAmount,
field: TransferInputField.usdcSize,
});
setError(null);
}
} catch (error) {
@@ -49,15 +49,15 @@ export const WithdrawButtonAndReceipt = ({
const [isEditingSlippage, setIsEditingSlipapge] = useState(false);
const stringGetter = useStringGetter();
const { balance, queryStatus } = useAccountBalance({
addressOrDenom: withdrawToken?.address || undefined,
assetSymbol: withdrawToken?.symbol || undefined,
chainId: withdrawChain ? parseInt(withdrawChain) : undefined,
decimals: withdrawToken?.decimals || undefined,
isCosmosChain: false,
});
// TODO: uncomment when we have a way to get token amount estimate from abacus
// const { balance, queryStatus } = useAccountBalance({
// addressOrDenom: withdrawToken?.address || undefined,
// assetSymbol: withdrawToken?.symbol || undefined,
// chainId: withdrawChain ? parseInt(withdrawChain) : undefined,
// decimals: withdrawToken?.decimals || undefined,
// isCosmosChain: false,
// });
// const balanceBN = MustBigNumber(balance);
// const newBalance =
// // toAmountMin && withdrawToken && parseUnits(toAmountMin, withdrawToken.decimals).toString();
@@ -158,7 +158,7 @@ export const WithdrawButtonAndReceipt = ({
// },
];
const isFormValid = !isDisabled && !isEditingSlippage && queryStatus !== 'error';
const isFormValid = !isDisabled && !isEditingSlippage;
return (
<Styled.WithReceipt
@@ -9,6 +9,7 @@ import { TRADE_TYPE_STRINGS, MobilePlaceOrderSteps } from '@/constants/trade';
import { useStringGetter } from '@/hooks';
import { AssetIcon } from '@/components/AssetIcon';
import { Button } from '@/components/Button';
import { Output, OutputType, ShowSign } from '@/components/Output';
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
@@ -62,7 +63,7 @@ export const PlaceOrderButtonAndReceipt = ({
const selectedTradeType = getSelectedTradeType(type);
const selectedOrderSide = getSelectedOrderSide(side);
const { fee, price: expectedPrice, total } = summary || {};
const { fee, price: expectedPrice, total, reward } = summary || {};
const items = [
{
@@ -79,6 +80,17 @@ export const PlaceOrderButtonAndReceipt = ({
label: stringGetter({ key: STRING_KEYS.FEE }),
value: <Output type={OutputType.Fiat} value={fee} useGrouping />,
},
{
key: 'max-reward',
label: (
<>
{stringGetter({ key: STRING_KEYS.MAXIMUM_REWARDS })}
{/* <AssetIcon symbol="DYDX" /> */}
</>
),
value: <Output type={OutputType.Asset} value={reward} useGrouping tag={reward ? "Dv4TNT" : ''} />,
tooltip: 'max-reward',
},
{
key: 'total',
label: stringGetter({ key: STRING_KEYS.TOTAL }),
+16 -52
View File
@@ -13,7 +13,7 @@ import { ButtonShape, ButtonSize } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks';
import { NumberSign, QUANTUM_MULTIPLIER } from '@/constants/numbers';
import { DYDX_CHAIN_ASSET_COIN_DENOM, DydxChainAsset } from '@/constants/wallets';
import { DYDX_CHAIN_ASSET_COIN_DENOM, DYDX_CHAIN_ASSET_TAGS, DydxChainAsset } from '@/constants/wallets';
import {
useAccountBalance,
@@ -52,28 +52,6 @@ type TransferFormProps = {
className?: string;
};
const debouncedEstimateFee = debounce(
async ({ amount, recipientAddress, asset, setFees, simulateTransfer }) => {
if (!amount || !recipientAddress) {
return;
}
try {
const coinDenom = DYDX_CHAIN_ASSET_COIN_DENOM[asset as DydxChainAsset];
const stdFee: StdFee = await simulateTransfer(amount, recipientAddress, coinDenom);
const fee = stdFee?.amount.find((coin) => coin.denom === coinDenom)?.amount;
const feeAmount = MustBigNumber(fee).div(QUANTUM_MULTIPLIER).toNumber();
setFees(feeAmount);
} catch (error) {
console.error('TransferForm > : debouncedEstimateFee > ', error);
}
},
1000,
{ trailing: true }
);
export const TransferForm = ({
selectedAsset = DydxChainAsset.DYDX,
onDone,
@@ -82,8 +60,8 @@ export const TransferForm = ({
const stringGetter = useStringGetter();
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
const { dydxAddress } = useAccounts();
const { address: recipientAddress, size } = useSelector(getTransferInputs, shallowEqual) || {};
const { transfer, simulateTransfer } = useSubaccount();
const { address: recipientAddress, size, fee } = useSelector(getTransferInputs, shallowEqual) || {};
const { transfer } = useSubaccount();
const { nativeTokenBalance, usdcBalance } = useAccountBalance();
const { selectedNetwork } = useSelectedNetwork();
@@ -93,7 +71,6 @@ export const TransferForm = ({
// Form states
const [error, setError] = useState<Error | undefined>();
const [isLoading, setIsLoading] = useState(false);
const [fees, setFees] = useState<number>();
const balance = asset === DydxChainAsset.USDC ? freeCollateral?.current : nativeTokenBalance;
const newBalance =
@@ -104,7 +81,7 @@ export const TransferForm = ({
.toNumber();
const amount = asset === DydxChainAsset.USDC ? size?.usdcSize : size?.size;
const showNotEnoughGasWarning = fees && asset === DydxChainAsset.USDC && usdcBalance < fees;
const showNotEnoughGasWarning = fee && asset === DydxChainAsset.USDC && usdcBalance < fee;
// BN
const amountBN = MustBigNumber(amount);
@@ -134,34 +111,21 @@ export const TransferForm = ({
useEffect(() => {
setError(undefined);
debouncedEstimateFee.cancel();
if (isAmountValid && isAddressValid) {
debouncedEstimateFee({
amount,
recipientAddress,
asset,
setFees,
simulateTransfer,
});
} else {
setFees(undefined);
}
}, [asset, amount, recipientAddress]);
useEffect(() => {
setError(undefined);
abacusStateManager.setTransferValue({
value: asset,
field: TransferInputField.token,
});
}, [asset]);
const onTransfer = async () => {
if (!isAmountValid || !isAddressValid || !fees) return;
if (!isAmountValid || !isAddressValid || !fee) return;
setIsLoading(true);
setError(undefined);
try {
// Subtract fees from amount if sending native tokens
const amountToTransfer = (
asset === DydxChainAsset.DYDX ? amountBN.minus(fees) : amountBN
asset === DydxChainAsset.DYDX ? amountBN.minus(fee) : amountBN
).toNumber();
const txResponse = await transfer(
@@ -212,7 +176,7 @@ export const TransferForm = ({
value: DydxChainAsset.USDC,
label: (
<Styled.InlineRow>
<AssetIcon symbol="USDC" /> USDC
<AssetIcon symbol="USDC" /> {DYDX_CHAIN_ASSET_TAGS[DydxChainAsset.USDC]}
</Styled.InlineRow>
),
},
@@ -221,7 +185,7 @@ export const TransferForm = ({
label: (
<Styled.InlineRow>
{/* <AssetIcon symbol="DYDX" /> */}
Dv4TNT
{DYDX_CHAIN_ASSET_TAGS[DydxChainAsset.DYDX]}
</Styled.InlineRow>
),
},
@@ -243,7 +207,7 @@ export const TransferForm = ({
key: 'amount',
label: (
<span>
{stringGetter({ key: STRING_KEYS.AVAILABLE })} <Tag>{asset}</Tag>
{stringGetter({ key: STRING_KEYS.AVAILABLE })} <Tag>{DYDX_CHAIN_ASSET_TAGS[asset]}</Tag>
</span>
),
value: (
@@ -375,9 +339,9 @@ export const TransferForm = ({
<Styled.Footer>
<TransferButtonAndReceipt
selectedAsset={asset}
fees={fees}
isDisabled={!isAmountValid || !isAddressValid || !fees}
isLoading={isLoading || Boolean(isAmountValid && isAddressValid && !fees)}
fees={fee || undefined}
isDisabled={!isAmountValid || !isAddressValid || !fee}
isLoading={isLoading || Boolean(isAmountValid && isAddressValid && !fee)}
/>
</Styled.Footer>
</Styled.Form>
@@ -3,7 +3,7 @@ import { shallowEqual, useSelector } from 'react-redux';
import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { NumberSign } from '@/constants/numbers';
import { DydxChainAsset } from '@/constants/wallets';
import { DYDX_CHAIN_ASSET_TAGS, DydxChainAsset } from '@/constants/wallets';
import { useAccountBalance, useStringGetter } from '@/hooks';
@@ -60,7 +60,7 @@ export const TransferButtonAndReceipt = ({
key: 'fees',
label: (
<span>
{stringGetter({ key: STRING_KEYS.FEES })} <Tag>{selectedAsset}</Tag>
{stringGetter({ key: STRING_KEYS.FEES })} <Tag>{DYDX_CHAIN_ASSET_TAGS[selectedAsset]}</Tag>
</span>
),
value: <Output type={OutputType.Asset} value={fees} />,
@@ -69,7 +69,7 @@ export const TransferButtonAndReceipt = ({
key: 'balance',
label: (
<span>
{stringGetter({ key: STRING_KEYS.BALANCE })} <Tag>{selectedAsset}</Tag>
{stringGetter({ key: STRING_KEYS.BALANCE })} <Tag>{DYDX_CHAIN_ASSET_TAGS[selectedAsset]}</Tag>
</span>
),
value: (