Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f593b40854 | ||
|
|
5c4fcf04d2 | ||
|
|
54181a1f52 | ||
|
|
e6750589db | ||
|
|
6c63e66bd6 | ||
|
|
50606a750f | ||
|
|
fe46a4d927 | ||
|
|
68e5cb8680 | ||
|
|
dea36da7bf | ||
|
|
f7d052f52e | ||
|
|
51906f1096 | ||
|
|
9a230401cd | ||
|
|
342bd2d334 | ||
|
|
cf68740725 |
+3
-3
@@ -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.4.20",
|
||||
"@dydxprotocol/v4-client-js": "^0.33.1",
|
||||
"@dydxprotocol/v4-localization": "^0.1.5",
|
||||
"@dydxprotocol/v4-abacus": "^0.5.12",
|
||||
"@dydxprotocol/v4-client-js": "^0.36.1",
|
||||
"@dydxprotocol/v4-localization": "^0.1.12",
|
||||
"@ethersproject/providers": "^5.7.2",
|
||||
"@js-joda/core": "^5.5.3",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
|
||||
Generated
+35
-241
@@ -1,5 +1,9 @@
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
'@0xsquid/sdk':
|
||||
specifier: ^1.10.0
|
||||
@@ -23,14 +27,14 @@ dependencies:
|
||||
specifier: ^0.31.0
|
||||
version: 0.31.0
|
||||
'@dydxprotocol/v4-abacus':
|
||||
specifier: ^0.4.20
|
||||
version: 0.4.20
|
||||
specifier: ^0.5.12
|
||||
version: 0.5.12
|
||||
'@dydxprotocol/v4-client-js':
|
||||
specifier: ^0.33.1
|
||||
version: 0.33.1
|
||||
specifier: ^0.36.1
|
||||
version: 0.36.1
|
||||
'@dydxprotocol/v4-localization':
|
||||
specifier: ^0.1.5
|
||||
version: 0.1.5
|
||||
specifier: ^0.1.12
|
||||
version: 0.1.12
|
||||
'@ethersproject/providers':
|
||||
specifier: ^5.7.2
|
||||
version: 5.7.2
|
||||
@@ -610,74 +614,6 @@ packages:
|
||||
'@babel/helper-validator-identifier': 7.22.5
|
||||
to-fast-properties: 2.0.0
|
||||
|
||||
/@bufbuild/buf-darwin-arm64@1.19.0-1:
|
||||
resolution: {integrity: sha512-HsWPii21wm3QSyuxrNq9+Yf8iAgpnC4rNCy4x3d6P1fd/LmgE1NPzQW0ghEZvl9dgAQKkL/4S5bKhlm7kbUdmQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@bufbuild/buf-darwin-x64@1.19.0-1:
|
||||
resolution: {integrity: sha512-2+Ig7ylYpVh4kms/OeJJVY+X0KX4awPA6hYr7L7aZOIcHwZEM8lWtSTO/se5pQc7dc8FXNiC4YUqHC8yfxxX6Q==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@bufbuild/buf-linux-aarch64@1.19.0-1:
|
||||
resolution: {integrity: sha512-g/Vxg3WiBr3nhsxsRr2Q81xXJD+0ktHIO3ZJggTG2Sbbl3dh8kyg1iKM6MjJiMP7su5RKCylLigzoEJzVTShyA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@bufbuild/buf-linux-x64@1.19.0-1:
|
||||
resolution: {integrity: sha512-anYuGx8k/2kp8GPX3eHNUf3IY/01Zpnyw0HaLPXK1Btqyy6XkapVywrDqg7YUzMd1ySFEp1wD9UqRNdEFNCQ4A==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@bufbuild/buf-win32-arm64@1.19.0-1:
|
||||
resolution: {integrity: sha512-xXgF1qYnCfRKbGx1FqvPbpZ6ajh4ddxpXhSxI3VCeb3MsMBuIbiLqX4fQAL3ls/Zwz8tVIITuSwOhYmSEGcpBA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@bufbuild/buf-win32-x64@1.19.0-1:
|
||||
resolution: {integrity: sha512-futmqgpMQCR1lcAzZJEGjPr7ECw1gYTPIV8crm5SY+iCJ7sOeStOBNt7q5hV4LKmmeWmvm03XIMZPjhQzjH5NQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@bufbuild/buf@1.19.0-1:
|
||||
resolution: {integrity: sha512-TIsLTTQUntr/Xq/IMSULv3dlC3/ZsVwQtWgxmJ++IzSuOW79TFQfq59vFeTWrPa6+QXFMz5t6jkMyD4ghzO5nw==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
'@bufbuild/buf-darwin-arm64': 1.19.0-1
|
||||
'@bufbuild/buf-darwin-x64': 1.19.0-1
|
||||
'@bufbuild/buf-linux-aarch64': 1.19.0-1
|
||||
'@bufbuild/buf-linux-x64': 1.19.0-1
|
||||
'@bufbuild/buf-win32-arm64': 1.19.0-1
|
||||
'@bufbuild/buf-win32-x64': 1.19.0-1
|
||||
dev: false
|
||||
|
||||
/@coinbase/wallet-sdk@3.7.1:
|
||||
resolution: {integrity: sha512-LjyoDCB+7p0waQXfK+fUgcAs3Ezk6S6e+LYaoFjpJ6c9VTop3NyZF40Pi7df4z7QJohCwzuIDjz0Rhtig6Y7Pg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
@@ -722,15 +658,6 @@ packages:
|
||||
'@cosmjs/utils': 0.27.1
|
||||
dev: false
|
||||
|
||||
/@cosmjs/amino@0.29.3:
|
||||
resolution: {integrity: sha512-BFz1++ERerIggiFc7iGHhGe1CeV3rCv8BvkoBQTBN/ZwzHOaKvqQj8smDlRGlQxX3HWlTwgiLN2A+OB5yX4ZRw==}
|
||||
dependencies:
|
||||
'@cosmjs/crypto': 0.29.5
|
||||
'@cosmjs/encoding': 0.29.5
|
||||
'@cosmjs/math': 0.29.5
|
||||
'@cosmjs/utils': 0.29.5
|
||||
dev: false
|
||||
|
||||
/@cosmjs/amino@0.30.1:
|
||||
resolution: {integrity: sha512-yNHnzmvAlkETDYIpeCTdVqgvrdt1qgkOXwuRVi8s27UKI5hfqyE9fJ/fuunXE6ZZPnKkjIecDznmuUOMrMvw4w==}
|
||||
dependencies:
|
||||
@@ -784,18 +711,6 @@ packages:
|
||||
sha.js: 2.4.11
|
||||
dev: false
|
||||
|
||||
/@cosmjs/crypto@0.29.5:
|
||||
resolution: {integrity: sha512-2bKkaLGictaNL0UipQCL6C1afaisv6k8Wr/GCLx9FqiyFkh9ZgRHDyetD64ZsjnWV/N/D44s/esI+k6oPREaiQ==}
|
||||
dependencies:
|
||||
'@cosmjs/encoding': 0.29.5
|
||||
'@cosmjs/math': 0.29.5
|
||||
'@cosmjs/utils': 0.29.5
|
||||
'@noble/hashes': 1.3.1
|
||||
bn.js: 5.2.1
|
||||
elliptic: 6.5.4
|
||||
libsodium-wrappers: 0.7.11
|
||||
dev: false
|
||||
|
||||
/@cosmjs/crypto@0.30.1:
|
||||
resolution: {integrity: sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ==}
|
||||
dependencies:
|
||||
@@ -828,14 +743,6 @@ packages:
|
||||
readonly-date: 1.0.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/encoding@0.29.5:
|
||||
resolution: {integrity: sha512-G4rGl/Jg4dMCw5u6PEZHZcoHnUBlukZODHbm/wcL4Uu91fkn5jVo5cXXZcvs4VCkArVGrEj/52eUgTZCmOBGWQ==}
|
||||
dependencies:
|
||||
base64-js: 1.5.1
|
||||
bech32: 1.1.4
|
||||
readonly-date: 1.0.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/encoding@0.30.1:
|
||||
resolution: {integrity: sha512-rXmrTbgqwihORwJ3xYhIgQFfMSrwLu1s43RIK9I8EBudPx3KmnmyAKzMOVsRDo9edLFNuZ9GIvysUCwQfq3WlQ==}
|
||||
dependencies:
|
||||
@@ -852,11 +759,12 @@ packages:
|
||||
readonly-date: 1.0.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/json-rpc@0.29.5:
|
||||
resolution: {integrity: sha512-C78+X06l+r9xwdM1yFWIpGl03LhB9NdM1xvZpQHwgCOl0Ir/WV8pw48y3Ez2awAoUBRfTeejPe4KvrE6NoIi/w==}
|
||||
/@cosmjs/encoding@0.31.1:
|
||||
resolution: {integrity: sha512-IuxP6ewwX6vg9sUJ8ocJD92pkerI4lyG8J5ynAM3NaX3q+n+uMoPRSQXNeL9bnlrv01FF1kIm8if/f5F7ZPtkA==}
|
||||
dependencies:
|
||||
'@cosmjs/stream': 0.29.5
|
||||
xstream: 11.14.0
|
||||
base64-js: 1.5.1
|
||||
bech32: 1.1.4
|
||||
readonly-date: 1.0.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/json-rpc@0.30.1:
|
||||
@@ -893,12 +801,6 @@ packages:
|
||||
bn.js: 5.2.1
|
||||
dev: false
|
||||
|
||||
/@cosmjs/math@0.29.5:
|
||||
resolution: {integrity: sha512-2GjKcv+A9f86MAWYLUkjhw1/WpRl2R1BTb3m9qPG7lzMA7ioYff9jY5SPCfafKdxM4TIQGxXQlYGewQL16O68Q==}
|
||||
dependencies:
|
||||
bn.js: 5.2.1
|
||||
dev: false
|
||||
|
||||
/@cosmjs/math@0.30.1:
|
||||
resolution: {integrity: sha512-yaoeI23pin9ZiPHIisa6qqLngfnBR/25tSaWpkTm8Cy10MX70UF5oN4+/t1heLaM6SSmRrhk3psRkV4+7mH51Q==}
|
||||
dependencies:
|
||||
@@ -911,16 +813,10 @@ packages:
|
||||
bn.js: 5.2.1
|
||||
dev: false
|
||||
|
||||
/@cosmjs/proto-signing@0.29.3:
|
||||
resolution: {integrity: sha512-Ai3l9THjMOrLJ4Ebn1Dgptwg6W5ZIRJqtnJjijHhGwTVC1WT0WdYU3aMZ7+PwubcA/cA1rH4ZTK7jrfYbra63g==}
|
||||
/@cosmjs/math@0.31.1:
|
||||
resolution: {integrity: sha512-kiuHV6m6DSB8/4UV1qpFhlc4ul8SgLXTGRlYkYiIIP4l0YNeJ+OpPYaOlEgx4Unk2mW3/O2FWYj7Jc93+BWXng==}
|
||||
dependencies:
|
||||
'@cosmjs/amino': 0.29.3
|
||||
'@cosmjs/crypto': 0.29.5
|
||||
'@cosmjs/encoding': 0.29.5
|
||||
'@cosmjs/math': 0.29.5
|
||||
'@cosmjs/utils': 0.29.5
|
||||
cosmjs-types: 0.5.2
|
||||
long: 4.0.0
|
||||
bn.js: 5.2.1
|
||||
dev: false
|
||||
|
||||
/@cosmjs/proto-signing@0.30.1:
|
||||
@@ -947,18 +843,6 @@ packages:
|
||||
long: 4.0.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/socket@0.29.5:
|
||||
resolution: {integrity: sha512-5VYDupIWbIXq3ftPV1LkS5Ya/T7Ol/AzWVhNxZ79hPe/mBfv1bGau/LqIYOm2zxGlgm9hBHOTmWGqNYDwr9LNQ==}
|
||||
dependencies:
|
||||
'@cosmjs/stream': 0.29.5
|
||||
isomorphic-ws: 4.0.1(ws@7.5.9)
|
||||
ws: 7.5.9
|
||||
xstream: 11.14.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@cosmjs/socket@0.30.1:
|
||||
resolution: {integrity: sha512-r6MpDL+9N+qOS/D5VaxnPaMJ3flwQ36G+vPvYJsXArj93BjgyFB7BwWwXCQDzZ+23cfChPUfhbINOenr8N2Kow==}
|
||||
dependencies:
|
||||
@@ -983,27 +867,6 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@cosmjs/stargate@0.29.3:
|
||||
resolution: {integrity: sha512-455TgXStCi6E8KDjnhDAM8wt6aLSjobH4Dixvd7Up1DfCH6UB9NkC/G0fMJANNcNXMaM4wSX14niTXwD1d31BA==}
|
||||
dependencies:
|
||||
'@confio/ics23': 0.6.8
|
||||
'@cosmjs/amino': 0.29.3
|
||||
'@cosmjs/encoding': 0.29.5
|
||||
'@cosmjs/math': 0.29.5
|
||||
'@cosmjs/proto-signing': 0.29.3
|
||||
'@cosmjs/stream': 0.29.5
|
||||
'@cosmjs/tendermint-rpc': 0.29.5
|
||||
'@cosmjs/utils': 0.29.5
|
||||
cosmjs-types: 0.5.2
|
||||
long: 4.0.0
|
||||
protobufjs: 6.11.4
|
||||
xstream: 11.14.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- debug
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@cosmjs/stargate@0.30.1:
|
||||
resolution: {integrity: sha512-RdbYKZCGOH8gWebO7r6WvNnQMxHrNXInY/gPHPzMjbQF6UatA6fNM2G2tdgS5j5u7FTqlCI10stNXrknaNdzog==}
|
||||
dependencies:
|
||||
@@ -1046,12 +909,6 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@cosmjs/stream@0.29.5:
|
||||
resolution: {integrity: sha512-TToTDWyH1p05GBtF0Y8jFw2C+4783ueDCmDyxOMM6EU82IqpmIbfwcdMOCAm0JhnyMh+ocdebbFvnX/sGKzRAA==}
|
||||
dependencies:
|
||||
xstream: 11.14.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/stream@0.30.1:
|
||||
resolution: {integrity: sha512-Fg0pWz1zXQdoxQZpdHRMGvUH5RqS6tPv+j9Eh7Q953UjMlrwZVo0YFLC8OTf/HKVf10E4i0u6aM8D69Q6cNkgQ==}
|
||||
dependencies:
|
||||
@@ -1064,25 +921,6 @@ packages:
|
||||
xstream: 11.14.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/tendermint-rpc@0.29.5:
|
||||
resolution: {integrity: sha512-ar80twieuAxsy0x2za/aO3kBr2DFPAXDmk2ikDbmkda+qqfXgl35l9CVAAjKRqd9d+cRvbQyb5M4wy6XQpEV6w==}
|
||||
dependencies:
|
||||
'@cosmjs/crypto': 0.29.5
|
||||
'@cosmjs/encoding': 0.29.5
|
||||
'@cosmjs/json-rpc': 0.29.5
|
||||
'@cosmjs/math': 0.29.5
|
||||
'@cosmjs/socket': 0.29.5
|
||||
'@cosmjs/stream': 0.29.5
|
||||
'@cosmjs/utils': 0.29.5
|
||||
axios: 0.21.4
|
||||
readonly-date: 1.0.0
|
||||
xstream: 11.14.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- debug
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@cosmjs/tendermint-rpc@0.30.1:
|
||||
resolution: {integrity: sha512-Z3nCwhXSbPZJ++v85zHObeUggrEHVfm1u18ZRwXxFE9ZMl5mXTybnwYhczuYOl7KRskgwlB+rID0WYACxj4wdQ==}
|
||||
dependencies:
|
||||
@@ -1125,10 +963,6 @@ packages:
|
||||
resolution: {integrity: sha512-VG7QPDiMUzVPxRdJahDV8PXxVdnuAHiIuG56hldV4yPnOz/si/DLNd7VAUUA5923b6jS1Hhev0Hr6AhEkcxBMg==}
|
||||
dev: false
|
||||
|
||||
/@cosmjs/utils@0.29.5:
|
||||
resolution: {integrity: sha512-m7h+RXDUxOzEOGt4P+3OVPX7PuakZT3GBmaM/Y2u+abN3xZkziykD/NvedYFvvCCdQo714XcGl33bwifS9FZPQ==}
|
||||
dev: false
|
||||
|
||||
/@cosmjs/utils@0.30.1:
|
||||
resolution: {integrity: sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g==}
|
||||
dev: false
|
||||
@@ -1137,22 +971,29 @@ packages:
|
||||
resolution: {integrity: sha512-nNcycZWUYLNJlrIXgpcgVRqdl6BXjF4YlXdxobQWpW9Tikk61bEGeAFhDYtC0PwHlokCNw0KxWiHGJL4nL7Q5A==}
|
||||
dev: false
|
||||
|
||||
/@cosmjs/utils@0.31.1:
|
||||
resolution: {integrity: sha512-n4Se1wu4GnKwztQHNFfJvUeWcpvx3o8cWhSbNs9JQShEuB3nv3R5lqFBtDCgHZF/emFQAP+ZjF8bTfCs9UBGhA==}
|
||||
dev: false
|
||||
|
||||
/@cush/relative@1.0.0:
|
||||
resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
|
||||
dev: true
|
||||
|
||||
/@dydxprotocol/v4-abacus@0.4.20:
|
||||
resolution: {integrity: sha512-ljYw9LLb3daf0vEhWQUylhxVVTsG4gY5iHKcyIF/fRS7TQvn+yBscxYlVbj3CMh6uh9b/oE+so5nZ7V2jiCWng==}
|
||||
/@dydxprotocol/v4-abacus@0.5.12:
|
||||
resolution: {integrity: sha512-OigoIjGtp0az1elkP84nc9qKYBVg5Fg4QEJFDn7J7oiUqVvwNggYNfnDsX77D8+K4DJ/rtbi2yZYsDE8OZMSoQ==}
|
||||
dev: false
|
||||
|
||||
/@dydxprotocol/v4-client-js@0.33.1:
|
||||
resolution: {integrity: sha512-yFDyiG5aVo4avF5u98yz6BEmWW66SscV2RgmdDwV+LfyKfcubVqKfmv3FtuqE0WKZuzzwiCuFat7YMSK125zyQ==}
|
||||
/@dydxprotocol/v4-client-js@0.36.1:
|
||||
resolution: {integrity: sha512-KJ3MtWI61wmm+xZtXQd7/hYKIoVFG32TRdyyVaXXO8vpW9Oqd0JD8QSM/wuegkciAh5YmP/BrDzYuu77zHO6yg==}
|
||||
dependencies:
|
||||
'@cosmjs/amino': 0.30.1
|
||||
'@cosmjs/encoding': 0.31.1
|
||||
'@cosmjs/math': 0.31.1
|
||||
'@cosmjs/proto-signing': 0.30.1
|
||||
'@cosmjs/stargate': 0.30.1
|
||||
'@cosmjs/tendermint-rpc': 0.30.1
|
||||
'@dydxprotocol/v4-proto': 0.1.2
|
||||
'@cosmjs/utils': 0.31.1
|
||||
'@dydxprotocol/v4-proto': 0.2.1
|
||||
'@osmonauts/lcd': 0.6.0
|
||||
'@scure/bip32': 1.3.1
|
||||
'@scure/bip39': 1.2.1
|
||||
@@ -1161,6 +1002,7 @@ packages:
|
||||
bignumber.js: 9.1.1
|
||||
ethereum-cryptography: 2.1.2
|
||||
long: 4.0.0
|
||||
protobufjs: 6.11.4
|
||||
ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -1168,25 +1010,14 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@dydxprotocol/v4-localization@0.1.5:
|
||||
resolution: {integrity: sha512-fiSHWrG8E2HuXkCzWsqyekntlI13hBRACrP0vaYudeSulw+ScGeAqZ5xp9/cANF6PP+H3z1yciNCZOH3OwSDwA==}
|
||||
/@dydxprotocol/v4-localization@0.1.12:
|
||||
resolution: {integrity: sha512-EiP/8+6Nk9QBa6YSWsyzsZaXoVbz5o/KgUlMp1Cew6VWkXL6DkQY0oMIEEy21pv0zuu/woxhlbyXygpUIcpdMg==}
|
||||
dev: false
|
||||
|
||||
/@dydxprotocol/v4-proto@0.1.2:
|
||||
resolution: {integrity: sha512-kcwdVdAexWB1nq/elFKCO4Su2ONQxBCJbN1TMeIAQiIAXxa7CnmYwdbLt4AIIxjgRhu4cHP8F6sGdwft6cjkCA==}
|
||||
/@dydxprotocol/v4-proto@0.2.1:
|
||||
resolution: {integrity: sha512-Q5b/g331DoyMjBpO2/jtrxUX3WF5UaIKZp/unK332xuefHNFnkMYtZ05p0V71iSdO35tBdz8yt0VYP2WtUsp+w==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.22.10
|
||||
'@bufbuild/buf': 1.19.0-1
|
||||
'@cosmjs/amino': 0.30.1
|
||||
'@cosmjs/proto-signing': 0.30.1
|
||||
'@cosmjs/stargate': 0.30.1
|
||||
'@cosmjs/tendermint-rpc': 0.30.1
|
||||
osmojs: 15.5.0
|
||||
protobufjs: 6.11.4
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- debug
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@emotion/is-prop-valid@1.2.1:
|
||||
@@ -2242,15 +2073,6 @@ packages:
|
||||
fastq: 1.15.0
|
||||
dev: true
|
||||
|
||||
/@osmonauts/lcd@0.10.0:
|
||||
resolution: {integrity: sha512-PzmXk9x9MHyLn2fUztpAqWqvDmMiEJaQv/JcAoAOE8VdHrD9Hf/KWnE1RZtamuS2ngQRqvQPD0xotCGXW7eTxA==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.22.10
|
||||
axios: 0.27.2
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
||||
/@osmonauts/lcd@0.6.0:
|
||||
resolution: {integrity: sha512-vz9VavXrEfxZoXbSAfNfk90MLpn34XtBYPV3L9YilE+s56AhqYxUh83nne9J5somnTRfGnyR3oeV8C+lHkqiuA==}
|
||||
dependencies:
|
||||
@@ -7783,13 +7605,6 @@ packages:
|
||||
path-type: 4.0.0
|
||||
dev: true
|
||||
|
||||
/cosmjs-types@0.5.2:
|
||||
resolution: {integrity: sha512-zxCtIJj8v3Di7s39uN4LNcN3HIE1z0B9Z0SPE8ZNQR0oSzsuSe1ACgxoFkvhkS7WBasCAFcglS11G2hyfd5tPg==}
|
||||
dependencies:
|
||||
long: 4.0.0
|
||||
protobufjs: 6.11.4
|
||||
dev: false
|
||||
|
||||
/cosmjs-types@0.7.2:
|
||||
resolution: {integrity: sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA==}
|
||||
dependencies:
|
||||
@@ -11637,23 +11452,6 @@ packages:
|
||||
type-check: 0.4.0
|
||||
dev: true
|
||||
|
||||
/osmojs@15.5.0:
|
||||
resolution: {integrity: sha512-7wy3QEYu+R+c8imfLEPS1PliYA8uw0qdFYjc2PToHteYG4hzYt4Noa7X0lM9O59s7nxo9ozT1N9z7uwB/1qHkA==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.22.10
|
||||
'@cosmjs/amino': 0.29.3
|
||||
'@cosmjs/proto-signing': 0.29.3
|
||||
'@cosmjs/stargate': 0.29.3
|
||||
'@cosmjs/tendermint-rpc': 0.29.5
|
||||
'@osmonauts/lcd': 0.10.0
|
||||
long: 5.2.3
|
||||
protobufjs: 6.11.4
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- debug
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/p-defer@3.0.0:
|
||||
resolution: {integrity: sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -14279,7 +14077,3 @@ packages:
|
||||
/zwitch@2.0.4:
|
||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||
dev: true
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"details": [
|
||||
{
|
||||
"appIDs": [
|
||||
"75C6UARB5H.exchangeV4.dydx.trading"
|
||||
"{PLACE_YOUR_APP_ID_HERE}"
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
{
|
||||
"deployments":{
|
||||
"MAINNET":null,
|
||||
"TESTNET":{
|
||||
"environments":[
|
||||
"dydxprotocol-testnet"
|
||||
],
|
||||
"default":"dydxprotocol-testnet"
|
||||
},
|
||||
"DEV":{
|
||||
"environments":[
|
||||
"dydxprotocol-dev",
|
||||
"dydxprotocol-dev-2",
|
||||
"dydxprotocol-dev-4",
|
||||
"dydxprotocol-dev-5",
|
||||
"dydxprotocol-staging",
|
||||
"dydxprotocol-testnet"
|
||||
],
|
||||
"default":"dydxprotocol-testnet"
|
||||
}
|
||||
},
|
||||
"environments":{
|
||||
"dydxprotocol-dev":{
|
||||
"name":"v4 Dev",
|
||||
"ethereumChainId":"5",
|
||||
"dydxChainId":"dydxprotocol-testnet",
|
||||
"isMainNet":false,
|
||||
"tokens":{
|
||||
"chain": {
|
||||
"name": "DYDX",
|
||||
"denom": "dv4tnt",
|
||||
"image": "/currencies/dydx.png"
|
||||
},
|
||||
"usdc": {
|
||||
"name": "USDC",
|
||||
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
|
||||
"image": "/currencies/usdc.png"
|
||||
}
|
||||
},
|
||||
"endpoints":{
|
||||
"indexers":[
|
||||
{
|
||||
"api":"http://indexer.v4dev.dydx.exchange",
|
||||
"socket":"wss://indexer.v4dev.dydx.exchange"
|
||||
}
|
||||
],
|
||||
"validators":[
|
||||
"http://validator.v4dev.dydx.exchange"
|
||||
],
|
||||
"0xsquid":"https://testnet.api.0xsquid.com",
|
||||
"faucet":"http://faucet.v4dev.dydx.exchange"
|
||||
},
|
||||
"links":{
|
||||
"tos":"https://dydx.exchange/v4-terms",
|
||||
"privacy":"https://dydx.exchange/privacy",
|
||||
"mintscan":"https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}"
|
||||
}
|
||||
},
|
||||
"dydxprotocol-dev-2":{
|
||||
"name":"v4 Dev 2",
|
||||
"ethereumChainId":"5",
|
||||
"dydxChainId":"dydxprotocol-testnet",
|
||||
"isMainNet":false,
|
||||
"tokens":{
|
||||
"chain": {
|
||||
"name": "DYDX",
|
||||
"denom": "dv4tnt",
|
||||
"image": "/currencies/dydx.png"
|
||||
},
|
||||
"usdc": {
|
||||
"name": "USDC",
|
||||
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
|
||||
"image": "/currencies/usdc.png"
|
||||
}
|
||||
},
|
||||
"endpoints":{
|
||||
"indexers":[
|
||||
{
|
||||
"api":"http://dev2-indexer-apne1-lb-public-2076363889.ap-northeast-1.elb.amazonaws.com",
|
||||
"socket":"ws://dev2-indexer-apne1-lb-public-2076363889.ap-northeast-1.elb.amazonaws.com"
|
||||
}
|
||||
],
|
||||
"validators":[
|
||||
"http://35.75.227.118"
|
||||
],
|
||||
"0xsquid":"https://testnet.api.0xsquid.com"
|
||||
},
|
||||
"links":{
|
||||
"tos":"https://dydx.exchange/v4-terms",
|
||||
"privacy":"https://dydx.exchange/privacy",
|
||||
"mintscan":"https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}"
|
||||
}
|
||||
},
|
||||
"dydxprotocol-dev-4":{
|
||||
"name":"v4 Dev 4",
|
||||
"ethereumChainId":"5",
|
||||
"dydxChainId":"dydxprotocol-testnet",
|
||||
"isMainNet":false,
|
||||
"tokens":{
|
||||
"chain": {
|
||||
"name": "DYDX",
|
||||
"denom": "dv4tnt",
|
||||
"image": "/currencies/dydx.png"
|
||||
},
|
||||
"usdc": {
|
||||
"name": "USDC",
|
||||
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
|
||||
"image": "/currencies/usdc.png"
|
||||
}
|
||||
},
|
||||
"endpoints":{
|
||||
"indexers":[
|
||||
{
|
||||
"api":"http://indexer.v4dev4.dydx.exchange",
|
||||
"socket":"ws://indexer.v4dev4.dydx.exchange"
|
||||
}
|
||||
],
|
||||
"validators":[
|
||||
"http://validator.v4dev4.dydx.exchange"
|
||||
],
|
||||
"0xsquid":"https://testnet.api.0xsquid.com"
|
||||
},
|
||||
"links":{
|
||||
"tos":"https://dydx.exchange/v4-terms",
|
||||
"privacy":"https://dydx.exchange/privacy",
|
||||
"mintscan":"https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}"
|
||||
}
|
||||
},
|
||||
"dydxprotocol-dev-5":{
|
||||
"name":"v4 Dev 5",
|
||||
"ethereumChainId":"5",
|
||||
"dydxChainId":"dydxprotocol-testnet",
|
||||
"isMainNet":false,
|
||||
"tokens":{
|
||||
"chain": {
|
||||
"name": "DYDX",
|
||||
"denom": "dv4tnt",
|
||||
"image": "/currencies/dydx.png"
|
||||
},
|
||||
"usdc": {
|
||||
"name": "USDC",
|
||||
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
|
||||
"image": "/currencies/usdc.png"
|
||||
}
|
||||
},
|
||||
"endpoints":{
|
||||
"indexers":[
|
||||
{
|
||||
"api":"http://dev5-indexer-apne1-lb-public-1721328151.ap-northeast-1.elb.amazonaws.com",
|
||||
"socket":"ws://dev5-indexer-apne1-lb-public-1721328151.ap-northeast-1.elb.amazonaws.com"
|
||||
}
|
||||
],
|
||||
"validators":[
|
||||
"http://18.223.78.50"
|
||||
],
|
||||
"0xsquid":"https://testnet.api.0xsquid.com"
|
||||
},
|
||||
"links":{
|
||||
"tos":"https://dydx.exchange/v4-terms",
|
||||
"privacy":"https://dydx.exchange/privacy",
|
||||
"mintscan":"https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}"
|
||||
}
|
||||
},
|
||||
"dydxprotocol-staging":{
|
||||
"name":"v4 Staging",
|
||||
"ethereumChainId":"5",
|
||||
"dydxChainId":"dydxprotocol-testnet",
|
||||
"isMainNet":false,
|
||||
"tokens":{
|
||||
"chain": {
|
||||
"name": "DYDX",
|
||||
"denom": "dv4tnt",
|
||||
"image": "/currencies/dydx.png"
|
||||
},
|
||||
"usdc": {
|
||||
"name": "USDC",
|
||||
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
|
||||
"image": "/currencies/usdc.png"
|
||||
}
|
||||
},
|
||||
"endpoints":{
|
||||
"indexers":[
|
||||
{
|
||||
"api":"https://indexer.v4staging.dydx.exchange",
|
||||
"socket":"wss://indexer.v4staging.dydx.exchange"
|
||||
}
|
||||
],
|
||||
"faucet":"https://faucet.v4staging.dydx.exchange",
|
||||
"validators":[
|
||||
"https://validator.v4staging.dydx.exchange"
|
||||
],
|
||||
"0xsquid":"https://squid-api-git-main-cosmos-testnet-0xsquid.vercel.app"
|
||||
},
|
||||
"links":{
|
||||
"tos":"https://dydx.exchange/v4-terms",
|
||||
"privacy":"https://dydx.exchange/privacy",
|
||||
"mintscan":"https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||
"documentation":"https://v4-teacher.vercel.app/",
|
||||
"community":"https://discord.com/invite/dydx",
|
||||
"feedback":"https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform"
|
||||
}
|
||||
},
|
||||
"dydxprotocol-testnet":{
|
||||
"name":"v4 Public Testnet",
|
||||
"ethereumChainId":"5",
|
||||
"dydxChainId":"dydx-testnet-3",
|
||||
"isMainNet":false,
|
||||
"tokens":{
|
||||
"chain": {
|
||||
"name": "DYDX",
|
||||
"denom": "dv4tnt",
|
||||
"image": "/currencies/dydx.png"
|
||||
},
|
||||
"usdc": {
|
||||
"name": "USDC",
|
||||
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
|
||||
"image": "/currencies/usdc.png"
|
||||
}
|
||||
},
|
||||
"endpoints":{
|
||||
"indexers":[
|
||||
{
|
||||
"api":"https://dydx-testnet.imperator.co",
|
||||
"socket":"wss://dydx-testnet.imperator.co"
|
||||
}
|
||||
],
|
||||
"validators":[
|
||||
"https://dydx-testnet.nodefleet.org",
|
||||
"https://test-dydx.kingnodes.com/"
|
||||
],
|
||||
"0xsquid":"https://squid-api-git-main-cosmos-testnet-0xsquid.vercel.app",
|
||||
"faucet":"https://faucet.v4testnet.dydx.exchange"
|
||||
},
|
||||
"links":{
|
||||
"tos":"https://dydx.exchange/v4-terms",
|
||||
"privacy":"https://dydx.exchange/privacy",
|
||||
"mintscan":"https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||
"documentation":"https://v4-teacher.vercel.app/",
|
||||
"community":"https://discord.com/invite/dydx",
|
||||
"feedback":"https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,454 @@
|
||||
{
|
||||
"1INCH-USD":{
|
||||
"name":"1inch",
|
||||
"tags":[
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://1inch.io/",
|
||||
"whitepaperLink":"https://github.com/1inch",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/1inch/"
|
||||
},
|
||||
"AAVE-USD":{
|
||||
"name":"Aave",
|
||||
"tags":[
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://aave.com/",
|
||||
"whitepaperLink":"https://github.com/aave/protocol-v2/blob/master/aave-v2-whitepaper.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/aave/"
|
||||
},
|
||||
"ADA-USD":{
|
||||
"name":"Cardano",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://cardano.org/",
|
||||
"whitepaperLink":"https://why.cardano.org/en/introduction/motivation/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/cardano/"
|
||||
},
|
||||
"ALGO-USD":{
|
||||
"name":"Algorand",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://algorand.com/",
|
||||
"whitepaperLink":"https://algorand.com/technology/white-papers",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/algorand/"
|
||||
},
|
||||
"APE-USD":{
|
||||
"name":"ApeCoin",
|
||||
"tags":[
|
||||
|
||||
],
|
||||
"websiteLink":"https://apecoin.com/",
|
||||
"whitepaperLink":"https://apecoin.com/about",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/apecoin-ape/"
|
||||
},
|
||||
"APT-USD":{
|
||||
"name":"Aptos",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://aptoslabs.com/",
|
||||
"whitepaperLink":"https://aptos.dev/aptos-white-paper/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/aptos/"
|
||||
},
|
||||
"ARB-USD":{
|
||||
"name":"Arbitrum",
|
||||
"tags":[
|
||||
|
||||
],
|
||||
"websiteLink":"https://arbitrum.io/",
|
||||
"whitepaperLink":"https://github.com/OffchainLabs/nitro",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/arbitrum/"
|
||||
},
|
||||
"ATOM-USD":{
|
||||
"name":"Cosmos",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://cosmos.network/",
|
||||
"whitepaperLink":"https://v1.cosmos.network/resources/whitepaper",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/cosmos/"
|
||||
},
|
||||
"AVAX-USD":{
|
||||
"name":"Avalanche",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://www.avalabs.org/",
|
||||
"whitepaperLink":"https://assets.website-files.com/5d80307810123f5ffbb34d6e/6008d7bbf8b10d1eb01e7e16_Avalanche%20Platform%20Whitepaper.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/avalanche/"
|
||||
},
|
||||
"BCH-USD":{
|
||||
"name":"Bitcoin Cash",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://bitcoincash.org/",
|
||||
"whitepaperLink":"https://bitcoincash.org/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/bitcoin-cash/"
|
||||
},
|
||||
"BLUR-USD":{
|
||||
"name":"Blur",
|
||||
"tags":[
|
||||
|
||||
],
|
||||
"websiteLink":"https://blur.io/",
|
||||
"whitepaperLink":"https://docs.blur.foundation/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/blur-token/"
|
||||
},
|
||||
"CELO-USD":{
|
||||
"name":"Celo",
|
||||
"tags":[
|
||||
|
||||
],
|
||||
"websiteLink":"https://celo.org",
|
||||
"whitepaperLink":"https://docs.celo.org",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/celo/"
|
||||
},
|
||||
"BTC-USD":{
|
||||
"name":"Bitcoin",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://bitcoin.org/",
|
||||
"whitepaperLink":"https://bitcoin.org/bitcoin.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/bitcoin/"
|
||||
},
|
||||
"COMP-USD":{
|
||||
"name":"Compound",
|
||||
"tags":[
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://compound.finance/",
|
||||
"whitepaperLink":"https://compound.finance/documents/Compound.Whitepaper.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/compound/"
|
||||
},
|
||||
"CRV-USD":{
|
||||
"name":"Curve",
|
||||
"tags":[
|
||||
"Governance"
|
||||
],
|
||||
"websiteLink":"https://curve.fi/",
|
||||
"whitepaperLink":"https://curve.fi/whitepaper",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/curve-dao-token/"
|
||||
},
|
||||
"DOGE-USD":{
|
||||
"name":"Dogecoin",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://dogecoin.com/",
|
||||
"whitepaperLink":"https://github.com/dogecoin/dogecoin",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/dogecoin/"
|
||||
},
|
||||
"DOT-USD":{
|
||||
"name":"Polkadot",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://polkadot.network/",
|
||||
"whitepaperLink":"https://polkadot.network/PolkaDotPaper.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/polkadot-new/"
|
||||
},
|
||||
"ENJ-USD":{
|
||||
"name":"Enjin",
|
||||
"tags":[
|
||||
|
||||
],
|
||||
"websiteLink":"https://enjin.io/",
|
||||
"whitepaperLink":"https://cdn.enjin.io/downloads/whitepapers/enjin-coin/en.pdf/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/enjin-coin/"
|
||||
},
|
||||
"EOS-USD":{
|
||||
"name":"EOS",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://eos.io/",
|
||||
"whitepaperLink":"https://github.com/EOSIO/Documentation/blob/master/TechnicalWhitePaper.md",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/eos/"
|
||||
},
|
||||
"ETC-USD":{
|
||||
"name":"Ethereum Classic",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://ethereumclassic.org/",
|
||||
"whitepaperLink":"https://ethereumclassic.org/why-classic",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/ethereum-classic/"
|
||||
},
|
||||
"ETH-USD":{
|
||||
"name":"Ethereum",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://ethereum.org/",
|
||||
"whitepaperLink":"https://ethereum.org/whitepaper/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/ethereum/",
|
||||
"displayStepSize":"0.001",
|
||||
"displayTickSize":"0.1"
|
||||
},
|
||||
"FIL-USD":{
|
||||
"name":"Filecoin",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://filecoin.io/",
|
||||
"whitepaperLink":"https://filecoin.io/filecoin.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/filecoin/"
|
||||
},
|
||||
"HNT-USD":{
|
||||
"name":"Helium",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://www.helium.com",
|
||||
"whitepaperLink":"http://whitepaper.helium.com",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/helium/"
|
||||
},
|
||||
"ICP-USD":{
|
||||
"name":"Internet Computer",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://dfinity.org",
|
||||
"whitepaperLink":"https://dfinity.org/whitepaper.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/internet-computer/"
|
||||
},
|
||||
"LDO-USD":{
|
||||
"name":"Lido DAO",
|
||||
"tags":[
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://lido.fi/",
|
||||
"whitepaperLink":"https://lido.fi/static/Lido:Ethereum-Liquid-Staking.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/lido-dao/"
|
||||
},
|
||||
"LINK-USD":{
|
||||
"name":"Chainlink",
|
||||
"tags":[
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://chain.link/",
|
||||
"whitepaperLink":"https://link.smartcontract.com/whitepaper",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/chainlink/"
|
||||
},
|
||||
"LTC-USD":{
|
||||
"name":"Litecoin",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://litecoin.org/",
|
||||
"whitepaperLink":"https://litecoin.info/index.php/Main_Page",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/litecoin/"
|
||||
},
|
||||
"MATIC-USD":{
|
||||
"name":"Polygon",
|
||||
"tags":[
|
||||
"Layer 2"
|
||||
],
|
||||
"websiteLink":"https://polygon.technology/",
|
||||
"whitepaperLink":"https://polygon.technology/lightpaper-polygon.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/polygon/"
|
||||
},
|
||||
"MKR-USD":{
|
||||
"name":"Maker",
|
||||
"tags":[
|
||||
"Governance"
|
||||
],
|
||||
"websiteLink":"https://makerdao.com",
|
||||
"whitepaperLink":"https://makerdao.com/whitepaper",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/maker/"
|
||||
},
|
||||
"NEAR-USD":{
|
||||
"name":"NEAR Protocol",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://near.org",
|
||||
"whitepaperLink":"https://near.org/papers/the-official-near-white-paper/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/near-protocol/"
|
||||
},
|
||||
"OP-USD":{
|
||||
"name":"Optimism",
|
||||
"tags":[
|
||||
|
||||
],
|
||||
"websiteLink":"https://www.optimism.io/",
|
||||
"whitepaperLink":"https://github.com/ethereum-optimism",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/optimism-ethereum/"
|
||||
},
|
||||
"PEPE-USD":{
|
||||
"name":"Pepe",
|
||||
"tags":[
|
||||
|
||||
],
|
||||
"websiteLink":"https://www.pepe.vip/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/pepe/"
|
||||
},
|
||||
"RUNE-USD":{
|
||||
"name":"THORChain",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://thorchain.org",
|
||||
"whitepaperLink":"https://whitepaper.io/document/709/thorchain-whitepaper",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/thorchain/"
|
||||
},
|
||||
"SEI-USD":{
|
||||
"name":"Sei",
|
||||
"tags":[
|
||||
"Layer 1",
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://www.sei.io/",
|
||||
"whitepaperLink":"https://github.com/sei-protocol/sei-chain/blob/3c9576fee3494ce039df684624f918dd8066ba3f/whitepaper/Sei_Whitepaper.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/sei/"
|
||||
},
|
||||
"SHIB-USD":{
|
||||
"name":"Shiba Inu",
|
||||
"tags":[
|
||||
|
||||
],
|
||||
"websiteLink":"https://shibatoken.com/",
|
||||
"whitepaperLink":"https://docs.shibatoken.com/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/shiba-inu/"
|
||||
},
|
||||
"SNX-USD":{
|
||||
"name":"Synthetix",
|
||||
"tags":[
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://synthetix.io/",
|
||||
"whitepaperLink":"https://docs.synthetix.io/litepaper",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/synthetix-network-token/"
|
||||
},
|
||||
"SOL-USD":{
|
||||
"name":"Solana",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://solana.com/",
|
||||
"whitepaperLink":"https://solana.com/solana-whitepaper.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/solana/"
|
||||
},
|
||||
"SUI-USD":{
|
||||
"name":"Sui",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://sui.io/",
|
||||
"whitepaperLink":"https://github.com/MystenLabs",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/sui/"
|
||||
},
|
||||
"SUSHI-USD":{
|
||||
"name":"Sushi",
|
||||
"tags":[
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://sushi.com/",
|
||||
"whitepaperLink":"https://docs.sushi.com/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/sushiswap/"
|
||||
},
|
||||
"TRX-USD":{
|
||||
"name":"TRON",
|
||||
"tags":[
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://tron.network/",
|
||||
"whitepaperLink":"https://tron.network/static/doc/white_paper_v_2_0.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/tron/"
|
||||
},
|
||||
"UMA-USD":{
|
||||
"name":"UMA",
|
||||
"tags":[
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://umaproject.org/",
|
||||
"whitepaperLink":"https://github.com/UMAprotocol/whitepaper",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/uma/"
|
||||
},
|
||||
"UNI-USD":{
|
||||
"name":"Uniswap",
|
||||
"tags":[
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://uniswap.org/",
|
||||
"whitepaperLink":"https://uniswap.org/whitepaper-v3.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/uniswap/"
|
||||
},
|
||||
"WLD-USD":{
|
||||
"name":"Worldcoin",
|
||||
"tags":[
|
||||
|
||||
],
|
||||
"websiteLink":"https://worldcoin.org/",
|
||||
"whitepaperLink":"https://whitepaper.worldcoin.org/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/worldcoin-org/"
|
||||
},
|
||||
"XLM-USD":{
|
||||
"name":"Stellar",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://www.stellar.org/",
|
||||
"whitepaperLink":"https://www.stellar.org/papers/stellar-consensus-protocol",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/stellar/"
|
||||
},
|
||||
"XMR-USD":{
|
||||
"name":"Monero",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://www.getmonero.org/",
|
||||
"whitepaperLink":"https://www.getmonero.org/resources/research-lab/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/monero/"
|
||||
},
|
||||
"XRP-USD":{
|
||||
"name":"Ripple",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://ripple.com/currency/",
|
||||
"whitepaperLink":"https://github.com/ripple",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/xrp/"
|
||||
},
|
||||
"XTZ-USD":{
|
||||
"name":"Tezos",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://tezos.com",
|
||||
"whitepaperLink":"https://tezos.com/whitepaper.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/tezos/"
|
||||
},
|
||||
"YFI-USD":{
|
||||
"name":"Yearn",
|
||||
"tags":[
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://yearn.finance/",
|
||||
"whitepaperLink":"https://docs.yearn.finance/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/yearn-finance/"
|
||||
},
|
||||
"ZEC-USD":{
|
||||
"name":"Zcash",
|
||||
"tags":[
|
||||
"Layer 1"
|
||||
],
|
||||
"websiteLink":"https://z.cash/",
|
||||
"whitepaperLink":"https://z.cash/technology/",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/zcash/"
|
||||
},
|
||||
"ZRX-USD":{
|
||||
"name":"0x",
|
||||
"tags":[
|
||||
"Defi"
|
||||
],
|
||||
"websiteLink":"https://0x.org/",
|
||||
"whitepaperLink":"https://0x.org/pdfs/0x_white_paper.pdf",
|
||||
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/0x/"
|
||||
}
|
||||
}
|
||||
+12
-9
@@ -40,6 +40,10 @@ export type AbacusFileSystemProtocol = Omit<
|
||||
Abacus.exchange.dydx.abacus.protocols.FileSystemProtocol,
|
||||
'__doNotUseOrImplementIt'
|
||||
>;
|
||||
export type AbacusTrackingProtocol = Omit<
|
||||
Abacus.exchange.dydx.abacus.protocols.TrackingProtocol,
|
||||
'__doNotUseOrImplementIt'
|
||||
>;
|
||||
|
||||
export type FileLocation = Abacus.exchange.dydx.abacus.protocols.FileLocation;
|
||||
export type ThreadingType = Abacus.exchange.dydx.abacus.protocols.ThreadingType;
|
||||
@@ -65,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;
|
||||
@@ -118,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;
|
||||
@@ -134,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];
|
||||
|
||||
@@ -174,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;
|
||||
|
||||
@@ -71,6 +71,7 @@ export enum AnalyticsEvent {
|
||||
|
||||
// Transfers
|
||||
TransferFaucet = 'TransferFaucet',
|
||||
TransferFaucetConfirmed = 'TransferFaucetConfirmed',
|
||||
TransferDeposit = 'TransferDeposit',
|
||||
TransferWithdraw = 'TransferWithdraw',
|
||||
|
||||
@@ -78,6 +79,7 @@ export enum AnalyticsEvent {
|
||||
TradeOrderTypeSelected = 'TradeOrderTypeSelected',
|
||||
TradePlaceOrder = 'TradePlaceOrder',
|
||||
TradePlaceOrderConfirmed = 'TradePlaceOrderConfirmed',
|
||||
TradeCancelOrder = 'TradeCancelOrder',
|
||||
TradeCancelOrderConfirmed = 'TradeCancelOrderConfirmed',
|
||||
}
|
||||
|
||||
@@ -133,6 +135,13 @@ export type AnalyticsEventData<T extends AnalyticsEvent> =
|
||||
: // Transfers
|
||||
T extends AnalyticsEvent.TransferFaucet
|
||||
? {}
|
||||
: T extends AnalyticsEvent.TransferFaucetConfirmed
|
||||
? {
|
||||
/** roundtrip time between user placing an order and confirmation from indexer (client → validator → indexer → client) */
|
||||
roundtripMs: number;
|
||||
/** URL/IP of node the order was sent to */
|
||||
validatorUrl: string;
|
||||
}
|
||||
: T extends AnalyticsEvent.TransferDeposit
|
||||
? {}
|
||||
: T extends AnalyticsEvent.TransferWithdraw
|
||||
@@ -151,13 +160,15 @@ export type AnalyticsEventData<T extends AnalyticsEvent> =
|
||||
/** roundtrip time between user placing an order and confirmation from indexer (client → validator → indexer → client) */
|
||||
roundtripMs: number;
|
||||
/** URL/IP of node the order was sent to */
|
||||
validator: string;
|
||||
validatorUrl: string;
|
||||
}
|
||||
: T extends AnalyticsEvent.TradeCancelOrder
|
||||
? {}
|
||||
: T extends AnalyticsEvent.TradeCancelOrderConfirmed
|
||||
? {
|
||||
/** roundtrip time between user canceling an order and confirmation from indexer (client → validator → indexer → client) */
|
||||
roundtripMs: number;
|
||||
/** URL/IP of node the order was sent to */
|
||||
validator: string;
|
||||
validatorUrl: string;
|
||||
}
|
||||
: never;
|
||||
|
||||
@@ -88,19 +88,3 @@ export type TooltipStrings = {
|
||||
learnMoreLink?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export const ORDER_ERROR_CODE_MAP: { [key: number]: string } = {
|
||||
2000: STRING_KEYS['2000_FILL_OR_KILL_ORDER_COULD_NOT_BE_FULLY_FILLED'],
|
||||
2001: STRING_KEYS['2001_REDUCE_ONLY_WOULD_INCREASE_POSITION_SIZE'],
|
||||
2002: STRING_KEYS['2002_REDUCE_ONLY_WOULD_CHANGE_POSITION_SIDE'],
|
||||
2003: STRING_KEYS['2003_POST_ONLY_WOULD_CROSS_MAKER_ORDER'],
|
||||
3000: STRING_KEYS['3000_INVALID_ORDER_FLAGS'],
|
||||
3001: STRING_KEYS['3001_INVALID_STATEFUL_ORDER_GOOD_TIL_BLOCK_TIME'],
|
||||
3002: STRING_KEYS['3002_STATEFUL_ORDERS_CANNOT_REQUIRE_IMMEDIATE_EXECUTION'],
|
||||
3003: STRING_KEYS['3003_TIME_EXCEEDS_GOOD_TIL_BLOCK_TIME'],
|
||||
3004: STRING_KEYS['3004_GOOD_TIL_BLOCK_TIME_EXCEEDS_STATEFUL_ORDER_TIME_WINDOW'],
|
||||
3005: STRING_KEYS['3005_STATEFUL_ORDER_ALREADY_EXISTS'],
|
||||
3006: STRING_KEYS['3006_STATEFUL_ORDER_DOES_NOT_EXIST'],
|
||||
3007: STRING_KEYS['3007_STATEFUL_ORDER_COLLATERALIZATION_CHECK_FAILED'],
|
||||
3008: STRING_KEYS['3008_STATEFUL_ORDER_PREVIOUSLY_CANCELLED'],
|
||||
};
|
||||
|
||||
@@ -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 }),
|
||||
|
||||
@@ -27,7 +27,7 @@ export enum PositionSide {
|
||||
Short = 'SHORT',
|
||||
}
|
||||
|
||||
export const UNCOMMITTED_ORDER_TIMEOUT = 10_000;
|
||||
export const UNCOMMITTED_ORDER_TIMEOUT_MS = 10_000;
|
||||
|
||||
export const ORDER_SIDE_STRINGS = {
|
||||
[OrderSide.BUY]: STRING_KEYS.BUY,
|
||||
|
||||
@@ -339,12 +339,12 @@ export type EvmAddress = `0x${string}`;
|
||||
export type DydxAddress = `dydx${string}`;
|
||||
|
||||
export const DYDX_CHAIN_INFO: Parameters<typeof suggestChain>[0] = {
|
||||
rpc: '13.59.4.93:26657',
|
||||
rest: '13.59.4.93:1317',
|
||||
chainId: 'dydx-testnet-2',
|
||||
rpc: 'https://dydx-testnet-archive.allthatnode.com:26657',
|
||||
rest: 'https://dydx-testnet-archive.allthatnode.com:1317',
|
||||
chainId: 'dydx-testnet-3',
|
||||
chainName: 'dYdX Public Testnet',
|
||||
chainSymbolImageUrl:
|
||||
'https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/dydx-testnet-2/chain.png',
|
||||
'https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/dydx-testnet-3/chain.png',
|
||||
bech32Config: {
|
||||
bech32PrefixAccPub: 'dydxpub',
|
||||
bech32PrefixValPub: 'dydxvaloperpub',
|
||||
@@ -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',
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -8,10 +8,7 @@ import { OnboardingGuard, OnboardingState, type EvmDerivedAddresses } from '@/co
|
||||
import { LocalStorageKey, LOCAL_STORAGE_VERSIONS } from '@/constants/localStorage';
|
||||
import { DydxAddress, EvmAddress, PrivateInformation } from '@/constants/wallets';
|
||||
|
||||
import {
|
||||
setOnboardingState,
|
||||
setOnboardingGuard,
|
||||
} from '@/state/account';
|
||||
import { setOnboardingState, setOnboardingGuard } from '@/state/account';
|
||||
|
||||
import abacusStateManager from '@/lib/abacus';
|
||||
import { log } from '@/lib/telemetry';
|
||||
@@ -222,9 +219,9 @@ const useAccountsContext = () => {
|
||||
// abacus
|
||||
// TODO: useAbacus({ dydxAddress })
|
||||
useEffect(() => {
|
||||
if (dydxAddress) abacusStateManager.setAccount(dydxAddress);
|
||||
if (dydxAddress) abacusStateManager.setAccount(localDydxWallet);
|
||||
else abacusStateManager.attemptDisconnectAccount();
|
||||
}, [dydxAddress]);
|
||||
}, [localDydxWallet]);
|
||||
|
||||
// clear subaccounts when no dydxAddress is set
|
||||
useEffect(() => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { LocalStorageKey } from '@/constants/localStorage';
|
||||
import { type TransferNotifcation } from '@/constants/notifications';
|
||||
|
||||
import { useAccounts } from '@/hooks/useAccounts';
|
||||
import { useSquid } from '@/hooks/useSquid';
|
||||
import { SQUID_ERROR_TYPES, useSquid } from '@/hooks/useSquid';
|
||||
import { useLocalStorage } from './useLocalStorage';
|
||||
|
||||
const LocalNotificationsContext = createContext<
|
||||
@@ -66,11 +66,14 @@ const useLocalNotificationsContext = () => {
|
||||
} of transferNotifications) {
|
||||
try {
|
||||
if (currentStatus && currentStatus?.squidTransactionStatus !== 'ongoing') continue;
|
||||
|
||||
|
||||
const status = await squid?.getStatus({ transactionId: txHash, toChainId, fromChainId });
|
||||
if (status) statuses[txHash] = status;
|
||||
} catch (error) {
|
||||
console.error(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) {
|
||||
statuses[txHash] = error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return statuses;
|
||||
|
||||
@@ -29,7 +29,7 @@ export const useMarketsData = (
|
||||
|
||||
const markets = useMemo(() => {
|
||||
return Object.values(allPerpetualMarkets)
|
||||
.filter(({ assetId }) => allAssets[assetId]) // Filter out markets with no asset information
|
||||
.filter((market) => allAssets[market?.assetId]) // Filter out markets with no asset information
|
||||
.map((marketData) => ({
|
||||
asset: allAssets[marketData.assetId],
|
||||
tickSizeDecimals: marketData.configs?.tickSizeDecimals,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||
import { useSelector, shallowEqual, useDispatch } from 'react-redux';
|
||||
import { groupBy } from 'lodash';
|
||||
|
||||
import { AlertType } from '@/constants/alerts';
|
||||
import { AbacusOrderStatus, ORDER_SIDES, ORDER_STATUS_STRINGS } from '@/constants/abacus';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
@@ -10,6 +12,7 @@ import { ORDER_SIDE_STRINGS, TRADE_TYPE_STRINGS, TradeTypes } from '@/constants/
|
||||
|
||||
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
|
||||
|
||||
import { AlertMessage } from '@/components/AlertMessage';
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
import { Output, OutputType } from '@/components/Output';
|
||||
import { TransferStatusToast } from '@/views/TransferStatus';
|
||||
@@ -119,19 +122,36 @@ export const notificationTypes = [
|
||||
const { toChainId, status, txHash, toAmount } = transfer;
|
||||
const finished = Boolean(status) && status?.squidTransactionStatus !== 'ongoing';
|
||||
const type = toChainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdraw';
|
||||
// @ts-ignore status.errors is not in the type definition but can be returned
|
||||
const error = status?.errors?.length ? status?.errors[0] : status?.error;
|
||||
|
||||
// TODO: confirm with design what the description should be
|
||||
const description = (
|
||||
<div>
|
||||
<Styled.TransferText>
|
||||
{type === 'deposit' ? 'Deposit of ' : 'Withdraw of '}
|
||||
<Output type={OutputType.Fiat} value={toAmount} />
|
||||
</Styled.TransferText>
|
||||
|
||||
{error && (
|
||||
<Styled.ErrorMessage type={AlertType.Error}>
|
||||
{stringGetter({
|
||||
key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
|
||||
params: {
|
||||
ERROR_MESSAGE: error.message || stringGetter({ key: STRING_KEYS.UNKNOWN_ERROR }),
|
||||
},
|
||||
})}
|
||||
</Styled.ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
trigger(
|
||||
txHash,
|
||||
{
|
||||
icon: <Icon iconName={finished ? IconName.Transfer : IconName.Clock} />,
|
||||
title: stringGetter({ key: getTitleStringKey(type, finished) }),
|
||||
// TODO: confirm with design what the description should be
|
||||
description: (
|
||||
<>
|
||||
<span>{type === 'deposit' ? 'Deposit of ' : 'Withdraw of'}</span>
|
||||
<Output type={OutputType.Fiat} value={toAmount} />
|
||||
</>
|
||||
),
|
||||
description: description,
|
||||
customContent: (
|
||||
<TransferStatusToast
|
||||
toAmount={transfer.toAmount}
|
||||
@@ -139,7 +159,12 @@ export const notificationTypes = [
|
||||
status={transfer.status}
|
||||
/>
|
||||
),
|
||||
customMenuContent: !finished && <TransferStatusSteps status={transfer.status} />,
|
||||
customMenuContent: !finished && (
|
||||
<div>
|
||||
{description}
|
||||
<TransferStatusSteps status={transfer.status} />
|
||||
</div>
|
||||
),
|
||||
toastSensitivity: 'foreground',
|
||||
},
|
||||
[]
|
||||
@@ -149,3 +174,15 @@ export const notificationTypes = [
|
||||
},
|
||||
},
|
||||
] satisfies NotificationTypeConfig[];
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.TransferText = styled.span`
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5ch;
|
||||
`
|
||||
|
||||
Styled.ErrorMessage = styled.div`
|
||||
max-width: 13rem;
|
||||
`;
|
||||
@@ -0,0 +1,26 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { getLatestOrderClientId } from '@/state/accountSelectors';
|
||||
|
||||
/**
|
||||
* @description This hook will fire a callback when the latest order has been updated to a non-pending state from the Indexer.
|
||||
* @param { callback: () => void }
|
||||
*/
|
||||
export const useOnLastOrderIndexed = ({ callback }: { callback: () => void }) => {
|
||||
const [unIndexedClientId, setUnIndexedClientId] = useState<number | undefined>();
|
||||
const latestOrderClientId = useSelector(getLatestOrderClientId);
|
||||
|
||||
useEffect(() => {
|
||||
if (unIndexedClientId) {
|
||||
if (unIndexedClientId === latestOrderClientId) {
|
||||
callback();
|
||||
setUnIndexedClientId(undefined);
|
||||
}
|
||||
}
|
||||
}, [callback, latestOrderClientId, unIndexedClientId]);
|
||||
|
||||
return {
|
||||
setUnIndexedClientId,
|
||||
};
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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,15 +1,13 @@
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { LocalStorageKey } from '@/constants/localStorage';
|
||||
import { CLIENT_NETWORK_CONFIGS, DEFAULT_APP_ENVIRONMENT, DydxNetwork } from '@/constants/networks';
|
||||
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork } from '@/constants/networks';
|
||||
|
||||
import { useAccounts, useLocalStorage } from '@/hooks';
|
||||
|
||||
import { setSelectedNetwork } from '@/state/app';
|
||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||
import { openDialog } from '@/state/dialogs';
|
||||
|
||||
export const useSelectedNetwork = (): {
|
||||
switchNetwork: (network: DydxNetwork) => void;
|
||||
@@ -24,17 +22,6 @@ export const useSelectedNetwork = (): {
|
||||
defaultValue: DEFAULT_APP_ENVIRONMENT,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
import.meta.env.MODE === 'production' &&
|
||||
CLIENT_NETWORK_CONFIGS[selectedNetwork].dydxChainId === 'dydx-testnet-3'
|
||||
) {
|
||||
dispatch(
|
||||
openDialog({ type: DialogTypes.ExchangeOffline, dialogProps: { preventClose: true } })
|
||||
);
|
||||
}
|
||||
}, [selectedNetwork]);
|
||||
|
||||
const switchNetwork = useCallback(
|
||||
(network: DydxNetwork) => {
|
||||
disconnect();
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client-js';
|
||||
import { Squid } from '@0xsquid/sdk';
|
||||
|
||||
import { CLIENT_NETWORK_CONFIGS, DydxV4Network, isDydxV4Network } from '@/constants/networks';
|
||||
import { CLIENT_NETWORK_CONFIGS, isDydxV4Network } from '@/constants/networks';
|
||||
|
||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||
|
||||
export const NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
||||
|
||||
export enum SQUID_ERROR_TYPES {
|
||||
NotFoundError = 'NotFoundError',
|
||||
}
|
||||
|
||||
const useSquidContext = () => {
|
||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||
const [_, setInitialized] = useState(false);
|
||||
|
||||
+55
-330
@@ -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';
|
||||
@@ -7,47 +7,35 @@ import type { EncodeObject, Coin } from '@cosmjs/proto-signing';
|
||||
import { Method } from '@cosmjs/tendermint-rpc';
|
||||
|
||||
import {
|
||||
LocalWallet,
|
||||
OrderExecution,
|
||||
OrderFlags,
|
||||
OrderSide,
|
||||
OrderTimeInForce,
|
||||
OrderType,
|
||||
type LocalWallet,
|
||||
SubaccountClient,
|
||||
DYDX_DENOM,
|
||||
USDC_DENOM,
|
||||
GAS_PRICE_DYDX_DENOM,
|
||||
} from '@dydxprotocol/v4-client-js';
|
||||
|
||||
import type {
|
||||
HumanReadableCancelOrderPayload,
|
||||
AccountBalance,
|
||||
HumanReadablePlaceOrderPayload,
|
||||
ParsingError,
|
||||
SubAccountHistoricalPNLs,
|
||||
} from '@/constants/abacus';
|
||||
|
||||
import { AMOUNT_RESERVED_FOR_GAS_USDC } from '@/constants/account';
|
||||
import { AnalyticsEvent } from '@/constants/analytics';
|
||||
import { ORDER_ERROR_CODE_MAP } from '@/constants/localization';
|
||||
import { QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
||||
import { UNCOMMITTED_ORDER_TIMEOUT } from '@/constants/trade';
|
||||
import { DydxAddress } from '@/constants/wallets';
|
||||
|
||||
import {
|
||||
addUncommittedOrderClientId,
|
||||
removeUncommittedOrderClientId,
|
||||
setSubaccount,
|
||||
setHistoricalPnl,
|
||||
} from '@/state/account';
|
||||
import { setSubaccount, setHistoricalPnl, removeUncommittedOrderClientId } from '@/state/account';
|
||||
import { getBalances } from '@/state/accountSelectors';
|
||||
|
||||
import abacusStateManager from '@/lib/abacus';
|
||||
import { track } from '@/lib/analytics';
|
||||
import { StatefulOrderError } from '@/lib/errors';
|
||||
import { MustBigNumber } from '@/lib/numbers';
|
||||
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);
|
||||
@@ -83,12 +71,8 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
||||
const {
|
||||
depositToSubaccount,
|
||||
withdrawFromSubaccount,
|
||||
simulateWithdrawFromSubaccount,
|
||||
transferFromSubaccountToAddress,
|
||||
transferNativeToken,
|
||||
simulateTransferNativeToken,
|
||||
placeOrderForSubaccount,
|
||||
cancelOrderForSubaccount,
|
||||
sendSquidWithdrawFromSubaccount,
|
||||
} = useMemo(
|
||||
() => ({
|
||||
@@ -110,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,
|
||||
@@ -185,125 +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
|
||||
),
|
||||
|
||||
placeOrderForSubaccount: async ({
|
||||
subaccount,
|
||||
marketId,
|
||||
type,
|
||||
side,
|
||||
price,
|
||||
triggerPrice,
|
||||
size,
|
||||
clientId,
|
||||
timeInForce,
|
||||
goodTilTimeInSeconds,
|
||||
execution,
|
||||
postOnly,
|
||||
reduceOnly,
|
||||
}: {
|
||||
subaccount: SubaccountClient;
|
||||
marketId: string;
|
||||
type: OrderType;
|
||||
side: OrderSide;
|
||||
price: number;
|
||||
triggerPrice: Nullable<number>;
|
||||
size: number;
|
||||
clientId: number;
|
||||
timeInForce: OrderTimeInForce;
|
||||
goodTilTimeInSeconds: number;
|
||||
execution: OrderExecution;
|
||||
postOnly: boolean;
|
||||
reduceOnly: boolean;
|
||||
}) => {
|
||||
const startTimestamp = performance.now();
|
||||
|
||||
const result = await compositeClient?.placeOrder(
|
||||
subaccount,
|
||||
marketId,
|
||||
type,
|
||||
side,
|
||||
price,
|
||||
size,
|
||||
clientId,
|
||||
timeInForce,
|
||||
goodTilTimeInSeconds,
|
||||
execution,
|
||||
postOnly,
|
||||
reduceOnly,
|
||||
triggerPrice ?? undefined
|
||||
);
|
||||
|
||||
const endTimestamp = performance.now();
|
||||
|
||||
track(AnalyticsEvent.TradePlaceOrderConfirmed, {
|
||||
roundtripMs: endTimestamp - startTimestamp,
|
||||
validator: compositeClient!.validatorClient.config.restEndpoint,
|
||||
});
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
cancelOrderForSubaccount: async ({
|
||||
subaccount,
|
||||
clientId,
|
||||
clobPairId,
|
||||
orderFlags,
|
||||
goodTilBlock,
|
||||
goodTilBlockTime,
|
||||
}: {
|
||||
subaccount: SubaccountClient;
|
||||
clientId: number;
|
||||
orderFlags: OrderFlags;
|
||||
clobPairId: number;
|
||||
goodTilBlock?: number;
|
||||
goodTilBlockTime?: number;
|
||||
}) => {
|
||||
const startTimestamp = performance.now();
|
||||
|
||||
const result = await compositeClient?.cancelOrder(
|
||||
subaccount,
|
||||
clientId,
|
||||
orderFlags,
|
||||
clobPairId,
|
||||
goodTilBlock,
|
||||
goodTilBlockTime
|
||||
);
|
||||
|
||||
const endTimestamp = performance.now();
|
||||
|
||||
track(AnalyticsEvent.TradeCancelOrderConfirmed, {
|
||||
roundtripMs: endTimestamp - startTimestamp,
|
||||
validator: compositeClient!.validatorClient.config.restEndpoint,
|
||||
});
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
sendSquidWithdrawFromSubaccount: async ({
|
||||
subaccountClient,
|
||||
amount,
|
||||
@@ -353,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();
|
||||
|
||||
@@ -370,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) => {
|
||||
@@ -413,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) {
|
||||
@@ -467,101 +286,41 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
||||
onSuccess,
|
||||
}: {
|
||||
isClosePosition?: boolean;
|
||||
onError?: (onErrorParams?: { errorStringKey?: string }) => void;
|
||||
onSuccess?: () => void;
|
||||
onError?: (onErrorParams?: { errorStringKey?: Nullable<string> }) => void;
|
||||
onSuccess?: (placeOrderPayload: Nullable<HumanReadablePlaceOrderPayload>) => void;
|
||||
}) => {
|
||||
let orderParams: Nullable<HumanReadablePlaceOrderPayload>;
|
||||
const callback = (
|
||||
success: boolean,
|
||||
parsingError?: Nullable<ParsingError>,
|
||||
data?: Nullable<HumanReadablePlaceOrderPayload>
|
||||
) => {
|
||||
if (success) {
|
||||
onSuccess?.(data);
|
||||
} else {
|
||||
onError?.({ errorStringKey: parsingError?.stringKey });
|
||||
|
||||
if (!subaccountClient) return;
|
||||
|
||||
try {
|
||||
orderParams = isClosePosition
|
||||
? abacusStateManager.closePositionPayload()
|
||||
: abacusStateManager.placeOrderPayload();
|
||||
|
||||
if (!orderParams) {
|
||||
throw new Error('Missing order params');
|
||||
if (data?.clientId !== undefined) {
|
||||
dispatch(removeUncommittedOrderClientId(data.clientId));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const {
|
||||
marketId,
|
||||
type,
|
||||
side,
|
||||
price,
|
||||
triggerPrice,
|
||||
size,
|
||||
clientId,
|
||||
timeInForce,
|
||||
goodTilTimeInSeconds,
|
||||
execution,
|
||||
postOnly,
|
||||
reduceOnly,
|
||||
} = orderParams;
|
||||
let placeOrderParams;
|
||||
|
||||
dispatch(addUncommittedOrderClientId(clientId));
|
||||
|
||||
// Remove uncommitted order after timeout if it hasn't already been removed
|
||||
setTimeout(() => {
|
||||
dispatch(removeUncommittedOrderClientId(clientId));
|
||||
}, UNCOMMITTED_ORDER_TIMEOUT);
|
||||
|
||||
console.log('useSubaccount/placeOrder', {
|
||||
...orderParams,
|
||||
});
|
||||
|
||||
const response = await placeOrderForSubaccount({
|
||||
subaccount: subaccountClient,
|
||||
marketId,
|
||||
type: type as OrderType,
|
||||
side: side as OrderSide,
|
||||
price,
|
||||
triggerPrice,
|
||||
size,
|
||||
clientId,
|
||||
timeInForce: timeInForce as OrderTimeInForce,
|
||||
goodTilTimeInSeconds: goodTilTimeInSeconds ?? 0,
|
||||
execution: execution as OrderExecution,
|
||||
postOnly,
|
||||
reduceOnly,
|
||||
});
|
||||
|
||||
// Handle Stateful orders
|
||||
if ((response as IndexedTx)?.code !== 0) {
|
||||
throw new StatefulOrderError('Stateful order has failed to commit.', response);
|
||||
}
|
||||
|
||||
if (orderParams?.clientId) {
|
||||
dispatch(removeUncommittedOrderClientId(orderParams.clientId));
|
||||
}
|
||||
|
||||
if (response?.hash) {
|
||||
console.log(
|
||||
isClosePosition
|
||||
? 'useSubaccount/closePosition'
|
||||
: 'useSubaccount/placeOrderForSubaccount',
|
||||
{
|
||||
txHash: Buffer.from(response.hash).toString('hex').toUpperCase(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
track(AnalyticsEvent.TradePlaceOrder, {
|
||||
...orderParams,
|
||||
isClosePosition,
|
||||
} as HumanReadablePlaceOrderPayload & { isClosePosition: boolean });
|
||||
onSuccess?.();
|
||||
} catch (error) {
|
||||
const errorCode: number | undefined = error?.code;
|
||||
const errorStringKey = errorCode ? ORDER_ERROR_CODE_MAP[errorCode] : undefined;
|
||||
onError?.({ errorStringKey });
|
||||
|
||||
log('useSubaccount/placeOrder', error, {
|
||||
orderParams,
|
||||
isClosePosition,
|
||||
});
|
||||
if (isClosePosition) {
|
||||
placeOrderParams = abacusStateManager.closePosition(callback);
|
||||
} else {
|
||||
placeOrderParams = abacusStateManager.placeOrder(callback);
|
||||
}
|
||||
|
||||
track(AnalyticsEvent.TradePlaceOrder, {
|
||||
...placeOrderParams,
|
||||
isClosePosition,
|
||||
} as HumanReadablePlaceOrderPayload & { isClosePosition: boolean });
|
||||
|
||||
return placeOrderParams;
|
||||
},
|
||||
[subaccountClient, placeOrderForSubaccount]
|
||||
[subaccountClient]
|
||||
);
|
||||
|
||||
const closePosition = useCallback(
|
||||
@@ -569,8 +328,8 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
||||
onError,
|
||||
onSuccess,
|
||||
}: {
|
||||
onError: (onErrorParams?: { errorStringKey?: string }) => void;
|
||||
onSuccess?: () => void;
|
||||
onError: (onErrorParams?: { errorStringKey?: Nullable<string> }) => void;
|
||||
onSuccess?: (placeOrderPayload: Nullable<HumanReadablePlaceOrderPayload>) => void;
|
||||
}) => await placeOrder({ isClosePosition: true, onError, onSuccess }),
|
||||
[placeOrder]
|
||||
);
|
||||
@@ -582,53 +341,21 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
||||
onSuccess,
|
||||
}: {
|
||||
orderId: string;
|
||||
onError?: ({ errorMsg }?: { errorMsg?: string }) => void;
|
||||
onError?: ({ errorStringKey }?: { errorStringKey?: Nullable<string> }) => void;
|
||||
onSuccess?: () => void;
|
||||
}) => {
|
||||
let cancelOrderParams: Nullable<HumanReadableCancelOrderPayload>;
|
||||
|
||||
if (!subaccountClient) return;
|
||||
|
||||
try {
|
||||
cancelOrderParams = abacusStateManager.cancelOrderPayload(orderId);
|
||||
|
||||
if (!cancelOrderParams) {
|
||||
throw new Error('Missing cancel order params');
|
||||
const callback = (success: boolean, parsingError?: Nullable<ParsingError>) => {
|
||||
if (success) {
|
||||
track(AnalyticsEvent.TradeCancelOrder);
|
||||
onSuccess?.();
|
||||
} else {
|
||||
onError?.({ errorStringKey: parsingError?.stringKey });
|
||||
}
|
||||
};
|
||||
|
||||
const { clientId, clobPairId, goodTilBlock, goodTilBlockTime, orderFlags } =
|
||||
cancelOrderParams;
|
||||
|
||||
// Keep for debugging
|
||||
console.log('useSubaccount/cancelOrder', cancelOrderParams);
|
||||
|
||||
const response = await cancelOrderForSubaccount({
|
||||
subaccount: subaccountClient,
|
||||
clientId,
|
||||
orderFlags,
|
||||
clobPairId,
|
||||
goodTilBlock: goodTilBlock || undefined,
|
||||
goodTilBlockTime: goodTilBlockTime || undefined,
|
||||
});
|
||||
|
||||
// Handle Stateful orders
|
||||
if ((response as IndexedTx)?.code !== 0) {
|
||||
throw new StatefulOrderError('Stateful cancel has failed to commit.', response);
|
||||
}
|
||||
|
||||
if (response?.hash) {
|
||||
console.log('useSubaccount/cancelOrderForSubaccount', {
|
||||
txHash: Buffer.from(response.hash).toString('hex').toUpperCase(),
|
||||
});
|
||||
}
|
||||
|
||||
onSuccess?.();
|
||||
} catch (error) {
|
||||
onError?.();
|
||||
log('useSubaccount/cancelOrder', error, cancelOrderParams);
|
||||
}
|
||||
abacusStateManager.cancelOrder(orderId, callback);
|
||||
},
|
||||
[subaccountClient, cancelOrderForSubaccount]
|
||||
[subaccountClient]
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -638,9 +365,7 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
||||
requestFaucetFunds,
|
||||
|
||||
// Transfer Methods
|
||||
simulateTransfer,
|
||||
transfer,
|
||||
simulateWithdraw,
|
||||
sendSquidWithdraw,
|
||||
|
||||
// Trading Methods
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { AbacusTrackingProtocol, Nullable } from '@/constants/abacus';
|
||||
import type { AnalyticsEvent } from '@/constants/analytics';
|
||||
|
||||
import { track } from '../analytics';
|
||||
import { log as telemetryLog } from '../telemetry';
|
||||
|
||||
class AbacusAnalytics implements AbacusTrackingProtocol {
|
||||
log(event: string, data: Nullable<string>) {
|
||||
try {
|
||||
const parsedData = data ? JSON.parse(data) : {};
|
||||
track(event as AnalyticsEvent, parsedData);
|
||||
} catch (error) {
|
||||
telemetryLog('AbacusAnalytics/log', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default AbacusAnalytics;
|
||||
@@ -1,30 +1,51 @@
|
||||
import Abacus, { Nullable } from '@dydxprotocol/v4-abacus';
|
||||
import Abacus, { type Nullable } from '@dydxprotocol/v4-abacus';
|
||||
import Long from 'long';
|
||||
import type { IndexedTx } from '@cosmjs/stargate';
|
||||
|
||||
import {
|
||||
CompositeClient,
|
||||
IndexerConfig,
|
||||
type LocalWallet,
|
||||
Network,
|
||||
NetworkOptimizer,
|
||||
SubaccountClient,
|
||||
ValidatorConfig,
|
||||
OrderType,
|
||||
OrderSide,
|
||||
OrderTimeInForce,
|
||||
OrderExecution,
|
||||
DYDX_DENOM,
|
||||
GAS_PRICE_DYDX_DENOM,
|
||||
} from '@dydxprotocol/v4-client-js';
|
||||
|
||||
import {
|
||||
type AbacusDYDXChainTransactionsProtocol,
|
||||
QueryType,
|
||||
type QueryTypes,
|
||||
TransactionType,
|
||||
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';
|
||||
import { openDialog } from '@/state/dialogs';
|
||||
|
||||
import { StatefulOrderError } from '../errors';
|
||||
import { bytesToBigInt } from '../numbers';
|
||||
import { log } from '../telemetry';
|
||||
|
||||
class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
private compositeClient: CompositeClient | undefined;
|
||||
private store: RootStore | undefined;
|
||||
private localWallet: LocalWallet | undefined;
|
||||
|
||||
constructor() {
|
||||
this.compositeClient = undefined;
|
||||
@@ -35,6 +56,10 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
setLocalWallet(localWallet: LocalWallet) {
|
||||
this.localWallet = localWallet;
|
||||
}
|
||||
|
||||
async connectNetwork(
|
||||
indexerUrl: string,
|
||||
indexerSocketUrl: string,
|
||||
@@ -93,6 +118,10 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
return x.toString() as T;
|
||||
}
|
||||
|
||||
if (x instanceof Uint8Array) {
|
||||
return bytesToBigInt(x).toString() as T;
|
||||
}
|
||||
|
||||
if (typeof x === 'object') {
|
||||
const parsedObj: { [key: string]: any } = {};
|
||||
for (const key in x) {
|
||||
@@ -106,13 +135,218 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
throw new Error(`Unsupported data type: ${typeof x}`);
|
||||
}
|
||||
|
||||
async placeOrderTransaction(params: HumanReadablePlaceOrderPayload): Promise<string> {
|
||||
if (!this.compositeClient || !this.localWallet)
|
||||
throw new Error('Missing compositeClient or localWallet');
|
||||
|
||||
try {
|
||||
const {
|
||||
subaccountNumber,
|
||||
marketId,
|
||||
type,
|
||||
side,
|
||||
price,
|
||||
size,
|
||||
clientId,
|
||||
timeInForce,
|
||||
goodTilTimeInSeconds,
|
||||
execution,
|
||||
postOnly,
|
||||
reduceOnly,
|
||||
triggerPrice,
|
||||
} = params || {};
|
||||
|
||||
// Observe uncommitted order
|
||||
this.store?.dispatch(addUncommittedOrderClientId(clientId));
|
||||
|
||||
setTimeout(() => {
|
||||
this.store?.dispatch(removeUncommittedOrderClientId(clientId));
|
||||
}, UNCOMMITTED_ORDER_TIMEOUT_MS);
|
||||
|
||||
// Place order
|
||||
const tx = await this.compositeClient?.placeOrder(
|
||||
new SubaccountClient(this.localWallet, subaccountNumber),
|
||||
marketId,
|
||||
type as OrderType,
|
||||
side as OrderSide,
|
||||
price,
|
||||
size,
|
||||
clientId,
|
||||
timeInForce as OrderTimeInForce,
|
||||
goodTilTimeInSeconds ?? 0,
|
||||
execution as OrderExecution,
|
||||
postOnly,
|
||||
reduceOnly,
|
||||
triggerPrice ?? undefined
|
||||
);
|
||||
|
||||
// Handle stateful orders
|
||||
if ((tx as IndexedTx)?.code !== 0) {
|
||||
throw new StatefulOrderError('Stateful order has failed to commit.', tx);
|
||||
}
|
||||
|
||||
const parsedTx = this.parseToPrimitives(tx);
|
||||
const hash = parsedTx?.hash;
|
||||
|
||||
if (import.meta.env.MODE === 'production') {
|
||||
console.log(`https://testnet.mintscan.io/dydx-testnet/txs/${hash}`);
|
||||
} else console.log(`txHash: ${hash}`);
|
||||
|
||||
return JSON.stringify(parsedTx);
|
||||
} catch (error) {
|
||||
if (error?.name !== 'BroadcastError') {
|
||||
log('DydxChainTransactions/placeOrderTransaction', error);
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async cancelOrderTransaction(params: HumanReadableCancelOrderPayload): Promise<string> {
|
||||
if (!this.compositeClient || !this.localWallet) {
|
||||
throw new Error('Missing compositeClient or localWallet');
|
||||
}
|
||||
|
||||
const { subaccountNumber, clientId, orderFlags, clobPairId, goodTilBlock, goodTilBlockTime } =
|
||||
params ?? {};
|
||||
|
||||
try {
|
||||
const tx = await this.compositeClient?.cancelOrder(
|
||||
new SubaccountClient(this.localWallet, subaccountNumber),
|
||||
clientId,
|
||||
orderFlags,
|
||||
clobPairId,
|
||||
goodTilBlock ?? undefined,
|
||||
goodTilBlockTime ?? undefined
|
||||
);
|
||||
|
||||
const parsedTx = this.parseToPrimitives(tx);
|
||||
|
||||
return JSON.stringify(parsedTx);
|
||||
} catch (error) {
|
||||
log('DydxChainTransactions/cancelOrderTransaction', error);
|
||||
|
||||
return JSON.stringify({
|
||||
error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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>,
|
||||
callback: (p0: Abacus.Nullable<string>) => void
|
||||
): Promise<void> {
|
||||
// To be implemented
|
||||
return;
|
||||
try {
|
||||
const params = paramsInJson ? JSON.parse(paramsInJson) : undefined;
|
||||
|
||||
switch (type) {
|
||||
case TransactionType.PlaceOrder: {
|
||||
const result = await this.placeOrderTransaction(params);
|
||||
callback(result);
|
||||
break;
|
||||
}
|
||||
case TransactionType.CancelOrder: {
|
||||
const result = await this.cancelOrderTransaction(params);
|
||||
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;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
try {
|
||||
const serializedError = JSON.stringify(error);
|
||||
callback(serializedError);
|
||||
} catch (parseError) {
|
||||
log('DydxChainTransactions/transaction', parseError);
|
||||
}
|
||||
|
||||
log('DydxChainTransactions/transaction', error);
|
||||
}
|
||||
}
|
||||
|
||||
async get(
|
||||
@@ -136,6 +370,12 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
);
|
||||
callback(JSON.stringify({ url: optimalNode }));
|
||||
break;
|
||||
case QueryType.EquityTiers:
|
||||
const equityTiers =
|
||||
await this.compositeClient?.validatorClient.get.getEquityTierLimitConfiguration();
|
||||
const parsedEquityTiers = this.parseToPrimitives(equityTiers);
|
||||
callback(JSON.stringify(parsedEquityTiers));
|
||||
break;
|
||||
case QueryType.FeeTiers:
|
||||
const feeTiers = await this.compositeClient?.validatorClient.get.getFeeTiers();
|
||||
const parsedFeeTiers = this.parseToPrimitives(feeTiers);
|
||||
@@ -155,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:
|
||||
|
||||
+43
-16
@@ -1,3 +1,5 @@
|
||||
import type { LocalWallet } from '@dydxprotocol/v4-client-js';
|
||||
|
||||
import type {
|
||||
ClosePositionInputFields,
|
||||
Nullable,
|
||||
@@ -6,6 +8,7 @@ import type {
|
||||
TradeInputFields,
|
||||
TransferInputFields,
|
||||
HistoricalPnlPeriods,
|
||||
ParsingError,
|
||||
} from '@/constants/abacus';
|
||||
|
||||
import {
|
||||
@@ -30,6 +33,7 @@ import { getInputTradeOptions } from '@/state/inputsSelectors';
|
||||
import { getTransferInputs } from '@/state/inputsSelectors';
|
||||
|
||||
import AbacusRest from './rest';
|
||||
import AbacusAnalytics from './analytics';
|
||||
import AbacusWebsocket from './websocket';
|
||||
import AbacusChainTransaction from './dydxChainTransactions';
|
||||
import AbacusStateNotifier from './stateNotification';
|
||||
@@ -45,23 +49,25 @@ class AbacusStateManager {
|
||||
stateManager: InstanceType<typeof AsyncAbacusStateManager>;
|
||||
websocket: AbacusWebsocket;
|
||||
stateNotifier: AbacusStateNotifier;
|
||||
analytics: AbacusAnalytics;
|
||||
abacusFormatter: AbacusFormatter;
|
||||
chainTransactionClient: AbacusChainTransaction;
|
||||
chainTransactions: AbacusChainTransaction;
|
||||
|
||||
constructor() {
|
||||
this.store = undefined;
|
||||
this.currentMarket = undefined;
|
||||
this.stateNotifier = new AbacusStateNotifier();
|
||||
this.analytics = new AbacusAnalytics();
|
||||
this.websocket = new AbacusWebsocket();
|
||||
this.abacusFormatter = new AbacusFormatter();
|
||||
this.chainTransactionClient = new AbacusChainTransaction();
|
||||
this.chainTransactions = new AbacusChainTransaction();
|
||||
|
||||
const ioImplementations = new IOImplementations(
|
||||
// @ts-ignore
|
||||
new AbacusRest(),
|
||||
this.websocket,
|
||||
this.chainTransactionClient,
|
||||
null,
|
||||
this.chainTransactions,
|
||||
this.analytics,
|
||||
new AbacusThreading(),
|
||||
new CoroutineTimer(),
|
||||
new AbacusFileSystem()
|
||||
@@ -157,11 +163,14 @@ class AbacusStateManager {
|
||||
setStore = (store: RootStore) => {
|
||||
this.store = store;
|
||||
this.stateNotifier.setStore(store);
|
||||
this.chainTransactionClient.setStore(store);
|
||||
this.chainTransactions.setStore(store);
|
||||
};
|
||||
|
||||
setAccount = (walletAddress: string) => {
|
||||
this.stateManager.accountAddress = walletAddress;
|
||||
setAccount = (localWallet?: LocalWallet) => {
|
||||
if (localWallet) {
|
||||
this.stateManager.accountAddress = localWallet.address;
|
||||
this.chainTransactions.setLocalWallet(localWallet);
|
||||
}
|
||||
};
|
||||
|
||||
setTransfersSourceAddress = (evmAddress: string) => {
|
||||
@@ -219,16 +228,34 @@ class AbacusStateManager {
|
||||
this.stateManager.transferStatus(hash, fromChainId, toChainId);
|
||||
};
|
||||
|
||||
// ------ Transactions ------ //
|
||||
|
||||
placeOrder = (
|
||||
callback: (
|
||||
success: boolean,
|
||||
parsingError: Nullable<ParsingError>,
|
||||
data: Nullable<HumanReadablePlaceOrderPayload>
|
||||
) => void
|
||||
): Nullable<HumanReadablePlaceOrderPayload> => this.stateManager.commitPlaceOrder(callback);
|
||||
|
||||
closePosition = (
|
||||
callback: (
|
||||
success: boolean,
|
||||
parsingError: Nullable<ParsingError>,
|
||||
data: Nullable<HumanReadablePlaceOrderPayload>
|
||||
) => void
|
||||
): Nullable<HumanReadablePlaceOrderPayload> => this.stateManager.commitClosePosition(callback);
|
||||
|
||||
cancelOrder = (
|
||||
orderId: string,
|
||||
callback: (
|
||||
success: boolean,
|
||||
parsingError: Nullable<ParsingError>,
|
||||
data: Nullable<HumanReadableCancelOrderPayload>
|
||||
) => void
|
||||
) => this.stateManager.cancelOrder(orderId, callback);
|
||||
|
||||
// ------ Utils ------ //
|
||||
placeOrderPayload = (): Nullable<HumanReadablePlaceOrderPayload> =>
|
||||
this.stateManager.placeOrderPayload();
|
||||
|
||||
closePositionPayload = (): Nullable<HumanReadablePlaceOrderPayload> =>
|
||||
this.stateManager.closePositionPayload();
|
||||
|
||||
cancelOrderPayload = (orderId: string): Nullable<HumanReadableCancelOrderPayload> =>
|
||||
this.stateManager.cancelOrderPayload(orderId);
|
||||
|
||||
getHistoricalPnlPeriod = (): Nullable<HistoricalPnlPeriods> =>
|
||||
this.stateManager.historicalPnlPeriod;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { kollections } from '@dydxprotocol/v4-abacus';
|
||||
|
||||
import type {
|
||||
AccountBalance,
|
||||
AbacusApiState,
|
||||
AbacusNotification,
|
||||
AbacusStateNotificationProtocol,
|
||||
@@ -18,9 +19,11 @@ import { Changes } from '@/constants/abacus';
|
||||
import type { RootStore } from '@/state/_store';
|
||||
|
||||
import {
|
||||
setBalances,
|
||||
setFills,
|
||||
setFundingPayments,
|
||||
setHistoricalPnl,
|
||||
setLatestOrder,
|
||||
setSubaccount,
|
||||
setTransfers,
|
||||
setWallet,
|
||||
@@ -71,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));
|
||||
}
|
||||
@@ -155,7 +168,9 @@ class AbacusStateNotifier implements AbacusStateNotificationProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
lastOrderChanged(order: SubaccountOrder) {}
|
||||
lastOrderChanged(order: SubaccountOrder) {
|
||||
this.store?.dispatch(setLatestOrder(order));
|
||||
}
|
||||
|
||||
errorsEmitted(errors: ParsingErrors) {
|
||||
console.error('parse errors', errors.toArray());
|
||||
|
||||
@@ -5,10 +5,15 @@ import type {
|
||||
AnalyticsEventData,
|
||||
} from '@/constants/analytics';
|
||||
|
||||
const DEBUG_ANALYTICS = false;
|
||||
|
||||
export const identify = <T extends AnalyticsUserProperty>(
|
||||
property: T,
|
||||
propertyValue: AnalyticsUserPropertyValue<T>
|
||||
) => {
|
||||
if (DEBUG_ANALYTICS) {
|
||||
console.log(`[Analytics:Identify] ${property}`, propertyValue);
|
||||
}
|
||||
const customEvent = new CustomEvent('dydx:identify', {
|
||||
detail: { property, propertyValue },
|
||||
});
|
||||
@@ -20,6 +25,9 @@ export const track = <T extends AnalyticsEvent>(
|
||||
eventType: T,
|
||||
eventData?: AnalyticsEventData<T>
|
||||
) => {
|
||||
if (DEBUG_ANALYTICS) {
|
||||
console.log(`[Analytics] ${eventType}`, eventData);
|
||||
}
|
||||
const customEvent = new CustomEvent('dydx:track', {
|
||||
detail: { eventType, eventData },
|
||||
});
|
||||
|
||||
@@ -66,3 +66,17 @@ export const getSeparator = ({
|
||||
Intl.NumberFormat(browserLanguage)
|
||||
.formatToParts(1000.1)
|
||||
.find?.((part) => part.type === separatorType)?.value;
|
||||
|
||||
/**
|
||||
* Converts a byte array (representing an arbitrary-size signed integer) into a bigint.
|
||||
* @param u Array of bytes represented as a Uint8Array.
|
||||
*/
|
||||
export function bytesToBigInt(u: Uint8Array): bigint {
|
||||
if (u.length <= 1) {
|
||||
return BigInt(0);
|
||||
}
|
||||
const negated: boolean = (u[0] & 1) === 1;
|
||||
const hex: string = Buffer.from(u.slice(1)).toString('hex');
|
||||
const abs: bigint = BigInt(`0x${hex}`);
|
||||
return negated ? -abs : abs;
|
||||
}
|
||||
|
||||
@@ -58,6 +58,12 @@ export const getStatusIconInfo = ({
|
||||
statusIconColor: `var(--color-negative)`,
|
||||
};
|
||||
}
|
||||
case AbacusOrderStatus.untriggered: {
|
||||
return {
|
||||
statusIcon: IconName.OrderUntriggered,
|
||||
statusIconColor: `var(--color-text-2)`,
|
||||
};
|
||||
}
|
||||
case AbacusOrderStatus.pending:
|
||||
default: {
|
||||
return {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useState } from 'react';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||
|
||||
import { AbacusOrderStatus } from '@/constants/abacus';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
|
||||
import { useBreakpoints, useStringGetter } from '@/hooks';
|
||||
@@ -18,13 +19,16 @@ import { FillsTable, FillsTableColumnKey } from '@/views/tables/FillsTable';
|
||||
import { OrdersTable, OrdersTableColumnKey } from '@/views/tables/OrdersTable';
|
||||
import { PositionsTable, PositionsTableColumnKey } from '@/views/tables/PositionsTable';
|
||||
|
||||
import { calculateIsAccountViewOnly } from '@/state/accountCalculators';
|
||||
|
||||
import {
|
||||
calculateHasUncommittedOrders,
|
||||
calculateIsAccountViewOnly,
|
||||
} from '@/state/accountCalculators';
|
||||
|
||||
import {
|
||||
getCurrentMarketTradeInfoNumbers,
|
||||
getHasUnseenFillUpdates,
|
||||
getHasUnseenOrderUpdates,
|
||||
getLatestOrderStatus,
|
||||
getTradeInfoNumbers,
|
||||
} from '@/state/accountSelectors';
|
||||
|
||||
@@ -69,8 +73,7 @@ export const HorizontalPanel = ({ isOpen = true, setIsOpen }: ElementProps) => {
|
||||
const hasUnseenOrderUpdates = useSelector(getHasUnseenOrderUpdates);
|
||||
const hasUnseenFillUpdates = useSelector(getHasUnseenFillUpdates);
|
||||
const isAccountViewOnly = useSelector(calculateIsAccountViewOnly);
|
||||
const hasUncommittedOrders = useSelector(calculateHasUncommittedOrders);
|
||||
|
||||
const isWaitingForOrderToIndex = useSelector(calculateHasUncommittedOrders);
|
||||
const showCurrentMarket = isTablet || view === PanelView.CurrentMarket;
|
||||
|
||||
const fillsTagNumber = shortenNumberForDisplay(showCurrentMarket ? numFills : numTotalFills);
|
||||
@@ -118,7 +121,7 @@ export const HorizontalPanel = ({ isOpen = true, setIsOpen }: ElementProps) => {
|
||||
value: InfoSection.Orders,
|
||||
label: stringGetter({ key: STRING_KEYS.ORDERS }),
|
||||
|
||||
slotRight: hasUncommittedOrders ? (
|
||||
slotRight: isWaitingForOrderToIndex ? (
|
||||
<Styled.LoadingSpinner />
|
||||
) : (
|
||||
ordersTagNumber && (
|
||||
|
||||
@@ -4,7 +4,6 @@ import abacusStateManager from '@/lib/abacus';
|
||||
import appMiddleware from './appMiddleware';
|
||||
import localizationMiddleware from './localizationMiddleware';
|
||||
import routerMiddleware from './routerMiddleware';
|
||||
import tradeMiddleware from './tradeMiddleware';
|
||||
|
||||
import { accountSlice } from './account';
|
||||
import { appSlice } from './app';
|
||||
@@ -40,7 +39,6 @@ export const store = configureStore({
|
||||
appMiddleware,
|
||||
localizationMiddleware,
|
||||
routerMiddleware,
|
||||
tradeMiddleware,
|
||||
],
|
||||
|
||||
devTools: process.env.NODE_ENV !== 'production',
|
||||
|
||||
+31
-14
@@ -1,6 +1,7 @@
|
||||
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
||||
|
||||
import type {
|
||||
AccountBalance,
|
||||
SubaccountFill,
|
||||
Nullable,
|
||||
Subaccount,
|
||||
@@ -24,16 +25,18 @@ export type AccountState = {
|
||||
fundingPayments?: SubaccountFundingPayments;
|
||||
transfers?: SubaccountTransfers;
|
||||
clearedOrderIds?: string[];
|
||||
uncommittedOrderClientIds?: number[];
|
||||
hasUnseenFillUpdates: boolean;
|
||||
hasUnseenOrderUpdates: boolean;
|
||||
historicalPnl?: SubAccountHistoricalPNLs;
|
||||
latestOrder?: Nullable<SubaccountOrder>;
|
||||
onboardingGuards: Record<OnboardingGuard, boolean | undefined>;
|
||||
onboardingState: OnboardingState;
|
||||
subaccount?: Nullable<Subaccount>;
|
||||
uncommittedOrderClientIds: number[];
|
||||
wallet?: Nullable<Wallet>;
|
||||
walletType?: WalletType;
|
||||
historicalPnlPeriod?: HistoricalPnlPeriods;
|
||||
balances?: Record<string, AccountBalance>;
|
||||
};
|
||||
|
||||
const initialState: AccountState = {
|
||||
@@ -41,10 +44,10 @@ const initialState: AccountState = {
|
||||
fundingPayments: undefined,
|
||||
transfers: undefined,
|
||||
clearedOrderIds: undefined,
|
||||
uncommittedOrderClientIds: undefined,
|
||||
hasUnseenFillUpdates: false,
|
||||
hasUnseenOrderUpdates: false,
|
||||
historicalPnl: undefined,
|
||||
latestOrder: undefined,
|
||||
onboardingGuards: {
|
||||
[OnboardingGuard.hasAcknowledgedTerms]: Boolean(
|
||||
getLocalStorage<boolean>({
|
||||
@@ -56,6 +59,7 @@ const initialState: AccountState = {
|
||||
},
|
||||
onboardingState: OnboardingState.Disconnected,
|
||||
subaccount: undefined,
|
||||
uncommittedOrderClientIds: [],
|
||||
wallet: undefined,
|
||||
walletType: getLocalStorage<WalletType>({
|
||||
key: LocalStorageKey.OnboardingSelectedWalletType,
|
||||
@@ -86,6 +90,16 @@ export const accountSlice = createSlice({
|
||||
setTransfers: (state, action: PayloadAction<any>) => {
|
||||
state.transfers = action.payload;
|
||||
},
|
||||
setLatestOrder: (state, action: PayloadAction<Nullable<SubaccountOrder>>) => {
|
||||
const { clientId } = action.payload ?? {};
|
||||
state.latestOrder = action.payload;
|
||||
|
||||
if (clientId) {
|
||||
state.uncommittedOrderClientIds = state.uncommittedOrderClientIds.filter(
|
||||
(id) => id !== clientId
|
||||
);
|
||||
}
|
||||
},
|
||||
clearOrder: (state, action: PayloadAction<string>) => ({
|
||||
...state,
|
||||
clearedOrderIds: [...(state.clearedOrderIds || []), action.payload],
|
||||
@@ -131,22 +145,23 @@ export const accountSlice = createSlice({
|
||||
...state,
|
||||
wallet: action.payload,
|
||||
}),
|
||||
addUncommittedOrderClientId: (state, action: PayloadAction<number>) => {
|
||||
state.uncommittedOrderClientIds = state.uncommittedOrderClientIds
|
||||
? [...state.uncommittedOrderClientIds, action.payload]
|
||||
: [action.payload];
|
||||
},
|
||||
removeUncommittedOrderClientId: (state, action: PayloadAction<number>) => {
|
||||
state.uncommittedOrderClientIds = state.uncommittedOrderClientIds?.filter(
|
||||
(clientId) => clientId !== action.payload
|
||||
);
|
||||
},
|
||||
viewedFills: (state) => {
|
||||
state.hasUnseenFillUpdates = false;
|
||||
},
|
||||
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);
|
||||
},
|
||||
removeUncommittedOrderClientId: (state, action: PayloadAction<number>) => {
|
||||
state.uncommittedOrderClientIds = state.uncommittedOrderClientIds.filter(
|
||||
(id) => id !== action.payload
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -154,14 +169,16 @@ export const {
|
||||
setFills,
|
||||
setFundingPayments,
|
||||
setTransfers,
|
||||
setLatestOrder,
|
||||
clearOrder,
|
||||
setOnboardingGuard,
|
||||
setOnboardingState,
|
||||
setHistoricalPnl,
|
||||
setSubaccount,
|
||||
setWallet,
|
||||
addUncommittedOrderClientId,
|
||||
removeUncommittedOrderClientId,
|
||||
viewedFills,
|
||||
viewedOrders,
|
||||
setBalances,
|
||||
addUncommittedOrderClientId,
|
||||
removeUncommittedOrderClientId,
|
||||
} = accountSlice.actions;
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
getOnboardingGuards,
|
||||
getOnboardingState,
|
||||
getSubaccountId,
|
||||
getUncommittedOrderClientIds,
|
||||
} from '@/state/accountSelectors';
|
||||
|
||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||
@@ -69,6 +70,11 @@ export const calculateHasOpenPositions = createSelector(
|
||||
(openPositions?: SubaccountPosition[]) => (openPositions?.length || 0) > 0
|
||||
);
|
||||
|
||||
export const calculateHasUncommittedOrders = createSelector(
|
||||
[getUncommittedOrderClientIds],
|
||||
(uncommittedOrderClientIds: number[]) => uncommittedOrderClientIds.length > 0
|
||||
);
|
||||
|
||||
/**
|
||||
* @description calculate whether the client is loading info.
|
||||
* (account is connected but subaccountId is till missing)
|
||||
|
||||
@@ -78,6 +78,12 @@ export const getCurrentMarketPositionData = (state: RootState) => {
|
||||
export const getSubaccountOrders = (state: RootState) =>
|
||||
state.account.subaccount?.orders?.toArray();
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns latestOrder of the currently connected subaccount throughout this session
|
||||
*/
|
||||
export const getLatestOrder = (state: RootState) => state.account?.latestOrder;
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns list of order ids that user has cleared and should be hidden
|
||||
@@ -115,7 +121,26 @@ export const getSubaccountOpenOrdersBySideAndPrice = createSelector(
|
||||
);
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns the clientId of the latest order
|
||||
*/
|
||||
export const getLatestOrderClientId = createSelector([getLatestOrder], (order) => order?.clientId);
|
||||
|
||||
/**
|
||||
* @returns the rawValue status of the latest order
|
||||
*/
|
||||
export const getLatestOrderStatus = createSelector(
|
||||
[getLatestOrder],
|
||||
(order) => order?.status.rawValue
|
||||
);
|
||||
|
||||
/**
|
||||
* @returns a list of clientIds belonging to uncommmited orders
|
||||
*/
|
||||
export const getUncommittedOrderClientIds = (state: RootState) =>
|
||||
state.account.uncommittedOrderClientIds;
|
||||
|
||||
/**
|
||||
* @param orderId
|
||||
* @returns order details with the given orderId
|
||||
*/
|
||||
export const getOrderDetails = (orderId: string) =>
|
||||
@@ -283,21 +308,6 @@ export const getIsAccountConnected = (state: RootState) =>
|
||||
*/
|
||||
export const getOnboardingGuards = (state: RootState) => state.account.onboardingGuards;
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns a boolean indicating whether the user has uncommitted orders
|
||||
*/
|
||||
export const calculateHasUncommittedOrders = (state: RootState) => {
|
||||
return !!state.account.uncommittedOrderClientIds?.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns List of uncommitted order clientIds
|
||||
*/
|
||||
export const getUncommittedOrderClientIds = (state: RootState) =>
|
||||
state.account.uncommittedOrderClientIds;
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns Whether there are unseen fill updates
|
||||
@@ -322,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;
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
|
||||
import type { SubaccountOrder } from '@/constants/abacus';
|
||||
|
||||
import { removeUncommittedOrderClientId, setSubaccount } from '@/state/account';
|
||||
|
||||
import { getSubaccountOrders, getUncommittedOrderClientIds } from '@/state/accountSelectors';
|
||||
|
||||
export default (store: any) => (next: any) => async (action: PayloadAction<any>) => {
|
||||
const { type, payload } = action;
|
||||
const state = store.getState();
|
||||
next(action);
|
||||
|
||||
switch (type) {
|
||||
case setSubaccount.type: {
|
||||
const updatedOrders = payload?.orders?.toArray() || [];
|
||||
const orders = getSubaccountOrders(state);
|
||||
const uncommittedOrderClientIds = getUncommittedOrderClientIds(state);
|
||||
|
||||
if (uncommittedOrderClientIds?.length && updatedOrders?.length !== orders?.length) {
|
||||
const updatedOrdersClientIds = Object.fromEntries(
|
||||
updatedOrders.map((order: SubaccountOrder) => [order.clientId, order])
|
||||
);
|
||||
|
||||
const receivedClientId = uncommittedOrderClientIds.find(
|
||||
(clientId) => updatedOrdersClientIds[clientId]
|
||||
);
|
||||
|
||||
if (receivedClientId) {
|
||||
store.dispatch(removeUncommittedOrderClientId(receivedClientId));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -62,8 +62,10 @@ export const AccountInfoConnectedState = () => {
|
||||
const { buyingPower, equity, marginUsage, leverage } = subAccount || {};
|
||||
|
||||
const hasDiff =
|
||||
marginUsage?.postOrder != null &&
|
||||
!MustBigNumber(marginUsage?.postOrder).eq(MustBigNumber(marginUsage?.current));
|
||||
(marginUsage?.postOrder !== null &&
|
||||
!MustBigNumber(marginUsage?.postOrder).eq(MustBigNumber(marginUsage?.current))) ||
|
||||
(buyingPower?.postOrder !== null &&
|
||||
!MustBigNumber(buyingPower?.postOrder).eq(MustBigNumber(buyingPower?.current)));
|
||||
|
||||
const showHeader = !hasDiff && !isTablet;
|
||||
|
||||
|
||||
@@ -15,14 +15,17 @@ export const MarketLinks = () => {
|
||||
|
||||
const linkItems = [
|
||||
{
|
||||
key: 'coinmarketcap',
|
||||
href: coinMarketCapsLink,
|
||||
icon: IconName.CoinMarketCap,
|
||||
},
|
||||
{
|
||||
key: 'whitepaper',
|
||||
href: whitepaperLink,
|
||||
icon: IconName.Whitepaper,
|
||||
},
|
||||
{
|
||||
key: 'project-website',
|
||||
href: websiteLink,
|
||||
icon: IconName.Website,
|
||||
},
|
||||
@@ -31,8 +34,8 @@ export const MarketLinks = () => {
|
||||
return (
|
||||
<Styled.MarketLinks>
|
||||
{linkItems.map(
|
||||
({ href, icon }) =>
|
||||
href && <IconButton key={href} href={href} iconName={icon} type={ButtonType.Link} />
|
||||
({ key, href, icon }) =>
|
||||
href && <IconButton key={key} href={href} iconName={icon} type={ButtonType.Link} />
|
||||
)}
|
||||
</Styled.MarketLinks>
|
||||
);
|
||||
|
||||
@@ -49,7 +49,6 @@ const useTradeTypeOptions = () => {
|
||||
value && {
|
||||
value: value as TradeTypes,
|
||||
label,
|
||||
disabled: import.meta.env.MODE === 'production', // TODO: Remove this when stop orders are supported on testnet
|
||||
}
|
||||
)
|
||||
.filter(isTruthy),
|
||||
|
||||
@@ -7,9 +7,11 @@ import { StatusResponse } from '@0xsquid/sdk';
|
||||
import { useInterval, useStringGetter } from '@/hooks';
|
||||
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { AlertType } from '@/constants/alerts';
|
||||
|
||||
import { formatSeconds } from '@/lib/timeUtils';
|
||||
|
||||
import { AlertMessage } from '@/components/AlertMessage';
|
||||
import { Output, OutputType } from '@/components/Output';
|
||||
import { WithReceipt } from '@/components/WithReceipt';
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
@@ -33,6 +35,9 @@ export const TransferStatusToast = ({
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
const [secondsLeft, setSecondsLeft] = useState<number | undefined>();
|
||||
|
||||
// @ts-ignore status.errors is not in the type definition but can be returned
|
||||
const error = status?.errors?.length ? status?.errors[0] : status?.error;
|
||||
|
||||
const type = useMemo(
|
||||
() => (status?.toChain?.chainData?.chainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdrawal'),
|
||||
[status]
|
||||
@@ -74,6 +79,16 @@ export const TransferStatusToast = ({
|
||||
},
|
||||
})}
|
||||
</Styled.Status>
|
||||
{error && (
|
||||
<AlertMessage type={AlertType.Error}>
|
||||
{stringGetter({
|
||||
key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
|
||||
params: {
|
||||
ERROR_MESSAGE: error.message || stringGetter({ key: STRING_KEYS.UNKNOWN_ERROR }),
|
||||
},
|
||||
})}
|
||||
</AlertMessage>
|
||||
)}
|
||||
<Styled.Trigger>
|
||||
<Styled.TriggerIcon>
|
||||
<Icon iconName={IconName.Caret} />
|
||||
|
||||
@@ -59,7 +59,7 @@ export const TransferStatusSteps = ({ status }: ElementProps) => {
|
||||
},
|
||||
];
|
||||
|
||||
const currentStatus = routeStatus[routeStatus?.length - 1];
|
||||
const currentStatus = routeStatus?.[routeStatus?.length - 1];
|
||||
|
||||
let currentStep = TransferStatusStep.Bridge;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
import { AbacusOrderStatus, AbacusOrderTypes, type Nullable } from '@/constants/abacus';
|
||||
import { ButtonAction } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { STRING_KEYS, type StringKey } from '@/constants/localization';
|
||||
|
||||
import { AssetIcon } from '@/components/AssetIcon';
|
||||
import { Button } from '@/components/Button';
|
||||
@@ -47,7 +47,7 @@ export const OrderDetailsDialog = ({ orderId, setIsOpen }: ElementProps) => {
|
||||
const { cancelOrder } = useSubaccount();
|
||||
|
||||
const {
|
||||
asset = {},
|
||||
asset,
|
||||
cancelReason,
|
||||
createdAtMilliseconds,
|
||||
expiresAtMilliseconds,
|
||||
@@ -57,7 +57,7 @@ export const OrderDetailsDialog = ({ orderId, setIsOpen }: ElementProps) => {
|
||||
price,
|
||||
reduceOnly,
|
||||
totalFilled,
|
||||
resources = {},
|
||||
resources,
|
||||
size,
|
||||
status,
|
||||
stepSizeDecimals,
|
||||
@@ -121,7 +121,9 @@ export const OrderDetailsDialog = ({ orderId, setIsOpen }: ElementProps) => {
|
||||
{
|
||||
key: 'cancel-reason',
|
||||
label: stringGetter({ key: STRING_KEYS.CANCEL_REASON }),
|
||||
value: cancelReason ? stringGetter({ key: STRING_KEYS[cancelReason] }) : undefined,
|
||||
value: cancelReason
|
||||
? stringGetter({ key: STRING_KEYS[cancelReason as StringKey] })
|
||||
: undefined,
|
||||
},
|
||||
{
|
||||
key: 'amount',
|
||||
@@ -182,8 +184,7 @@ export const OrderDetailsDialog = ({ orderId, setIsOpen }: ElementProps) => {
|
||||
|
||||
const onCancelClick = async () => {
|
||||
setIsPlacingCancel(true);
|
||||
await cancelOrder({ orderId });
|
||||
setIsPlacingCancel(false);
|
||||
await cancelOrder({ orderId, onError: () => setIsPlacingCancel(false) });
|
||||
};
|
||||
|
||||
const onClearClick = () => {
|
||||
|
||||
@@ -5,8 +5,6 @@ import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import { AbacusApiStatus } from '@/constants/abacus';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks';
|
||||
import { UNICODE } from '@/constants/unicode';
|
||||
import { useApiState, useStringGetter } from '@/hooks';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
@@ -31,16 +29,8 @@ export const ExchangeOfflineDialog = ({ preventClose, setIsOpen }: ElementProps)
|
||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||
const activeDialog = useSelector(getActiveDialog, shallowEqual);
|
||||
|
||||
const showOfflineMessage =
|
||||
import.meta.env.MODE === 'production' &&
|
||||
CLIENT_NETWORK_CONFIGS[selectedNetwork].dydxChainId === 'dydx-testnet-3';
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
activeDialog?.type === DialogTypes.ExchangeOffline &&
|
||||
status === AbacusApiStatus.NORMAL &&
|
||||
!showOfflineMessage
|
||||
) {
|
||||
if (activeDialog?.type === DialogTypes.ExchangeOffline && status === AbacusApiStatus.NORMAL) {
|
||||
dispatch(closeDialog());
|
||||
}
|
||||
}, [status, selectedNetwork]);
|
||||
@@ -53,16 +43,7 @@ export const ExchangeOfflineDialog = ({ preventClose, setIsOpen }: ElementProps)
|
||||
title={stringGetter({ key: STRING_KEYS.UNAVAILABLE })}
|
||||
>
|
||||
<Styled.Content>
|
||||
{showOfflineMessage ? (
|
||||
<>
|
||||
<p>Testnet is currently offline. Please check back!</p>
|
||||
<Styled.Link href="https://v4-teacher.vercel.app/testnets/schedule">
|
||||
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} {UNICODE.ARROW_RIGHT}
|
||||
</Styled.Link>
|
||||
</>
|
||||
) : (
|
||||
<p>{statusErrorMessage}</p>
|
||||
)}
|
||||
<p>{statusErrorMessage}</p>
|
||||
{import.meta.env.MODE !== 'production' && <NetworkSelectMenu />}
|
||||
</Styled.Content>
|
||||
</Dialog>
|
||||
|
||||
@@ -17,7 +17,7 @@ import { Ring } from '@/components/Ring';
|
||||
import { ToggleGroup } from '@/components/ToggleGroup';
|
||||
|
||||
import { getCurrentMarketAssetData } from '@/state/assetsSelectors';
|
||||
import { getInputTradeData } from '@/state/inputsSelectors';
|
||||
import { getInputTradeData, getInputTradeOptions } from '@/state/inputsSelectors';
|
||||
|
||||
import abacusStateManager from '@/lib/abacus';
|
||||
import { getSelectedTradeType } from '@/lib/tradeData';
|
||||
@@ -35,6 +35,15 @@ export const TradeDialog = ({ isOpen, setIsOpen, slotTrigger }: ElementProps) =>
|
||||
const currentTradeData = useSelector(getInputTradeData, shallowEqual);
|
||||
const { type } = currentTradeData || {};
|
||||
const selectedTradeType = getSelectedTradeType(type);
|
||||
const { typeOptions } = useSelector(getInputTradeOptions, shallowEqual) ?? {};
|
||||
|
||||
const allTradeTypeItems = typeOptions?.toArray()?.map(({ type, stringKey }) => ({
|
||||
value: type,
|
||||
label: stringGetter({
|
||||
key: stringKey,
|
||||
}),
|
||||
slotBefore: <AssetIcon symbol={symbol} />,
|
||||
}));
|
||||
|
||||
const [currentStep, setCurrentStep] = useState<MobilePlaceOrderSteps>(
|
||||
MobilePlaceOrderSteps.EditOrder
|
||||
@@ -62,11 +71,7 @@ export const TradeDialog = ({ isOpen, setIsOpen, slotTrigger }: ElementProps) =>
|
||||
[MobilePlaceOrderSteps.EditOrder]: {
|
||||
title: (
|
||||
<Styled.ToggleGroup
|
||||
items={[TradeTypes.LIMIT, TradeTypes.MARKET].map((tradeType: TradeTypes) => ({
|
||||
value: tradeType,
|
||||
label: stringGetter({ key: TRADE_TYPE_STRINGS[tradeType].tradeTypeKey }),
|
||||
slotBefore: <AssetIcon symbol={symbol} />,
|
||||
}))}
|
||||
items={allTradeTypeItems}
|
||||
value={selectedTradeType}
|
||||
onValueChange={(tradeType: TradeTypes) =>
|
||||
onTradeTypeChange(tradeType || selectedTradeType)
|
||||
@@ -126,6 +131,8 @@ Styled.Dialog = styled(Dialog)<{ currentStep: MobilePlaceOrderSteps }>`
|
||||
`;
|
||||
|
||||
Styled.ToggleGroup = styled(ToggleGroup)`
|
||||
overflow-x: auto;
|
||||
|
||||
button[data-state='off'] {
|
||||
gap: 0;
|
||||
|
||||
|
||||
@@ -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';
|
||||
@@ -38,6 +38,7 @@ import { getTransferInputs } from '@/state/inputsSelectors';
|
||||
import abacusStateManager from '@/lib/abacus';
|
||||
import { MustBigNumber } from '@/lib/numbers';
|
||||
import { log } from '@/lib/telemetry';
|
||||
import { parseWalletError } from '@/lib/wallet';
|
||||
|
||||
import { ChainSelectMenu } from './ChainSelectMenu';
|
||||
import { TokenSelectMenu } from './TokenSelectMenu';
|
||||
@@ -85,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,
|
||||
@@ -286,12 +287,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
|
||||
const errorMessage = useMemo(() => {
|
||||
if (error) {
|
||||
return error?.message
|
||||
? stringGetter({
|
||||
key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
|
||||
params: { ERROR_MESSAGE: error.message },
|
||||
})
|
||||
: stringGetter({ key: STRING_KEYS.SOMETHING_WENT_WRONG });
|
||||
return parseWalletError({ error, stringGetter }).message;
|
||||
}
|
||||
|
||||
if (fromAmount) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
import { type FormEvent, useEffect, useState } from 'react';
|
||||
import { type FormEvent, useCallback, useEffect, useState } from 'react';
|
||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { ClosePositionInputField } from '@/constants/abacus';
|
||||
import {
|
||||
ClosePositionInputField,
|
||||
type HumanReadablePlaceOrderPayload,
|
||||
type Nullable,
|
||||
} from '@/constants/abacus';
|
||||
import { AlertType } from '@/constants/alerts';
|
||||
import { ButtonAction, ButtonShape, ButtonSize, ButtonType } from '@/constants/buttons';
|
||||
import { TOKEN_DECIMALS } from '@/constants/numbers';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { MobilePlaceOrderSteps } from '@/constants/trade';
|
||||
import { useBreakpoints, useIsFirstRender, useStringGetter, useSubaccount } from '@/hooks';
|
||||
import { useOnLastOrderIndexed } from '@/hooks/useOnLastOrderIndexed';
|
||||
|
||||
import { breakpoints } from '@/styles';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
@@ -27,10 +32,7 @@ import { Orderbook, orderbookMixins, type OrderbookScrollBehavior } from '@/view
|
||||
|
||||
import { PositionPreview } from '@/views/forms/TradeForm/PositionPreview';
|
||||
|
||||
import {
|
||||
calculateHasUncommittedOrders,
|
||||
getCurrentMarketPositionData,
|
||||
} from '@/state/accountSelectors';
|
||||
import { getCurrentMarketPositionData } from '@/state/accountSelectors';
|
||||
|
||||
import { getCurrentMarketAssetData } from '@/state/assetsSelectors';
|
||||
import { getInputClosePositionData } from '@/state/inputsSelectors';
|
||||
@@ -82,9 +84,7 @@ export const ClosePositionForm = ({
|
||||
const { stepSizeDecimals } = useSelector(getCurrentMarketConfig, shallowEqual) || {};
|
||||
const { size: sizeData, summary } = useSelector(getInputClosePositionData, shallowEqual) || {};
|
||||
const { size, percent } = sizeData || {};
|
||||
const hasUncommittedOrders = useSelector(calculateHasUncommittedOrders);
|
||||
const currentInput = useSelector(getCurrentInput);
|
||||
|
||||
const currentPositionData = useSelector(getCurrentMarketPositionData, shallowEqual);
|
||||
const { size: currentPositionSize } = currentPositionData || {};
|
||||
const { current: currentSize } = currentPositionSize || {};
|
||||
@@ -106,17 +106,22 @@ export const ClosePositionForm = ({
|
||||
}
|
||||
}, [currentInput, market, currentStep]);
|
||||
|
||||
useEffect(() => {
|
||||
// close has been placed
|
||||
if (!isFirstRender && !hasUncommittedOrders) {
|
||||
const onLastOrderIndexed = useCallback(() => {
|
||||
if (!isFirstRender) {
|
||||
abacusStateManager.clearClosePositionInputValues({ shouldFocusOnTradeInput: true });
|
||||
onClosePositionSuccess?.();
|
||||
|
||||
if (currentStep === MobilePlaceOrderSteps.PlacingOrder) {
|
||||
setCurrentStep?.(MobilePlaceOrderSteps.Confirmation);
|
||||
}
|
||||
|
||||
setIsClosingPosition(false);
|
||||
}
|
||||
}, [hasUncommittedOrders]);
|
||||
}, [currentStep, isFirstRender]);
|
||||
|
||||
const { setUnIndexedClientId } = useOnLastOrderIndexed({
|
||||
callback: onLastOrderIndexed,
|
||||
});
|
||||
|
||||
const onAmountInput = ({ floatValue }: { floatValue?: number }) => {
|
||||
if (currentSize == null) return;
|
||||
@@ -165,14 +170,16 @@ export const ClosePositionForm = ({
|
||||
setIsClosingPosition(true);
|
||||
|
||||
await closePosition({
|
||||
onError: (errorParams?: { errorStringKey?: string }) => {
|
||||
onError: (errorParams?: { errorStringKey?: Nullable<string> }) => {
|
||||
setClosePositionError(
|
||||
stringGetter({ key: errorParams?.errorStringKey || STRING_KEYS.SOMETHING_WENT_WRONG })
|
||||
);
|
||||
setIsClosingPosition(false);
|
||||
},
|
||||
onSuccess: (placeOrderPayload: Nullable<HumanReadablePlaceOrderPayload>) => {
|
||||
setUnIndexedClientId(placeOrderPayload?.clientId);
|
||||
},
|
||||
});
|
||||
|
||||
setIsClosingPosition(false);
|
||||
};
|
||||
|
||||
const alertMessage = closePositionError && (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type FormEvent, useState, useEffect, Ref } from 'react';
|
||||
import { type FormEvent, useState, Ref, useCallback } from 'react';
|
||||
import styled, { AnyStyledComponent, css } from 'styled-components';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
import type { NumberFormatValues, SourceInfo } from 'react-number-format';
|
||||
@@ -7,6 +7,8 @@ import { AlertType } from '@/constants/alerts';
|
||||
|
||||
import {
|
||||
ErrorType,
|
||||
type HumanReadablePlaceOrderPayload,
|
||||
type Nullable,
|
||||
TradeInputErrorAction,
|
||||
TradeInputField,
|
||||
ValidationError,
|
||||
@@ -19,6 +21,7 @@ import { InputErrorData, TradeBoxKeys, MobilePlaceOrderSteps } from '@/constants
|
||||
|
||||
import { breakpoints } from '@/styles';
|
||||
import { useStringGetter, useSubaccount } from '@/hooks';
|
||||
import { useOnLastOrderIndexed } from '@/hooks/useOnLastOrderIndexed';
|
||||
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { formMixins } from '@/styles/formMixins';
|
||||
@@ -34,7 +37,6 @@ import { WithTooltip } from '@/components/WithTooltip';
|
||||
|
||||
import { Orderbook } from '@/views/tables/Orderbook';
|
||||
|
||||
import { calculateHasUncommittedOrders } from '@/state/accountSelectors';
|
||||
import { getCurrentInput, useTradeFormData } from '@/state/inputsSelectors';
|
||||
import { getCurrentMarketConfig } from '@/state/perpetualsSelectors';
|
||||
|
||||
@@ -97,7 +99,6 @@ export const TradeForm = ({
|
||||
} = useTradeFormData();
|
||||
|
||||
const { limitPrice, triggerPrice, trailingPercent } = price || {};
|
||||
const hasUncommittedOrders = useSelector(calculateHasUncommittedOrders);
|
||||
const currentInput = useSelector(getCurrentInput);
|
||||
const { tickSizeDecimals, stepSizeDecimals } =
|
||||
useSelector(getCurrentMarketConfig, shallowEqual) || {};
|
||||
@@ -154,30 +155,33 @@ export const TradeForm = ({
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// order has been placed
|
||||
if (
|
||||
(!currentStep || currentStep === MobilePlaceOrderSteps.PlacingOrder) &&
|
||||
!hasUncommittedOrders
|
||||
) {
|
||||
const onLastOrderIndexed = useCallback(() => {
|
||||
if (!currentStep || currentStep === MobilePlaceOrderSteps.PlacingOrder) {
|
||||
setIsPlacingOrder(false);
|
||||
abacusStateManager.clearTradeInputValues({ shouldResetSize: true });
|
||||
setCurrentStep?.(MobilePlaceOrderSteps.Confirmation);
|
||||
}
|
||||
}, [currentStep, hasUncommittedOrders]);
|
||||
}, [currentStep]);
|
||||
|
||||
const { setUnIndexedClientId } = useOnLastOrderIndexed({
|
||||
callback: onLastOrderIndexed,
|
||||
});
|
||||
|
||||
const onPlaceOrder = async () => {
|
||||
setPlaceOrderError(undefined);
|
||||
setIsPlacingOrder(true);
|
||||
|
||||
await placeOrder({
|
||||
onError: (errorParams?: { errorStringKey?: string }) => {
|
||||
onError: (errorParams?: { errorStringKey?: Nullable<string> }) => {
|
||||
setPlaceOrderError(
|
||||
stringGetter({ key: errorParams?.errorStringKey || STRING_KEYS.SOMETHING_WENT_WRONG })
|
||||
);
|
||||
|
||||
setIsPlacingOrder(false);
|
||||
},
|
||||
onSuccess: (placeOrderPayload?: Nullable<HumanReadablePlaceOrderPayload>) => {
|
||||
setUnIndexedClientId(placeOrderPayload?.clientId);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -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 }),
|
||||
@@ -136,7 +148,7 @@ export const PlaceOrderButtonAndReceipt = ({
|
||||
|
||||
const buttonState = currentStep
|
||||
? buttonStatesPerStep[currentStep].buttonState
|
||||
: { isDisabled: !shouldEnableTrade, isLoading };
|
||||
: { isDisabled: !shouldEnableTrade || isLoading, isLoading };
|
||||
|
||||
return (
|
||||
<WithDetailsReceipt detailItems={items}>
|
||||
|
||||
@@ -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: (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import styled, { AnyStyledComponent } from 'styled-components';
|
||||
|
||||
import { AbacusOrderStatus, type OrderStatus } from '@/constants/abacus';
|
||||
@@ -29,8 +29,7 @@ export const OrderActionsCell = ({ orderId, status, isDisabled }: ElementProps)
|
||||
|
||||
const onCancel = useCallback(async () => {
|
||||
setIsCanceling(true);
|
||||
await cancelOrder({ orderId });
|
||||
setIsCanceling(false);
|
||||
await cancelOrder({ orderId, onError: () => setIsCanceling(false) });
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user