Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87731097b8 | ||
|
|
1e9209028e | ||
|
|
2861286bdb |
+7
-7
@@ -33,14 +33,14 @@
|
||||
"packageManager": "pnpm@8.6.6",
|
||||
"dependencies": {
|
||||
"@0xsquid/sdk": "^1.10.0",
|
||||
"@cosmjs/amino": "^0.32.1",
|
||||
"@cosmjs/crypto": "^0.32.1",
|
||||
"@cosmjs/encoding": "^0.32.1",
|
||||
"@cosmjs/proto-signing": "^0.32.1",
|
||||
"@cosmjs/stargate": "^0.32.1",
|
||||
"@cosmjs/tendermint-rpc": "^0.32.1",
|
||||
"@cosmjs/amino": "^0.31.0",
|
||||
"@cosmjs/crypto": "^0.31.0",
|
||||
"@cosmjs/encoding": "^0.31.0",
|
||||
"@cosmjs/proto-signing": "^0.31.0",
|
||||
"@cosmjs/stargate": "^0.31.0",
|
||||
"@cosmjs/tendermint-rpc": "^0.31.0",
|
||||
"@dydxprotocol/v4-abacus": "^1.2.5",
|
||||
"@dydxprotocol/v4-client-js": "^1.0.14",
|
||||
"@dydxprotocol/v4-client-js": "^1.0.11",
|
||||
"@dydxprotocol/v4-localization": "^1.1.11",
|
||||
"@ethersproject/providers": "^5.7.2",
|
||||
"@js-joda/core": "^5.5.3",
|
||||
|
||||
Generated
+53
-160
@@ -1,37 +1,33 @@
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
'@0xsquid/sdk':
|
||||
specifier: ^1.10.0
|
||||
version: 1.10.0
|
||||
'@cosmjs/amino':
|
||||
specifier: ^0.32.1
|
||||
version: 0.32.2
|
||||
specifier: ^0.31.0
|
||||
version: 0.31.0
|
||||
'@cosmjs/crypto':
|
||||
specifier: ^0.32.1
|
||||
version: 0.32.2
|
||||
specifier: ^0.31.0
|
||||
version: 0.31.0
|
||||
'@cosmjs/encoding':
|
||||
specifier: ^0.32.1
|
||||
version: 0.32.2
|
||||
specifier: ^0.31.0
|
||||
version: 0.31.0
|
||||
'@cosmjs/proto-signing':
|
||||
specifier: ^0.32.1
|
||||
version: 0.32.2
|
||||
specifier: ^0.31.0
|
||||
version: 0.31.0
|
||||
'@cosmjs/stargate':
|
||||
specifier: ^0.32.1
|
||||
version: 0.32.2
|
||||
specifier: ^0.31.0
|
||||
version: 0.31.0
|
||||
'@cosmjs/tendermint-rpc':
|
||||
specifier: ^0.32.1
|
||||
version: 0.32.2
|
||||
specifier: ^0.31.0
|
||||
version: 0.31.0
|
||||
'@dydxprotocol/v4-abacus':
|
||||
specifier: ^1.2.5
|
||||
version: 1.2.5
|
||||
'@dydxprotocol/v4-client-js':
|
||||
specifier: ^1.0.14
|
||||
version: 1.0.14
|
||||
specifier: ^1.0.11
|
||||
version: 1.0.11
|
||||
'@dydxprotocol/v4-localization':
|
||||
specifier: ^1.1.11
|
||||
version: 1.1.11
|
||||
@@ -688,15 +684,6 @@ packages:
|
||||
'@cosmjs/utils': 0.31.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/amino@0.32.2:
|
||||
resolution: {integrity: sha512-lcK5RCVm4OfdAooxKcF2+NwaDVVpghOq6o/A40c2mHXDUzUoRZ33VAHjVJ9Me6vOFxshrw/XEFn1f4KObntjYA==}
|
||||
dependencies:
|
||||
'@cosmjs/crypto': 0.32.2
|
||||
'@cosmjs/encoding': 0.32.2
|
||||
'@cosmjs/math': 0.32.2
|
||||
'@cosmjs/utils': 0.32.2
|
||||
dev: false
|
||||
|
||||
/@cosmjs/cosmwasm-stargate@0.30.1:
|
||||
resolution: {integrity: sha512-W/6SLUCJAJGBN+sJLXouLZikVgmqDd9LCdlMzQaxczcCHTWeJAmRvOiZGSZaSy3shw/JN1qc6g6PKpvTVgj10A==}
|
||||
dependencies:
|
||||
@@ -750,19 +737,7 @@ packages:
|
||||
'@cosmjs/encoding': 0.31.0
|
||||
'@cosmjs/math': 0.31.0
|
||||
'@cosmjs/utils': 0.31.0
|
||||
'@noble/hashes': 1.3.3
|
||||
bn.js: 5.2.1
|
||||
elliptic: 6.5.4
|
||||
libsodium-wrappers-sumo: 0.7.11
|
||||
dev: false
|
||||
|
||||
/@cosmjs/crypto@0.32.2:
|
||||
resolution: {integrity: sha512-RuxrYKzhrPF9g6NmU7VEq++Hn1vZJjqqJpZ9Tmw9lOYOV8BUsv+j/0BE86kmWi7xVJ7EwxiuxYsKuM8IR18CIA==}
|
||||
dependencies:
|
||||
'@cosmjs/encoding': 0.32.2
|
||||
'@cosmjs/math': 0.32.2
|
||||
'@cosmjs/utils': 0.32.2
|
||||
'@noble/hashes': 1.3.3
|
||||
'@noble/hashes': 1.3.1
|
||||
bn.js: 5.2.1
|
||||
elliptic: 6.5.4
|
||||
libsodium-wrappers-sumo: 0.7.11
|
||||
@@ -792,8 +767,8 @@ packages:
|
||||
readonly-date: 1.0.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/encoding@0.32.2:
|
||||
resolution: {integrity: sha512-WX7m1wLpA9V/zH0zRcz4EmgZdAv1F44g4dbXOgNj1eXZw1PIGR12p58OEkLN51Ha3S4DKRtCv5CkhK1KHEvQtg==}
|
||||
/@cosmjs/encoding@0.31.1:
|
||||
resolution: {integrity: sha512-IuxP6ewwX6vg9sUJ8ocJD92pkerI4lyG8J5ynAM3NaX3q+n+uMoPRSQXNeL9bnlrv01FF1kIm8if/f5F7ZPtkA==}
|
||||
dependencies:
|
||||
base64-js: 1.5.1
|
||||
bech32: 1.1.4
|
||||
@@ -814,13 +789,6 @@ packages:
|
||||
xstream: 11.14.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/json-rpc@0.32.2:
|
||||
resolution: {integrity: sha512-lan2lOgmz4yVE/HR8eCOSiII/1OudIulk8836koyIDCsPEpt6eKBuctnAD168vABGArKccLAo7Mr2gy9nrKrOQ==}
|
||||
dependencies:
|
||||
'@cosmjs/stream': 0.32.2
|
||||
xstream: 11.14.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/launchpad@0.27.1:
|
||||
resolution: {integrity: sha512-DcFwGD/z5PK8CzO2sojDxa+Be9EIEtRZb2YawgVnw2Ht/p5FlNv+OVo8qlishpBdalXEN7FvQ1dVeDFEe9TuJw==}
|
||||
dependencies:
|
||||
@@ -853,8 +821,8 @@ packages:
|
||||
bn.js: 5.2.1
|
||||
dev: false
|
||||
|
||||
/@cosmjs/math@0.32.2:
|
||||
resolution: {integrity: sha512-b8+ruAAY8aKtVKWSft2IvtCVCUH1LigIlf9ALIiY8n9jtM4kMASiaRbQ/27etnSAInV88IaezKK9rQZrtxTjcw==}
|
||||
/@cosmjs/math@0.31.1:
|
||||
resolution: {integrity: sha512-kiuHV6m6DSB8/4UV1qpFhlc4ul8SgLXTGRlYkYiIIP4l0YNeJ+OpPYaOlEgx4Unk2mW3/O2FWYj7Jc93+BWXng==}
|
||||
dependencies:
|
||||
bn.js: 5.2.1
|
||||
dev: false
|
||||
@@ -883,17 +851,6 @@ packages:
|
||||
long: 4.0.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/proto-signing@0.32.2:
|
||||
resolution: {integrity: sha512-UV4WwkE3W3G3s7wwU9rizNcUEz2g0W8jQZS5J6/3fiN0mRPwtPKQ6EinPN9ASqcAJ7/VQH4/9EPOw7d6XQGnqw==}
|
||||
dependencies:
|
||||
'@cosmjs/amino': 0.32.2
|
||||
'@cosmjs/crypto': 0.32.2
|
||||
'@cosmjs/encoding': 0.32.2
|
||||
'@cosmjs/math': 0.32.2
|
||||
'@cosmjs/utils': 0.32.2
|
||||
cosmjs-types: 0.9.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/socket@0.30.1:
|
||||
resolution: {integrity: sha512-r6MpDL+9N+qOS/D5VaxnPaMJ3flwQ36G+vPvYJsXArj93BjgyFB7BwWwXCQDzZ+23cfChPUfhbINOenr8N2Kow==}
|
||||
dependencies:
|
||||
@@ -918,18 +875,6 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@cosmjs/socket@0.32.2:
|
||||
resolution: {integrity: sha512-Qc8jaw4uSBJm09UwPgkqe3g9TBFx4ZR9HkXpwT6Z9I+6kbLerXPR0Gy3NSJFSUgxIfTpO8O1yqoWAyf0Ay17Mw==}
|
||||
dependencies:
|
||||
'@cosmjs/stream': 0.32.2
|
||||
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/stargate@0.30.1:
|
||||
resolution: {integrity: sha512-RdbYKZCGOH8gWebO7r6WvNnQMxHrNXInY/gPHPzMjbQF6UatA6fNM2G2tdgS5j5u7FTqlCI10stNXrknaNdzog==}
|
||||
dependencies:
|
||||
@@ -972,25 +917,6 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@cosmjs/stargate@0.32.2:
|
||||
resolution: {integrity: sha512-AsJa29fT7Jd4xt9Ai+HMqhyj7UQu7fyYKdXj/8+/9PD74xe6lZSYhQPcitUmMLJ1ckKPgXSk5Dd2LbsQT0IhZg==}
|
||||
dependencies:
|
||||
'@confio/ics23': 0.6.8
|
||||
'@cosmjs/amino': 0.32.2
|
||||
'@cosmjs/encoding': 0.32.2
|
||||
'@cosmjs/math': 0.32.2
|
||||
'@cosmjs/proto-signing': 0.32.2
|
||||
'@cosmjs/stream': 0.32.2
|
||||
'@cosmjs/tendermint-rpc': 0.32.2
|
||||
'@cosmjs/utils': 0.32.2
|
||||
cosmjs-types: 0.9.0
|
||||
xstream: 11.14.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- debug
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@cosmjs/stream@0.30.1:
|
||||
resolution: {integrity: sha512-Fg0pWz1zXQdoxQZpdHRMGvUH5RqS6tPv+j9Eh7Q953UjMlrwZVo0YFLC8OTf/HKVf10E4i0u6aM8D69Q6cNkgQ==}
|
||||
dependencies:
|
||||
@@ -1003,12 +929,6 @@ packages:
|
||||
xstream: 11.14.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/stream@0.32.2:
|
||||
resolution: {integrity: sha512-gpCufLfHAD8Zp1ZKge7AHbDf4RA0TZp66wZY6JaQR5bSiEF2Drjtp4mwXZPGejtaUMnaAgff3LrUzPJfKYdQwg==}
|
||||
dependencies:
|
||||
xstream: 11.14.0
|
||||
dev: false
|
||||
|
||||
/@cosmjs/tendermint-rpc@0.30.1:
|
||||
resolution: {integrity: sha512-Z3nCwhXSbPZJ++v85zHObeUggrEHVfm1u18ZRwXxFE9ZMl5mXTybnwYhczuYOl7KRskgwlB+rID0WYACxj4wdQ==}
|
||||
dependencies:
|
||||
@@ -1047,25 +967,6 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@cosmjs/tendermint-rpc@0.32.2:
|
||||
resolution: {integrity: sha512-DXyJHDmcAfCix4H/7/dKR0UMdshP01KxJOXHdHxBCbLIpck94BsWD3B2ZTXwfA6sv98so9wOzhp7qGQa5malxg==}
|
||||
dependencies:
|
||||
'@cosmjs/crypto': 0.32.2
|
||||
'@cosmjs/encoding': 0.32.2
|
||||
'@cosmjs/json-rpc': 0.32.2
|
||||
'@cosmjs/math': 0.32.2
|
||||
'@cosmjs/socket': 0.32.2
|
||||
'@cosmjs/stream': 0.32.2
|
||||
'@cosmjs/utils': 0.32.2
|
||||
axios: 1.6.5
|
||||
readonly-date: 1.0.0
|
||||
xstream: 11.14.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- debug
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@cosmjs/utils@0.27.1:
|
||||
resolution: {integrity: sha512-VG7QPDiMUzVPxRdJahDV8PXxVdnuAHiIuG56hldV4yPnOz/si/DLNd7VAUUA5923b6jS1Hhev0Hr6AhEkcxBMg==}
|
||||
dev: false
|
||||
@@ -1078,8 +979,8 @@ packages:
|
||||
resolution: {integrity: sha512-nNcycZWUYLNJlrIXgpcgVRqdl6BXjF4YlXdxobQWpW9Tikk61bEGeAFhDYtC0PwHlokCNw0KxWiHGJL4nL7Q5A==}
|
||||
dev: false
|
||||
|
||||
/@cosmjs/utils@0.32.2:
|
||||
resolution: {integrity: sha512-Gg5t+eR7vPJMAmhkFt6CZrzPd0EKpAslWwk5rFVYZpJsM8JG5KT9XQ99hgNM3Ov6ScNoIWbXkpX27F6A9cXR4Q==}
|
||||
/@cosmjs/utils@0.31.1:
|
||||
resolution: {integrity: sha512-n4Se1wu4GnKwztQHNFfJvUeWcpvx3o8cWhSbNs9JQShEuB3nv3R5lqFBtDCgHZF/emFQAP+ZjF8bTfCs9UBGhA==}
|
||||
dev: false
|
||||
|
||||
/@cush/relative@1.0.0:
|
||||
@@ -1090,29 +991,28 @@ packages:
|
||||
resolution: {integrity: sha512-pB3Fv1bzJRUDp29kAN61daZ34gTSGrSTNh+/AP3TUB63/Q/gaXQVBf91xVcso4Hw23xM3FwIcrRK0cvOSWgXKg==}
|
||||
dev: false
|
||||
|
||||
/@dydxprotocol/v4-client-js@1.0.14:
|
||||
resolution: {integrity: sha512-nIjj9OKuXb3n3rrihDPkBE6OIBxXNB7gf0NMsrG1Pc9O7M0yjpitTUgnfIzplf0XMrtmozWRYZhlLgBfJcIbBg==}
|
||||
/@dydxprotocol/v4-client-js@1.0.11:
|
||||
resolution: {integrity: sha512-rJNFGTO+HU1GQppXeRLKXNk4HWx/h+DjU2sUCieEv5mnRIMQpLw8dH/L+Uyhxx2oovccY1MaKB4Fr9IngdrF0A==}
|
||||
dependencies:
|
||||
'@cosmjs/amino': 0.32.2
|
||||
'@cosmjs/encoding': 0.32.2
|
||||
'@cosmjs/math': 0.32.2
|
||||
'@cosmjs/proto-signing': 0.32.2
|
||||
'@cosmjs/stargate': 0.32.2
|
||||
'@cosmjs/tendermint-rpc': 0.32.2
|
||||
'@cosmjs/utils': 0.32.2
|
||||
'@dydxprotocol/v4-proto': 3.0.0-dev.0
|
||||
'@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
|
||||
'@cosmjs/utils': 0.31.1
|
||||
'@dydxprotocol/v4-proto': 0.4.1
|
||||
'@osmonauts/lcd': 0.6.0
|
||||
'@scure/bip32': 1.3.2
|
||||
'@scure/bip39': 1.2.1
|
||||
axios: 1.1.3
|
||||
bech32: 1.1.4
|
||||
bignumber.js: 9.1.1
|
||||
cosmjs-types: 0.9.0
|
||||
ethereum-cryptography: 2.1.2
|
||||
ethers: 6.6.1
|
||||
long: 4.0.0
|
||||
protobufjs: 6.11.4
|
||||
ws: 8.15.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)
|
||||
ws: 8.15.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- debug
|
||||
@@ -1123,8 +1023,8 @@ packages:
|
||||
resolution: {integrity: sha512-ZHnyrWD1bEpvY1tctkcmSV6A5+hQSYBFwyjbiyOqepqDqrv24J5a3hlZU94lDyYf+7Sdk3alOvy9Z7Lpk59nvw==}
|
||||
dev: false
|
||||
|
||||
/@dydxprotocol/v4-proto@3.0.0-dev.0:
|
||||
resolution: {integrity: sha512-hT6F/AgaTqv8Bwo7twpIhmjXvJE/Fx+3mmHHTuIXMeL6OhVtlOpcEQyHvBEAdh1VrNq/S7qWvdQD0fvC/UgKyA==}
|
||||
/@dydxprotocol/v4-proto@0.4.1:
|
||||
resolution: {integrity: sha512-2pBkokufWcxfIpiXE6QuQOBXUe154OTp6ojCIdOPW9TFLxzchoygxXnb5dL6rAQVNj9Qbg+hhXBllutt4m99dw==}
|
||||
dependencies:
|
||||
protobufjs: 6.11.4
|
||||
dev: false
|
||||
@@ -7476,7 +7376,7 @@ packages:
|
||||
/axios@0.21.4:
|
||||
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.5
|
||||
follow-redirects: 1.15.2
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
@@ -7493,17 +7393,7 @@ packages:
|
||||
/axios@1.1.3:
|
||||
resolution: {integrity: sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.5
|
||||
form-data: 4.0.0
|
||||
proxy-from-env: 1.1.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
||||
/axios@1.6.5:
|
||||
resolution: {integrity: sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.5
|
||||
follow-redirects: 1.15.2
|
||||
form-data: 4.0.0
|
||||
proxy-from-env: 1.1.0
|
||||
transitivePeerDependencies:
|
||||
@@ -8167,10 +8057,6 @@ packages:
|
||||
protobufjs: 6.11.4
|
||||
dev: false
|
||||
|
||||
/cosmjs-types@0.9.0:
|
||||
resolution: {integrity: sha512-MN/yUe6mkJwHnCFfsNPeCfXVhyxHYW6c/xDUzrSbBycYzw++XvWDMJArXp2pLdgD6FQ8DW79vkPjeNKVrXaHeQ==}
|
||||
dev: false
|
||||
|
||||
/cosmos-directory-client@0.0.6:
|
||||
resolution: {integrity: sha512-WIdaQ8uW1vIbYvNnAVunkC6yxTrneJC7VQ5UUQ0kuw8b0C0A39KTIpoQHCfc8tV7o9vF4niwRhdXEdfAgQEsQQ==}
|
||||
dependencies:
|
||||
@@ -9536,16 +9422,6 @@ packages:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/follow-redirects@1.15.5:
|
||||
resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==}
|
||||
engines: {node: '>=4.0'}
|
||||
peerDependencies:
|
||||
debug: '*'
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/for-each@0.3.3:
|
||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||
dependencies:
|
||||
@@ -14801,6 +14677,19 @@ packages:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/ws@8.15.0:
|
||||
resolution: {integrity: sha512-H/Z3H55mrcrgjFwI+5jKavgXvwQLtfPCUEp6pi35VhoB0pfcHnSoyuTzkBEZpzq49g1193CUEwIvmsjcotenYw==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/ws@8.15.1(bufferutil@4.0.8)(utf-8-validate@5.0.10):
|
||||
resolution: {integrity: sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
@@ -14920,3 +14809,7 @@ packages:
|
||||
/zwitch@2.0.4:
|
||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||
dev: true
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"apps": {
|
||||
"ios": {
|
||||
"scheme": "dydx-t-v4"
|
||||
"scheme": "dydxv4"
|
||||
}
|
||||
},
|
||||
"deployments": {
|
||||
@@ -215,11 +215,10 @@
|
||||
}
|
||||
],
|
||||
"validators": [
|
||||
"https://validator.v4dev4.dydx.exchange"
|
||||
"http://validator.v4dev4.dydx.exchange"
|
||||
],
|
||||
"0xsquid": "https://testnet.api.0xsquid.com",
|
||||
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
|
||||
"faucet": "https://faucet.v4dev4.dydx.exchange"
|
||||
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
|
||||
},
|
||||
"links": {
|
||||
"tos": "https://dydx.exchange/v4-terms",
|
||||
@@ -474,7 +473,7 @@
|
||||
"apps": {
|
||||
"ios": {
|
||||
"minimalVersion": "1.0",
|
||||
"build": 40000,
|
||||
"build":40000,
|
||||
"url": "https://apps.apple.com/app/dydx/id1564787350"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
type CanvasProps = {
|
||||
className?: string;
|
||||
width: number | string;
|
||||
height: number | string;
|
||||
};
|
||||
|
||||
export const Canvas = forwardRef<HTMLCanvasElement, CanvasProps>(
|
||||
({ className, width, height }, canvasRef) => (
|
||||
<canvas ref={canvasRef} className={className} width={width} height={height} />
|
||||
)
|
||||
);
|
||||
@@ -11,5 +11,6 @@ export const DetachedScrollableSection = styled.section`
|
||||
|
||||
export const AttachedExpandingSection = styled.section`
|
||||
${layoutMixins.contentSectionAttached}
|
||||
${layoutMixins.expandingColumnWithHeader}
|
||||
gap: var(--border-width);
|
||||
`;
|
||||
|
||||
@@ -14,7 +14,7 @@ export const DiffArrowStory: Story<DiffArrowProps> = (args) => (
|
||||
|
||||
DiffArrowStory.argTypes = {
|
||||
direction: {
|
||||
options: ['left', 'right', 'up', 'down'],
|
||||
options: ['left', 'right'],
|
||||
control: { type: 'select' },
|
||||
defaultValue: 'right',
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ type ElementProps = {
|
||||
|
||||
type StyleProps = {
|
||||
className?: string;
|
||||
direction?: 'right' | 'left' | 'up' | 'down';
|
||||
direction?: 'right' | 'left';
|
||||
};
|
||||
|
||||
export type DiffArrowProps = ElementProps & StyleProps;
|
||||
@@ -57,11 +57,5 @@ Styled.DiffArrowContainer = styled.span<DiffArrowProps>`
|
||||
left: css`
|
||||
transform: scaleX(-1);
|
||||
`,
|
||||
up: css`
|
||||
transform: rotate(-90deg);
|
||||
`,
|
||||
down: css`
|
||||
transform: rotate(90deg);
|
||||
`
|
||||
}[direction || 'right'])}
|
||||
`;
|
||||
|
||||
@@ -44,7 +44,6 @@ import {
|
||||
MenuIcon,
|
||||
MigrateIcon,
|
||||
MintscanIcon,
|
||||
MoonIcon,
|
||||
OrderbookIcon,
|
||||
OrderCanceledIcon,
|
||||
OrderFilledIcon,
|
||||
@@ -67,7 +66,6 @@ import {
|
||||
ShowIcon,
|
||||
TogglesMenuIcon,
|
||||
StarIcon,
|
||||
SunIcon,
|
||||
TerminalIcon,
|
||||
TradeIcon,
|
||||
TransferIcon,
|
||||
@@ -121,7 +119,6 @@ export enum IconName {
|
||||
Menu = 'Menu',
|
||||
Migrate = 'Migrate',
|
||||
Mintscan = 'Mintscan',
|
||||
Moon = 'Moon',
|
||||
Onboarding = 'Onboarding',
|
||||
Orderbook = 'OrderbookIcon',
|
||||
OrderCanceled = 'OrderCanceled',
|
||||
@@ -144,7 +141,6 @@ export enum IconName {
|
||||
Share = 'Share',
|
||||
Show = 'Show',
|
||||
Star = 'Star',
|
||||
Sun = 'Sun',
|
||||
Terminal = 'Terminal',
|
||||
TogglesMenu = 'TogglesMenu',
|
||||
Trade = 'Trade',
|
||||
@@ -199,7 +195,6 @@ const icons = {
|
||||
[IconName.Menu]: MenuIcon,
|
||||
[IconName.Migrate]: MigrateIcon,
|
||||
[IconName.Mintscan]: MintscanIcon,
|
||||
[IconName.Moon]: MoonIcon,
|
||||
[IconName.Orderbook]: OrderbookIcon,
|
||||
[IconName.OrderCanceled]: OrderCanceledIcon,
|
||||
[IconName.OrderFilled]: OrderFilledIcon,
|
||||
@@ -221,7 +216,6 @@ const icons = {
|
||||
[IconName.Share]: ShareIcon,
|
||||
[IconName.Show]: ShowIcon,
|
||||
[IconName.Star]: StarIcon,
|
||||
[IconName.Sun]: SunIcon,
|
||||
[IconName.Terminal]: TerminalIcon,
|
||||
[IconName.TogglesMenu]: TogglesMenuIcon,
|
||||
[IconName.Trade]: TradeIcon,
|
||||
|
||||
@@ -7,7 +7,7 @@ import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { breakpoints } from '@/styles';
|
||||
|
||||
type PanelProps = {
|
||||
slotHeaderContent?: React.ReactNode;
|
||||
slotHeaderContent?: string;
|
||||
slotHeader?: React.ReactNode;
|
||||
slotRight?: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
|
||||
@@ -33,20 +33,17 @@ import {
|
||||
|
||||
import { useAsyncList } from 'react-stately';
|
||||
|
||||
import { useBreakpoints, useStringGetter } from '@/hooks';
|
||||
import { useBreakpoints } from '@/hooks';
|
||||
import { MediaQueryKeys } from '@/hooks/useBreakpoints';
|
||||
|
||||
import { Checkbox } from '@/components/Checkbox';
|
||||
|
||||
import { breakpoints } from '@/styles';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { CaretIcon } from '@/icons';
|
||||
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
|
||||
import { MustBigNumber } from '@/lib/numbers';
|
||||
|
||||
import { Icon, IconName } from './Icon';
|
||||
import { Tag } from './Tag';
|
||||
import { Button } from './Button';
|
||||
import { MustBigNumber } from '@/lib/numbers';
|
||||
|
||||
export { TableCell } from './Table/TableCell';
|
||||
export { TableColumnHeader } from './Table/TableColumnHeader';
|
||||
@@ -68,7 +65,7 @@ export type TableItem<TableRowData> = {
|
||||
onSelect?: (key: TableRowData) => void;
|
||||
};
|
||||
|
||||
type ColumnDef<TableRowData extends object> = {
|
||||
export type ColumnDef<TableRowData extends object> = {
|
||||
columnKey: string;
|
||||
label: React.ReactNode;
|
||||
tag?: React.ReactNode;
|
||||
@@ -83,7 +80,7 @@ type ColumnDef<TableRowData extends object> = {
|
||||
width?: ColumnSize;
|
||||
};
|
||||
|
||||
export type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey extends Key> = {
|
||||
type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey extends Key> = {
|
||||
label?: string;
|
||||
columns: ColumnDef<TableRowData>[];
|
||||
data: TableRowData[];
|
||||
@@ -95,7 +92,6 @@ export type ElementProps<TableRowData extends object | CustomRowConfig, TableRow
|
||||
selectionBehavior?: 'replace' | 'toggle';
|
||||
onRowAction?: (key: TableRowKey, row: TableRowData) => void;
|
||||
slotEmpty?: React.ReactNode;
|
||||
initialNumRowsToShow?: number;
|
||||
// collection: TableCollection<string>;
|
||||
// children: React.ReactNode;
|
||||
};
|
||||
@@ -125,7 +121,6 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
|
||||
selectionMode = 'single',
|
||||
selectionBehavior = 'toggle',
|
||||
slotEmpty,
|
||||
initialNumRowsToShow,
|
||||
// shouldRowRender,
|
||||
|
||||
// collection,
|
||||
@@ -141,8 +136,6 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
|
||||
style,
|
||||
}: ElementProps<TableRowData, TableRowKey> & StyleProps) => {
|
||||
const [selectedKeys, setSelectedKeys] = useState(new Set<TableRowKey>());
|
||||
const [numRowsToShow, setNumRowsToShow] = useState(initialNumRowsToShow);
|
||||
const enableViewMore = numRowsToShow !== undefined;
|
||||
|
||||
const currentBreakpoints = useBreakpoints();
|
||||
const shownColumns = columns.filter(
|
||||
@@ -216,12 +209,6 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
|
||||
onRowAction &&
|
||||
((key: TableRowKey) => onRowAction(key, data.find((row) => getRowKey(row) === key)!))
|
||||
}
|
||||
numColumns={shownColumns.length}
|
||||
onViewMoreClick={
|
||||
enableViewMore && numRowsToShow < data.length
|
||||
? () => setNumRowsToShow(data.length)
|
||||
: undefined
|
||||
}
|
||||
// shouldRowRender={shouldRowRender}
|
||||
hideHeader={hideHeader}
|
||||
withGradientCardRows={withGradientCardRows}
|
||||
@@ -246,7 +233,7 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
|
||||
)}
|
||||
</TableHeader>
|
||||
|
||||
<TableBody items={enableViewMore ? list.items.slice(0, numRowsToShow) : list.items}>
|
||||
<TableBody items={list.items}>
|
||||
{(item) => (
|
||||
<Row key={getRowKey(item)}>
|
||||
{(columnKey) => (
|
||||
@@ -280,8 +267,6 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
|
||||
onRowAction?: (key: TableRowKey) => void;
|
||||
// shouldRowRender?: (prevRowData: object, currentRowData: object) => boolean;
|
||||
children: CollectionChildren<TableRowData>;
|
||||
numColumns: number;
|
||||
onViewMoreClick?: () => void;
|
||||
|
||||
hideHeader?: boolean;
|
||||
withGradientCardRows?: boolean;
|
||||
@@ -291,7 +276,7 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
|
||||
withScrollSnapColumns?: boolean;
|
||||
withScrollSnapRows?: boolean;
|
||||
}) => {
|
||||
const { selectionMode, selectionBehavior, numColumns, onViewMoreClick } = props;
|
||||
const { selectionMode, selectionBehavior } = props;
|
||||
|
||||
const state = useTableState<TableRowData>({
|
||||
...props,
|
||||
@@ -352,7 +337,6 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
|
||||
<TableBodyRowGroup
|
||||
withGradientCardRows={props.withGradientCardRows}
|
||||
withInnerBorders={props.withInnerBorders}
|
||||
withOuterBorder={props.withOuterBorder}
|
||||
>
|
||||
{/* {Array.from(collection.getChildren!(collection.body.key), (row) => */}
|
||||
{[...collection.body.childNodes].map((row) =>
|
||||
@@ -398,9 +382,6 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
|
||||
</TableRow>
|
||||
)
|
||||
)}
|
||||
{onViewMoreClick ? (
|
||||
<ViewMoreRow colSpan={numColumns} onClick={onViewMoreClick} />
|
||||
) : undefined}
|
||||
</TableBodyRowGroup>
|
||||
</Styled.Table>
|
||||
);
|
||||
@@ -434,7 +415,6 @@ const TableBodyRowGroup = ({
|
||||
children,
|
||||
withGradientCardRows,
|
||||
withInnerBorders,
|
||||
withOuterBorder,
|
||||
}: { children: React.ReactNode } & StyleProps) => {
|
||||
const { rowGroupProps } = useTableRowGroup();
|
||||
|
||||
@@ -443,7 +423,6 @@ const TableBodyRowGroup = ({
|
||||
{...rowGroupProps}
|
||||
withGradientCardRows={withGradientCardRows}
|
||||
withInnerBorders={withInnerBorders}
|
||||
withOuterBorder={withOuterBorder}
|
||||
>
|
||||
{children}
|
||||
</Styled.Tbody>
|
||||
@@ -510,23 +489,6 @@ const TableColumnHeader = <TableRowData extends object>({
|
||||
);
|
||||
};
|
||||
|
||||
export const ViewMoreRow = ({ colSpan, onClick }: { colSpan: number; onClick: () => void }) => {
|
||||
const stringGetter = useStringGetter();
|
||||
return (
|
||||
<Styled.Tr key="viewmore">
|
||||
<Styled.Td
|
||||
colSpan={colSpan}
|
||||
onMouseDown={(e: MouseEvent) => e.preventDefault()}
|
||||
onPointerDown={(e: MouseEvent) => e.preventDefault()}
|
||||
>
|
||||
<Styled.ViewMoreButton slotRight={<CaretIcon />} onClick={onClick}>
|
||||
{stringGetter({ key: STRING_KEYS.VIEW_MORE })}
|
||||
</Styled.ViewMoreButton>
|
||||
</Styled.Td>
|
||||
</Styled.Tr>
|
||||
);
|
||||
};
|
||||
|
||||
export const TableRow = <TableRowData extends object>({
|
||||
item,
|
||||
children,
|
||||
@@ -698,7 +660,7 @@ Styled.Empty = styled.div<{ withOuterBorder: boolean }>`
|
||||
|
||||
justify-items: center;
|
||||
align-content: center;
|
||||
padding: 4rem;
|
||||
padding: 2rem;
|
||||
gap: 0.75em;
|
||||
|
||||
color: var(--color-text-0);
|
||||
@@ -906,18 +868,6 @@ Styled.Tbody = styled.tbody<StyleProps>`
|
||||
--stickyArea2-paddingLeft: var(--border-width);
|
||||
--stickyArea2-paddingRight: var(--border-width);
|
||||
|
||||
tr:first-of-type {
|
||||
box-shadow: 0 calc(var(--border-width)) 0 0 var(--border-color);
|
||||
}
|
||||
`}
|
||||
|
||||
${({ withOuterBorder }) =>
|
||||
withOuterBorder &&
|
||||
css`
|
||||
tr:last-of-type:not(:only-of-type) {
|
||||
box-shadow: 0 calc(-1 * var(--border-width)) 0 0 var(--border-color);
|
||||
}
|
||||
|
||||
tr:first-of-type {
|
||||
box-shadow: none;
|
||||
}
|
||||
@@ -972,15 +922,3 @@ Styled.Row = styled.div`
|
||||
${layoutMixins.inlineRow}
|
||||
padding: var(--tableCell-padding);
|
||||
`;
|
||||
|
||||
Styled.ViewMoreButton = styled(Button)`
|
||||
--button-backgroundColor: var(--color-layer-2);
|
||||
--button-textColor: var(--color-text-1);
|
||||
|
||||
width: 100%;
|
||||
|
||||
svg {
|
||||
width: 0.675rem;
|
||||
margin-left: 0.5ch;
|
||||
}
|
||||
`;
|
||||
|
||||
+1
-16
@@ -282,22 +282,13 @@ export const TRADE_TYPES: Record<
|
||||
[AbacusOrderType.takeProfitMarket.rawValue]: TradeTypes.TAKE_PROFIT_MARKET,
|
||||
|
||||
[AbacusOrderType.liquidated.name]: null,
|
||||
[AbacusOrderType.liquidated.rawValue]: null,
|
||||
[AbacusOrderType.liquidation.name]: null,
|
||||
|
||||
[AbacusOrderType.liquidation.name]: null,
|
||||
[AbacusOrderType.liquidation.rawValue]: null,
|
||||
|
||||
[AbacusOrderType.trailingStop.name]: null,
|
||||
[AbacusOrderType.trailingStop.rawValue]: null,
|
||||
|
||||
[AbacusOrderType.offsetting.name]: null,
|
||||
[AbacusOrderType.offsetting.rawValue]: null,
|
||||
|
||||
[AbacusOrderType.deleveraged.name]: null,
|
||||
[AbacusOrderType.deleveraged.rawValue]: null,
|
||||
|
||||
[AbacusOrderType.finalSettlement.name]: null,
|
||||
[AbacusOrderType.finalSettlement.rawValue]: null,
|
||||
};
|
||||
|
||||
// Custom types involving Abacus
|
||||
@@ -316,9 +307,3 @@ export type NetworkConfig = Partial<{
|
||||
}>;
|
||||
|
||||
export type ConnectNetworkEvent = CustomEvent<Partial<NetworkConfig>>;
|
||||
|
||||
export type PerpetualMarketOrderbookLevel = OrderbookLine & {
|
||||
side?: 'ask' | 'bid';
|
||||
mine: number;
|
||||
key: string;
|
||||
};
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* @description Orderbook display constants
|
||||
*/
|
||||
export const ORDERBOOK_MAX_ROWS_PER_SIDE = 30;
|
||||
export const ORDERBOOK_ANIMATION_DURATION = 400;
|
||||
|
||||
/**
|
||||
* @description Orderbook pixel constants
|
||||
* @note ORDERBOOK_ROW_HEIGHT should be a divisor of ORDERBOOK_HEIGHT so that we do not have a partial row at the bottom
|
||||
* @note To change the Orderbook width, --orderbook-trades-width and ORDERBOOK_WIDTH must be changed to the same value
|
||||
*/
|
||||
export const ORDERBOOK_HEIGHT = 800;
|
||||
export const ORDERBOOK_WIDTH = 300;
|
||||
export const ORDERBOOK_ROW_HEIGHT = 24;
|
||||
export const ORDERBOOK_ROW_PADDING_RIGHT = 8;
|
||||
@@ -1,4 +0,0 @@
|
||||
export * from './useCenterOrderbook';
|
||||
export * from './useSpreadRowScrollListener';
|
||||
export * from './useDrawOrderbook';
|
||||
export * from './useOrderbookValues';
|
||||
@@ -1,22 +0,0 @@
|
||||
import { useEffect, type RefObject } from 'react';
|
||||
|
||||
type Props = {
|
||||
marketId: string;
|
||||
orderbookRef: RefObject<HTMLDivElement>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Center Orderbook on load and market change
|
||||
* Assumed that the two sides are the same height
|
||||
*/
|
||||
export const useCenterOrderbook = ({ marketId, orderbookRef }: Props) => {
|
||||
const orderbookEl = orderbookRef.current;
|
||||
const { clientHeight, scrollHeight } = orderbookEl ?? {};
|
||||
const shouldScroll = scrollHeight && clientHeight && scrollHeight > clientHeight;
|
||||
|
||||
useEffect(() => {
|
||||
if (orderbookEl && shouldScroll) {
|
||||
orderbookEl.scrollTo({ top: (scrollHeight - clientHeight) / 2 });
|
||||
}
|
||||
}, [shouldScroll, marketId]);
|
||||
};
|
||||
@@ -1,373 +0,0 @@
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
|
||||
import type { PerpetualMarketOrderbookLevel } from '@/constants/abacus';
|
||||
import { SMALL_USD_DECIMALS, TOKEN_DECIMALS } from '@/constants/numbers';
|
||||
|
||||
import {
|
||||
ORDERBOOK_ANIMATION_DURATION,
|
||||
ORDERBOOK_HEIGHT,
|
||||
ORDERBOOK_ROW_HEIGHT,
|
||||
ORDERBOOK_ROW_PADDING_RIGHT,
|
||||
ORDERBOOK_WIDTH,
|
||||
} from '@/constants/orderbook';
|
||||
|
||||
import { getCurrentMarketConfig, getCurrentMarketOrderbookMap } from '@/state/perpetualsSelectors';
|
||||
import { getAppTheme } from '@/state/configsSelectors';
|
||||
|
||||
import { MustBigNumber } from '@/lib/numbers';
|
||||
|
||||
import {
|
||||
getHistogramXValues,
|
||||
getRektFromIdx,
|
||||
getXByColumn,
|
||||
getYForElements,
|
||||
} from '@/lib/orderbookHelpers';
|
||||
import { useAppThemeContext } from '../useAppTheme';
|
||||
|
||||
type ElementProps = {
|
||||
data: Array<PerpetualMarketOrderbookLevel | undefined>;
|
||||
histogramRange: number;
|
||||
side: PerpetualMarketOrderbookLevel['side'];
|
||||
};
|
||||
|
||||
type StyleProps = {
|
||||
histogramSide: 'left' | 'right';
|
||||
};
|
||||
|
||||
enum OrderbookRowAnimationType {
|
||||
REMOVE,
|
||||
NEW,
|
||||
NONE,
|
||||
}
|
||||
|
||||
export const useDrawOrderbook = ({
|
||||
data,
|
||||
histogramRange,
|
||||
histogramSide,
|
||||
side,
|
||||
}: ElementProps & StyleProps) => {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const canvas = canvasRef.current;
|
||||
const currentOrderbookMap = useSelector(getCurrentMarketOrderbookMap, shallowEqual);
|
||||
const { stepSizeDecimals = TOKEN_DECIMALS, tickSizeDecimals = SMALL_USD_DECIMALS } =
|
||||
useSelector(getCurrentMarketConfig, shallowEqual) || {};
|
||||
const prevData = useRef<typeof data>(data);
|
||||
const theme = useAppThemeContext();
|
||||
|
||||
/**
|
||||
* Scale canvas using device pixel ratio to unblur drawn text
|
||||
* @url https://stackoverflow.com/questions/15661339/how-do-i-fix-blurry-text-in-my-html5-canvas/65124939#65124939
|
||||
* @returns adjusted canvas width/height/rowHeight used in coordinates for drawing
|
||||
**/
|
||||
const { canvasWidth, canvasHeight, rowHeight } = useMemo(() => {
|
||||
const ratio = window.devicePixelRatio || 1;
|
||||
|
||||
if (!canvas) {
|
||||
return {
|
||||
canvasWidth: ORDERBOOK_WIDTH / devicePixelRatio,
|
||||
canvasHeight: ORDERBOOK_HEIGHT / devicePixelRatio,
|
||||
rowHeight: ORDERBOOK_ROW_HEIGHT / devicePixelRatio,
|
||||
};
|
||||
}
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = canvas.offsetWidth * ratio;
|
||||
canvas.height = canvas.offsetHeight * ratio;
|
||||
|
||||
if (ctx) {
|
||||
ctx.scale(ratio, ratio);
|
||||
ctx.font = '12px Satoshi';
|
||||
ctx.textAlign = 'right';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.imageSmoothingQuality = 'high';
|
||||
}
|
||||
|
||||
return {
|
||||
canvasWidth: canvas.width / ratio,
|
||||
canvasHeight: canvas.height / ratio,
|
||||
rowHeight: ORDERBOOK_ROW_HEIGHT,
|
||||
};
|
||||
}, [canvas]);
|
||||
|
||||
const drawBars = ({
|
||||
barType,
|
||||
ctx,
|
||||
depthOrSizeValue,
|
||||
gradientMultiplier,
|
||||
histogramAccentColor,
|
||||
histogramSide,
|
||||
idx,
|
||||
}: {
|
||||
barType: 'depth' | 'size';
|
||||
ctx: CanvasRenderingContext2D;
|
||||
depthOrSizeValue: number;
|
||||
gradientMultiplier: number;
|
||||
histogramAccentColor: string;
|
||||
histogramSide: 'left' | 'right';
|
||||
idx: number;
|
||||
}) => {
|
||||
const { x1, x2, y1, y2 } = getRektFromIdx({
|
||||
idx,
|
||||
rowHeight,
|
||||
canvasWidth,
|
||||
canvasHeight,
|
||||
side,
|
||||
});
|
||||
|
||||
// X values
|
||||
const maxHistogramBarWidth = x2 - x1 - (barType === 'size' ? 8 : 2);
|
||||
const barWidth = depthOrSizeValue
|
||||
? Math.min((depthOrSizeValue / histogramRange) * maxHistogramBarWidth, maxHistogramBarWidth)
|
||||
: 0;
|
||||
|
||||
const { gradient, bar } = getHistogramXValues({
|
||||
barWidth,
|
||||
canvasWidth,
|
||||
gradientMultiplier,
|
||||
histogramSide,
|
||||
});
|
||||
|
||||
// Gradient
|
||||
let linearGradient;
|
||||
|
||||
try {
|
||||
linearGradient = ctx.createLinearGradient(gradient.x1, y1, gradient.x2, y2);
|
||||
linearGradient.addColorStop(0, histogramAccentColor);
|
||||
linearGradient.addColorStop(1, 'rgba(0, 0, 0, 0)');
|
||||
ctx.fillStyle = linearGradient;
|
||||
} catch (err) {
|
||||
ctx.fillStyle = 'rgba(0, 0, 0, 0)';
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
// Bar
|
||||
const { bar: y } = getYForElements({ y: y1, rowHeight });
|
||||
|
||||
if (ctx.roundRect) {
|
||||
ctx.roundRect(
|
||||
bar.x1,
|
||||
y,
|
||||
bar.x2,
|
||||
rowHeight - 2,
|
||||
histogramSide === 'right' ? [2, 0, 0, 2] : [0, 2, 2, 0]
|
||||
);
|
||||
} else {
|
||||
ctx.rect(bar.x1, y, bar.x2, rowHeight - 2);
|
||||
}
|
||||
|
||||
ctx.fill();
|
||||
};
|
||||
|
||||
const drawText = ({
|
||||
animationType = OrderbookRowAnimationType.NONE,
|
||||
ctx,
|
||||
idx,
|
||||
mine,
|
||||
price,
|
||||
size,
|
||||
}: {
|
||||
animationType?: OrderbookRowAnimationType;
|
||||
ctx: CanvasRenderingContext2D;
|
||||
idx: number;
|
||||
mine?: number;
|
||||
price?: number;
|
||||
size?: number;
|
||||
}) => {
|
||||
const { y1 } = getRektFromIdx({
|
||||
idx,
|
||||
rowHeight,
|
||||
canvasWidth,
|
||||
canvasHeight,
|
||||
side,
|
||||
});
|
||||
|
||||
const { text: y } = getYForElements({ y: y1, rowHeight });
|
||||
|
||||
let textColor: string;
|
||||
let updatedTextColor: string | undefined;
|
||||
|
||||
switch (animationType) {
|
||||
case OrderbookRowAnimationType.REMOVE: {
|
||||
textColor = theme.textSecondary;
|
||||
break;
|
||||
}
|
||||
|
||||
case OrderbookRowAnimationType.NEW: {
|
||||
updatedTextColor = side === 'bid' ? theme.positive : theme.negative;
|
||||
textColor = theme.textPrimary;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
textColor = theme.textPrimary;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Size text
|
||||
if (size) {
|
||||
ctx.fillStyle = updatedTextColor ?? textColor;
|
||||
ctx.fillText(
|
||||
MustBigNumber(size).toFixed(stepSizeDecimals ?? TOKEN_DECIMALS),
|
||||
getXByColumn({ canvasWidth, colIdx: 0 }) - ORDERBOOK_ROW_PADDING_RIGHT,
|
||||
y
|
||||
);
|
||||
}
|
||||
|
||||
// Price text
|
||||
if (price) {
|
||||
ctx.fillStyle = textColor;
|
||||
ctx.fillText(
|
||||
MustBigNumber(price).toFixed(tickSizeDecimals ?? SMALL_USD_DECIMALS),
|
||||
getXByColumn({ canvasWidth, colIdx: 1 }) - ORDERBOOK_ROW_PADDING_RIGHT,
|
||||
y
|
||||
);
|
||||
}
|
||||
|
||||
// Mine text
|
||||
if (mine) {
|
||||
ctx.fillStyle = textColor;
|
||||
ctx.fillText(
|
||||
MustBigNumber(mine).toFixed(stepSizeDecimals ?? TOKEN_DECIMALS),
|
||||
getXByColumn({ canvasWidth, colIdx: 2 }) - ORDERBOOK_ROW_PADDING_RIGHT,
|
||||
y
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const drawOrderbookRow = ({
|
||||
ctx,
|
||||
idx,
|
||||
rowToRender,
|
||||
animationType = OrderbookRowAnimationType.NONE,
|
||||
}: {
|
||||
ctx: CanvasRenderingContext2D;
|
||||
idx: number;
|
||||
rowToRender?: PerpetualMarketOrderbookLevel;
|
||||
animationType?: OrderbookRowAnimationType;
|
||||
}) => {
|
||||
if (!rowToRender) return;
|
||||
const { depth, mine, price, size } = rowToRender;
|
||||
const histogramAccentColor = side === 'bid' ? theme.positiveFaded : theme.negativeFaded;
|
||||
|
||||
// Depth Bar
|
||||
if (depth) {
|
||||
drawBars({
|
||||
barType: 'depth',
|
||||
ctx,
|
||||
depthOrSizeValue: depth,
|
||||
gradientMultiplier: 1.3,
|
||||
histogramAccentColor,
|
||||
histogramSide,
|
||||
idx,
|
||||
});
|
||||
}
|
||||
|
||||
// Size Bar
|
||||
drawBars({
|
||||
barType: 'size',
|
||||
ctx,
|
||||
depthOrSizeValue: size,
|
||||
gradientMultiplier: 5,
|
||||
histogramAccentColor,
|
||||
histogramSide,
|
||||
idx,
|
||||
});
|
||||
|
||||
// Size, Price, Mine
|
||||
drawText({
|
||||
animationType,
|
||||
ctx,
|
||||
idx,
|
||||
mine,
|
||||
price,
|
||||
size,
|
||||
});
|
||||
};
|
||||
|
||||
// Update histograms and row contents on data change
|
||||
useEffect(() => {
|
||||
const ctx = canvas?.getContext('2d');
|
||||
|
||||
if (!canvas || !ctx) return;
|
||||
|
||||
// Clear canvas before redraw
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
|
||||
// Animate row removal and update
|
||||
const mapOfOrderbookPriceLevels =
|
||||
side && currentOrderbookMap?.[side === 'ask' ? 'asks' : 'bids'];
|
||||
const empty: number[] = [];
|
||||
const removed: number[] = [];
|
||||
const updated: number[] = [];
|
||||
|
||||
prevData.current.forEach((row, idx) => {
|
||||
if (!row) {
|
||||
empty.push(idx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mapOfOrderbookPriceLevels?.[row.price] === 0) {
|
||||
removed.push(idx);
|
||||
drawOrderbookRow({
|
||||
ctx,
|
||||
idx,
|
||||
rowToRender: row,
|
||||
animationType: OrderbookRowAnimationType.REMOVE,
|
||||
});
|
||||
} else if (mapOfOrderbookPriceLevels?.[row.price] === row?.size) {
|
||||
drawOrderbookRow({
|
||||
ctx,
|
||||
idx,
|
||||
rowToRender: data[idx],
|
||||
animationType: OrderbookRowAnimationType.NONE,
|
||||
});
|
||||
} else {
|
||||
updated.push(idx);
|
||||
drawOrderbookRow({
|
||||
ctx,
|
||||
idx,
|
||||
rowToRender: row,
|
||||
animationType: OrderbookRowAnimationType.NEW,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
[...empty, ...removed, ...updated].forEach((idx) => {
|
||||
const { x1, y1, x2, y2 } = getRektFromIdx({
|
||||
idx,
|
||||
rowHeight,
|
||||
canvasWidth,
|
||||
canvasHeight,
|
||||
side,
|
||||
});
|
||||
|
||||
ctx.clearRect(x1, y1, x2 - x1, y2 - y1);
|
||||
drawOrderbookRow({
|
||||
ctx,
|
||||
idx,
|
||||
rowToRender: data[idx],
|
||||
});
|
||||
});
|
||||
}, ORDERBOOK_ANIMATION_DURATION);
|
||||
|
||||
prevData.current = data;
|
||||
}, [
|
||||
canvasHeight,
|
||||
canvasWidth,
|
||||
rowHeight,
|
||||
data,
|
||||
histogramRange,
|
||||
stepSizeDecimals,
|
||||
tickSizeDecimals,
|
||||
histogramSide,
|
||||
side,
|
||||
theme,
|
||||
currentOrderbookMap,
|
||||
]);
|
||||
|
||||
return { canvasRef };
|
||||
};
|
||||
@@ -1,126 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||
|
||||
import { type PerpetualMarketOrderbookLevel } from '@/constants/abacus';
|
||||
import { DepthChartSeries, DepthChartDatum } from '@/constants/charts';
|
||||
|
||||
import { getCurrentMarketOrderbook } from '@/state/perpetualsSelectors';
|
||||
import { getSubaccountOpenOrdersBySideAndPrice } from '@/state/accountSelectors';
|
||||
|
||||
import { MustBigNumber } from '@/lib/numbers';
|
||||
|
||||
export const useCalculateOrderbookData = ({ maxRowsPerSide }: { maxRowsPerSide: number }) => {
|
||||
const orderbook = useSelector(getCurrentMarketOrderbook, shallowEqual);
|
||||
|
||||
const openOrdersBySideAndPrice =
|
||||
useSelector(getSubaccountOpenOrdersBySideAndPrice, shallowEqual) || {};
|
||||
|
||||
return useMemo(() => {
|
||||
const asks: Array<PerpetualMarketOrderbookLevel | undefined> = (
|
||||
orderbook?.asks?.toArray() ?? []
|
||||
)
|
||||
.map(
|
||||
(row, idx: number) =>
|
||||
({
|
||||
key: `ask-${idx}`,
|
||||
side: 'ask',
|
||||
mine: openOrdersBySideAndPrice[OrderSide.SELL]?.[row.price]?.size,
|
||||
...row,
|
||||
} as PerpetualMarketOrderbookLevel)
|
||||
)
|
||||
.slice(0, maxRowsPerSide);
|
||||
|
||||
const bids: Array<PerpetualMarketOrderbookLevel | undefined> = (
|
||||
orderbook?.bids?.toArray() ?? []
|
||||
)
|
||||
.map(
|
||||
(row, idx: number) =>
|
||||
({
|
||||
key: `bid-${idx}`,
|
||||
side: 'bid',
|
||||
mine: openOrdersBySideAndPrice[OrderSide.BUY]?.[row.price]?.size,
|
||||
...row,
|
||||
} as PerpetualMarketOrderbookLevel)
|
||||
)
|
||||
.slice(0, maxRowsPerSide);
|
||||
|
||||
// Prevent the bid/ask sides from crossing by using the offsets.
|
||||
// While the books are crossing...
|
||||
while (asks[0] && bids[0] && bids[0]!.price >= asks[0].price) {
|
||||
// Drop the order on the side with the lower offset.
|
||||
// The offset of the other side is higher and so supercedes.
|
||||
if (bids[0]!.offset === asks[0].offset) {
|
||||
// If offsets are the same, give precedence to the larger size. In this case,
|
||||
// one of the sizes *should* be zero, but we simply check for the larger size.
|
||||
if (bids[0]!.size > asks[0].size) {
|
||||
asks.shift();
|
||||
} else {
|
||||
bids.pop();
|
||||
}
|
||||
} else {
|
||||
// Offsets are not equal. Give precedence to the larger offset.
|
||||
if (bids[0]!.offset > asks[0].offset) {
|
||||
asks.shift();
|
||||
} else {
|
||||
bids.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const spread =
|
||||
asks[0]?.price && bids[0]?.price ? MustBigNumber(asks[0].price).minus(bids[0].price) : null;
|
||||
|
||||
const spreadPercent = orderbook?.spreadPercent;
|
||||
|
||||
const histogramRange = Math.max(
|
||||
isNaN(Number(bids[bids.length - 1]?.depth)) ? 0 : Number(bids[bids.length - 1]?.depth),
|
||||
isNaN(Number(asks[asks.length - 1]?.depth)) ? 0 : Number(asks[asks.length - 1]?.depth)
|
||||
);
|
||||
|
||||
return {
|
||||
asks,
|
||||
bids,
|
||||
spread,
|
||||
spreadPercent,
|
||||
histogramRange,
|
||||
hasOrderbook: !!orderbook,
|
||||
};
|
||||
}, [orderbook, openOrdersBySideAndPrice]);
|
||||
};
|
||||
|
||||
export const useOrderbookValuesForDepthChart = () => {
|
||||
const orderbook = useSelector(getCurrentMarketOrderbook, shallowEqual);
|
||||
|
||||
return useMemo(() => {
|
||||
const bids = (orderbook?.bids?.toArray() ?? [])
|
||||
.filter(Boolean)
|
||||
.map((datum) => ({ ...datum, seriesKey: DepthChartSeries.Bids } as DepthChartDatum));
|
||||
|
||||
const asks = (orderbook?.asks?.toArray() ?? [])
|
||||
.filter(Boolean)
|
||||
.map((datum) => ({ ...datum, seriesKey: DepthChartSeries.Asks } as DepthChartDatum));
|
||||
|
||||
const lowestBid = bids[bids.length - 1];
|
||||
const highestBid = bids[0];
|
||||
const lowestAsk = asks[0];
|
||||
const highestAsk = asks[asks.length - 1];
|
||||
|
||||
const midMarketPrice = orderbook?.midPrice;
|
||||
const spread = MustBigNumber(lowestAsk?.price ?? 0).minus(highestBid?.price ?? 0);
|
||||
const spreadPercent = orderbook?.spreadPercent;
|
||||
|
||||
return {
|
||||
bids,
|
||||
asks,
|
||||
lowestBid,
|
||||
highestBid,
|
||||
lowestAsk,
|
||||
highestAsk,
|
||||
midMarketPrice,
|
||||
spread,
|
||||
spreadPercent,
|
||||
orderbook,
|
||||
};
|
||||
}, [orderbook]);
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
import { type RefObject, useEffect, useState } from 'react';
|
||||
|
||||
export const useSpreadRowScrollListener = ({
|
||||
orderbookRef,
|
||||
spreadRowRef,
|
||||
}: {
|
||||
orderbookRef: RefObject<HTMLDivElement>;
|
||||
spreadRowRef: RefObject<HTMLDivElement>;
|
||||
}) => {
|
||||
const [displaySide, setDisplaySide] = useState<string>();
|
||||
|
||||
useEffect(() => {
|
||||
const onScroll = () => {
|
||||
if (spreadRowRef.current && orderbookRef.current) {
|
||||
const { clientHeight } = orderbookRef.current;
|
||||
const parent = orderbookRef.current.getBoundingClientRect();
|
||||
const spread = spreadRowRef.current.getBoundingClientRect();
|
||||
const spreadTop = spread.top - parent.top;
|
||||
const spreadBottom = spread.bottom - parent.top;
|
||||
|
||||
if (spreadBottom > clientHeight) {
|
||||
setDisplaySide('bottom');
|
||||
} else if (spreadTop < 0) {
|
||||
setDisplaySide('top');
|
||||
} else {
|
||||
setDisplaySide(undefined);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
orderbookRef.current?.addEventListener('scroll', onScroll, false);
|
||||
|
||||
return () => {
|
||||
orderbookRef.current?.removeEventListener('scroll', onScroll, false);
|
||||
};
|
||||
}, [orderbookRef.current, spreadRowRef.current]);
|
||||
|
||||
return displaySide;
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
import { useMemo } from 'react';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
|
||||
import { DepthChartSeries, DepthChartDatum } from '@/constants/charts';
|
||||
|
||||
import { getCurrentMarketOrderbook } from '@/state/perpetualsSelectors';
|
||||
|
||||
import { MustBigNumber } from '@/lib/numbers';
|
||||
|
||||
export const useOrderbookValuesForDepthChart = () => {
|
||||
const orderbook = useSelector(getCurrentMarketOrderbook, shallowEqual);
|
||||
|
||||
return useMemo(() => {
|
||||
const bids = (orderbook?.bids?.toArray() ?? [])
|
||||
.filter(Boolean)
|
||||
.map((datum) => ({ ...datum, seriesKey: DepthChartSeries.Bids } as DepthChartDatum));
|
||||
|
||||
const asks = (orderbook?.asks?.toArray() ?? [])
|
||||
.filter(Boolean)
|
||||
.map((datum) => ({ ...datum, seriesKey: DepthChartSeries.Asks } as DepthChartDatum));
|
||||
|
||||
const lowestBid = bids[bids.length - 1];
|
||||
const highestBid = bids[0];
|
||||
const lowestAsk = asks[0];
|
||||
const highestAsk = asks[asks.length - 1];
|
||||
|
||||
const midMarketPrice = orderbook?.midPrice;
|
||||
const spread = MustBigNumber(lowestAsk?.price ?? 0).minus(highestBid?.price ?? 0);
|
||||
const spreadPercent = orderbook?.spreadPercent;
|
||||
|
||||
return {
|
||||
bids,
|
||||
asks,
|
||||
lowestBid,
|
||||
highestBid,
|
||||
lowestAsk,
|
||||
highestAsk,
|
||||
midMarketPrice,
|
||||
spread,
|
||||
spreadPercent,
|
||||
orderbook,
|
||||
};
|
||||
}, [orderbook]);
|
||||
};
|
||||
@@ -198,13 +198,7 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
||||
);
|
||||
const ibcMsg: EncodeObject = {
|
||||
typeUrl: transaction.msgTypeUrl,
|
||||
value: {
|
||||
...transaction.msg,
|
||||
timeoutTimestamp: transaction.msg.timeoutTimestamp
|
||||
// Squid returns timeoutTimestamp as Long, but the signer expects BigInt
|
||||
? BigInt(Long.fromValue(transaction.msg.timeoutTimestamp).toString())
|
||||
: undefined,
|
||||
},
|
||||
value: transaction.msg,
|
||||
};
|
||||
|
||||
return await compositeClient.send(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useCallback, useEffect, useState, useMemo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { EvmDerivedAddresses } from '@/constants/account';
|
||||
import { LocalStorageKey } from '@/constants/localStorage';
|
||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||
|
||||
@@ -105,17 +104,11 @@ export const useWalletConnection = () => {
|
||||
[walletConnectConfig, walletType, walletConnectionType]
|
||||
);
|
||||
|
||||
const { connectAsync: connectWagmi } = useConnectWagmi({ connector: wagmiConnector });
|
||||
const { connectAsync: connectWagmi } = useConnectWagmi({ connector: wagmiConnector })
|
||||
const { suggestAndConnect: connectGraz } = useConnectGraz();
|
||||
const [evmDerivedAddresses] = useLocalStorage({
|
||||
key: LocalStorageKey.EvmDerivedAddresses,
|
||||
defaultValue: {} as EvmDerivedAddresses,
|
||||
});
|
||||
|
||||
const connectWallet = useCallback(
|
||||
async ({ walletType, forceConnect }: { walletType?: WalletType; forceConnect?: boolean }) => {
|
||||
if (!walletType) return { walletType, walletConnectionType };
|
||||
|
||||
async ({ walletType }: { walletType: WalletType }) => {
|
||||
const walletConnection = getWalletConnection({ walletType });
|
||||
|
||||
try {
|
||||
@@ -139,11 +132,7 @@ export const useWalletConnection = () => {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const isAccountConnected = Boolean(
|
||||
evmAddress && evmDerivedAddresses[evmAddress]?.encryptedSignature
|
||||
);
|
||||
// if account connected (via remember me), do not show wagmi popup until forceConnect
|
||||
if (!isConnectedWagmi && (forceConnect || !isAccountConnected)) {
|
||||
if (!isConnectedWagmi) {
|
||||
await connectWagmi({
|
||||
connector: resolveWagmiConnector({
|
||||
walletType,
|
||||
@@ -239,12 +228,6 @@ export const useWalletConnection = () => {
|
||||
evmAddressWagmi,
|
||||
signerWagmi,
|
||||
publicClientWagmi,
|
||||
isConnectedWagmi,
|
||||
connectWallet: () =>
|
||||
connectWallet({
|
||||
walletType: selectedWalletType,
|
||||
forceConnect: true,
|
||||
}),
|
||||
|
||||
// Wallet connection (Cosmos)
|
||||
dydxAddress,
|
||||
|
||||
@@ -39,7 +39,6 @@ export { default as MarketsIcon } from './markets.svg';
|
||||
export { default as MenuIcon } from './menu.svg';
|
||||
export { default as MigrateIcon } from './migrate.svg';
|
||||
export { default as MintscanIcon } from './logos/mintscan.svg';
|
||||
export { default as MoonIcon } from './moon.svg';
|
||||
export { default as OrderbookIcon } from './orderbook.svg';
|
||||
export { default as OverviewIcon } from './overview.svg';
|
||||
export { default as PencilIcon } from './pencil.svg';
|
||||
@@ -57,7 +56,6 @@ export { default as SendIcon } from './send.svg';
|
||||
export { default as ShareIcon } from './share.svg';
|
||||
export { default as ShowIcon } from './show.svg';
|
||||
export { default as StarIcon } from './star.svg';
|
||||
export { default as SunIcon } from './sun.svg';
|
||||
export { default as TerminalIcon } from './terminal.svg';
|
||||
export { default as TogglesMenuIcon } from './toggles-menu.svg';
|
||||
export { default as TradeIcon } from './trade.svg';
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 380 B |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 393 B |
+1
-2
@@ -8,7 +8,6 @@
|
||||
background-color: var(--color-layer-2);
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
--border: var(--default-border-width) solid var(--color-border);
|
||||
}
|
||||
|
||||
body,
|
||||
@@ -54,7 +53,7 @@ button:disabled {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
:focus-visible{
|
||||
outline: var(--color-accent) 1px solid;
|
||||
outline-offset: -1px;
|
||||
/* outline-offset: -2px; */
|
||||
|
||||
@@ -173,10 +173,6 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
return parsedObj as T;
|
||||
}
|
||||
|
||||
if (typeof x === 'bigint') {
|
||||
return x.toString() as T;
|
||||
}
|
||||
|
||||
throw new Error(`Unsupported data type: ${typeof x}`);
|
||||
}
|
||||
|
||||
@@ -367,13 +363,7 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
try {
|
||||
const ibcMsg = {
|
||||
typeUrl: params.msgTypeUrl, // '/ibc.applications.transfer.v1.MsgTransfer',
|
||||
value: {
|
||||
...params.msg,
|
||||
timeoutTimestamp: params.msg.timeoutTimestamp
|
||||
// Squid returns timeoutTimestamp as Long, but the signer expects BigInt
|
||||
? BigInt(Long.fromValue(params.msg.timeoutTimestamp).toString())
|
||||
: undefined,
|
||||
},
|
||||
value: params.msg,
|
||||
};
|
||||
const fee = await this.nobleClient.simulateTransaction([ibcMsg]);
|
||||
|
||||
@@ -423,13 +413,7 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
);
|
||||
const ibcMsg: EncodeObject = {
|
||||
typeUrl: parsedIbcPayload.msgTypeUrl,
|
||||
value: {
|
||||
...parsedIbcPayload.msg,
|
||||
timeoutTimestamp: parsedIbcPayload.msg.timeoutTimestamp
|
||||
// Squid returns timeoutTimestamp as Long, but the signer expects BigInt
|
||||
? BigInt(Long.fromValue(parsedIbcPayload.msg.timeoutTimestamp).toString())
|
||||
: undefined,
|
||||
},
|
||||
value: parsedIbcPayload.msg,
|
||||
};
|
||||
|
||||
const tx = await this.compositeClient.send(
|
||||
|
||||
+5
-10
@@ -171,15 +171,6 @@ class AbacusStateManager {
|
||||
this.setTransferValue({ value: null, field: TransferInputField.usdcSize });
|
||||
};
|
||||
|
||||
resetInputState = () => {
|
||||
this.clearTransferInputValues();
|
||||
this.setTransferValue({
|
||||
field: TransferInputField.type,
|
||||
value: null,
|
||||
});
|
||||
this.clearTradeInputValues();
|
||||
};
|
||||
|
||||
// ------ Set Data ------ //
|
||||
setStore = (store: RootStore) => {
|
||||
this.store = store;
|
||||
@@ -271,7 +262,11 @@ class AbacusStateManager {
|
||||
) => this.stateManager.cancelOrder(orderId, callback);
|
||||
|
||||
cctpWithdraw = (
|
||||
callback: (success: boolean, parsingError: Nullable<ParsingError>, data: string) => void
|
||||
callback: (
|
||||
success: boolean,
|
||||
parsingError: Nullable<ParsingError>,
|
||||
data: string,
|
||||
) => void
|
||||
): void => this.stateManager.commitCCTPWithdraw(callback);
|
||||
|
||||
// ------ Utils ------ //
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
// ------ Canvas helper methods ------ //
|
||||
|
||||
import type { MarketOrderbook, Nullable, PerpetualMarketOrderbookLevel } from '@/constants/abacus';
|
||||
|
||||
/**
|
||||
* @returns top left x,y and bottom x,y from array idx
|
||||
*/
|
||||
export const getRektFromIdx = ({
|
||||
idx,
|
||||
canvasWidth,
|
||||
canvasHeight,
|
||||
rowHeight,
|
||||
side = 'bid',
|
||||
}: {
|
||||
idx: number;
|
||||
canvasWidth: number;
|
||||
canvasHeight: number;
|
||||
rowHeight: number;
|
||||
side: PerpetualMarketOrderbookLevel['side'];
|
||||
}) => {
|
||||
/**
|
||||
* Does not change
|
||||
*/
|
||||
const x1 = 0;
|
||||
const x2 = Math.floor(canvasWidth);
|
||||
|
||||
/**
|
||||
* Changes based on side
|
||||
* Asks: The drawing should starts from the bottom of the orderbook
|
||||
*/
|
||||
if (side === 'ask') {
|
||||
const y1 = Math.floor(canvasHeight - (idx + 1) * rowHeight);
|
||||
const y2 = Math.floor(y1 + rowHeight);
|
||||
return { x1, x2, y1, y2 };
|
||||
}
|
||||
|
||||
const y1 = Math.floor(idx * rowHeight);
|
||||
const y2 = Math.floor(y1 + rowHeight);
|
||||
return { x1, x2, y1, y2 };
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns y value for text and bar
|
||||
*/
|
||||
export const getYForElements = ({ y, rowHeight }: { y: number; rowHeight: number }) => ({
|
||||
text: Math.floor(y + rowHeight / 2),
|
||||
bar: Math.floor(y + 1),
|
||||
});
|
||||
|
||||
/**
|
||||
* @description X coordinate for text
|
||||
* @returns Get X value by column, colIdx starts at 0
|
||||
*/
|
||||
export const getXByColumn = ({ canvasWidth, colIdx }: { canvasWidth: number; colIdx: number }) => {
|
||||
return Math.floor(((colIdx + 1) * canvasWidth) / 3);
|
||||
};
|
||||
|
||||
/**
|
||||
* to === 'right' to === 'left'
|
||||
* |===================| |===================|
|
||||
* bar: a b c d
|
||||
* a = 0
|
||||
* b = depthBarWidth
|
||||
* c = canvasWidth - depthBarWidth
|
||||
* d = canvasWidth
|
||||
*
|
||||
*/
|
||||
export const getHistogramXValues = ({
|
||||
barWidth,
|
||||
canvasWidth,
|
||||
gradientMultiplier,
|
||||
histogramSide,
|
||||
}: {
|
||||
barWidth: number;
|
||||
canvasWidth: number;
|
||||
gradientMultiplier: number;
|
||||
histogramSide: 'left' | 'right';
|
||||
}) => {
|
||||
const gradient = {
|
||||
x1: Math.floor(histogramSide === 'left' ? barWidth : canvasWidth - barWidth),
|
||||
x2: Math.floor(
|
||||
histogramSide === 'left'
|
||||
? 0 - (canvasWidth * gradientMultiplier - canvasWidth)
|
||||
: canvasWidth * gradientMultiplier
|
||||
),
|
||||
};
|
||||
const bar = {
|
||||
x1: Math.floor(histogramSide === 'left' ? 0 : canvasWidth - barWidth),
|
||||
x2: Math.floor(histogramSide === 'left' ? Math.min(barWidth, canvasWidth) : canvasWidth),
|
||||
};
|
||||
|
||||
return {
|
||||
bar,
|
||||
gradient,
|
||||
};
|
||||
};
|
||||
|
||||
// ------ Orderbook helper methods ------ //
|
||||
export const processOrderbookToCreateMap = ({
|
||||
orderbookMap,
|
||||
newOrderbook,
|
||||
}: {
|
||||
orderbookMap?: {
|
||||
asks: Record<string, number>;
|
||||
bids: Record<string, number>;
|
||||
};
|
||||
newOrderbook: Nullable<MarketOrderbook>;
|
||||
}) => {
|
||||
// Create Orderbooks Map indexed by Price
|
||||
const asks = newOrderbook?.asks?.toArray() ?? [];
|
||||
const bids = newOrderbook?.bids?.toArray() ?? [];
|
||||
const prevAsks = orderbookMap?.asks ?? {};
|
||||
const prevBids = orderbookMap?.bids ?? {};
|
||||
const newAsks = Object.fromEntries(asks.map((ask) => [ask.price, ask.size]) ?? {});
|
||||
const newBids = Object.fromEntries(bids.map((bid) => [bid.price, bid.size]) ?? {});
|
||||
|
||||
Object.keys(prevAsks).forEach((price) => {
|
||||
if (!newAsks[price] || newAsks[price] === 0) {
|
||||
newAsks[price] = 0;
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(prevBids).forEach((price) => {
|
||||
if (!newBids[price] || newBids[price] === 0) {
|
||||
newBids[price] = 0;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
newAsks,
|
||||
newBids,
|
||||
};
|
||||
};
|
||||
@@ -5,7 +5,7 @@ import { useEnsName } from 'wagmi';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { ButtonSize } from '@/constants/buttons';
|
||||
import { TransferType } from '@/constants/abacus';
|
||||
import { TransferInputField, TransferType } from '@/constants/abacus';
|
||||
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
@@ -26,13 +26,12 @@ import { useAccounts, useStringGetter, useTokenConfigs } from '@/hooks';
|
||||
import { getOnboardingState } from '@/state/accountSelectors';
|
||||
import { openDialog } from '@/state/dialogs';
|
||||
|
||||
import abacusStateManager from '@/lib/abacus';
|
||||
import { isTruthy } from '@/lib/isTruthy';
|
||||
import { truncateAddress } from '@/lib/wallet';
|
||||
|
||||
import { DYDXBalancePanel } from './rewards/DYDXBalancePanel';
|
||||
import { MigratePanel } from './rewards/MigratePanel';
|
||||
import { GovernancePanel } from './rewards/GovernancePanel';
|
||||
import { StakingPanel } from './rewards/StakingPanel';
|
||||
|
||||
const ENS_CHAIN_ID = 1; // Ethereum
|
||||
|
||||
@@ -179,7 +178,7 @@ const Profile = () => {
|
||||
onClick={() => dispatch(openDialog({ type: DialogTypes.Help }))}
|
||||
/>
|
||||
</Styled.EqualGrid>
|
||||
|
||||
|
||||
<MigratePanel />
|
||||
<DYDXBalancePanel />
|
||||
|
||||
@@ -231,9 +230,6 @@ const Profile = () => {
|
||||
withInnerBorders={false}
|
||||
/>
|
||||
</Styled.TablePanel>
|
||||
|
||||
<GovernancePanel />
|
||||
<StakingPanel />
|
||||
</Styled.MobileProfileLayout>
|
||||
);
|
||||
};
|
||||
@@ -247,7 +243,6 @@ Styled.MobileProfileLayout = styled.div`
|
||||
|
||||
gap: 1rem;
|
||||
padding: 1.25rem 0.9rem;
|
||||
max-width: 100vw;
|
||||
`;
|
||||
|
||||
Styled.Header = styled.header`
|
||||
@@ -342,7 +337,7 @@ Styled.Details = styled(Details)`
|
||||
|
||||
Styled.RewardsPanel = styled(Panel)`
|
||||
align-self: flex-start;
|
||||
|
||||
|
||||
&,
|
||||
> * {
|
||||
height: 100%;
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
import styled, { AnyStyledComponent } from 'styled-components';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { ButtonAction, ButtonSize } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
|
||||
import { useStringGetter, useURLConfigs } from '@/hooks';
|
||||
|
||||
import { Panel } from '@/components/Panel';
|
||||
import { IconName } from '@/components/Icon';
|
||||
import { IconButton } from '@/components/IconButton';
|
||||
import { Link } from '@/components/Link';
|
||||
|
||||
import { openDialog } from '@/state/dialogs';
|
||||
|
||||
export const GovernancePanel = () => {
|
||||
const stringGetter = useStringGetter();
|
||||
const dispatch = useDispatch();
|
||||
const { governanceLearnMore } = useURLConfigs();
|
||||
|
||||
return (
|
||||
<Panel
|
||||
slotHeaderContent={
|
||||
<Styled.Title>{stringGetter({ key: STRING_KEYS.GOVERNANCE })}</Styled.Title>
|
||||
}
|
||||
slotRight={
|
||||
<Styled.Arrow>
|
||||
<Styled.IconButton
|
||||
action={ButtonAction.Base}
|
||||
iconName={IconName.Arrow}
|
||||
size={ButtonSize.Small}
|
||||
/>
|
||||
</Styled.Arrow>
|
||||
}
|
||||
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
|
||||
>
|
||||
<Styled.Description>
|
||||
{stringGetter({ key: STRING_KEYS.GOVERNANCE_DESCRIPTION })}
|
||||
<Link href={governanceLearnMore} onClick={(e) => e.stopPropagation()}>
|
||||
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} →
|
||||
</Link>
|
||||
</Styled.Description>
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.Description = styled.div`
|
||||
color: var(--color-text-0);
|
||||
--link-color: var(--color-text-1);
|
||||
|
||||
a {
|
||||
display: inline;
|
||||
::before {
|
||||
content: ' ';
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
Styled.IconButton = styled(IconButton)`
|
||||
color: var(--color-text-0);
|
||||
--color-border: var(--color-layer-6);
|
||||
`;
|
||||
|
||||
Styled.Arrow = styled.div`
|
||||
padding-right: 1.5rem;
|
||||
`;
|
||||
|
||||
Styled.Title = styled.h3`
|
||||
font: var(--font-medium-book);
|
||||
color: var(--color-text-2);
|
||||
margin-bottom: -1rem;
|
||||
`;
|
||||
@@ -146,15 +146,14 @@ Styled.Title = styled.h3`
|
||||
color: var(--color-text-2);
|
||||
|
||||
padding: var(--panel-paddingY) var(--panel-paddingX) 0;
|
||||
margin-bottom: -0.5rem;
|
||||
`;
|
||||
|
||||
Styled.MigrateAction = styled.div`
|
||||
${layoutMixins.flexEqualColumns}
|
||||
align-items: center;
|
||||
margin: 1rem;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
margin: 1rem;
|
||||
width: 100%;
|
||||
|
||||
background-color: var(--color-layer-2);
|
||||
@@ -234,4 +233,4 @@ Styled.InlineRow = styled.div`
|
||||
${layoutMixins.inlineRow}
|
||||
color: var(--color-text-0);
|
||||
--link-color: var(--color-text-1);
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -3,29 +3,45 @@ import { useDispatch } from 'react-redux';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { ButtonAction, ButtonSize } from '@/constants/buttons';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { AppRoute } from '@/constants/routes';
|
||||
|
||||
import { useBreakpoints, useStringGetter } from '@/hooks';
|
||||
import { useBreakpoints, useStringGetter, useURLConfigs } from '@/hooks';
|
||||
|
||||
import { breakpoints } from '@/styles';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
import { BackButton } from '@/components/BackButton';
|
||||
import { Panel } from '@/components/Panel';
|
||||
import { IconName } from '@/components/Icon';
|
||||
import { IconButton } from '@/components/IconButton';
|
||||
import { Link } from '@/components/Link';
|
||||
|
||||
import { openDialog } from '@/state/dialogs';
|
||||
|
||||
import { DYDXBalancePanel } from './DYDXBalancePanel';
|
||||
import { MigratePanel } from './MigratePanel';
|
||||
import { LaunchIncentivesPanel } from './LaunchIncentivesPanel';
|
||||
import { RewardsHelpPanel } from './RewardsHelpPanel';
|
||||
import { GovernancePanel } from './GovernancePanel';
|
||||
import { StakingPanel } from './StakingPanel';
|
||||
|
||||
const RewardsPage = () => {
|
||||
const dispatch = useDispatch();
|
||||
const stringGetter = useStringGetter();
|
||||
const { governanceLearnMore, stakingLearnMore } = useURLConfigs();
|
||||
const { isTablet, isNotTablet } = useBreakpoints();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const panelArrow = (
|
||||
<Styled.Arrow>
|
||||
<Styled.IconButton
|
||||
action={ButtonAction.Base}
|
||||
iconName={IconName.Arrow}
|
||||
size={ButtonSize.Small}
|
||||
/>
|
||||
</Styled.Arrow>
|
||||
);
|
||||
|
||||
return (
|
||||
<Styled.Page>
|
||||
{isTablet && (
|
||||
@@ -45,12 +61,37 @@ const RewardsPage = () => {
|
||||
</Styled.PanelRowIncentivesAndBalance>
|
||||
)}
|
||||
|
||||
{isNotTablet && (
|
||||
<Styled.PanelRow>
|
||||
<GovernancePanel />
|
||||
<StakingPanel />
|
||||
</Styled.PanelRow>
|
||||
)}
|
||||
<Styled.PanelRow>
|
||||
<Styled.Panel
|
||||
slotHeaderContent={
|
||||
<Styled.Title>{stringGetter({ key: STRING_KEYS.GOVERNANCE })}</Styled.Title>
|
||||
}
|
||||
slotRight={panelArrow}
|
||||
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
|
||||
>
|
||||
<Styled.Description>
|
||||
{stringGetter({ key: STRING_KEYS.GOVERNANCE_DESCRIPTION })}
|
||||
<Link href={governanceLearnMore} onClick={(e) => e.stopPropagation()}>
|
||||
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} →
|
||||
</Link>
|
||||
</Styled.Description>
|
||||
</Styled.Panel>
|
||||
|
||||
<Styled.Panel
|
||||
slotHeaderContent={
|
||||
<Styled.Title>{stringGetter({ key: STRING_KEYS.STAKING })}</Styled.Title>
|
||||
}
|
||||
slotRight={panelArrow}
|
||||
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
|
||||
>
|
||||
<Styled.Description>
|
||||
{stringGetter({ key: STRING_KEYS.STAKING_DESCRIPTION })}
|
||||
<Link href={stakingLearnMore} onClick={(e) => e.stopPropagation()}>
|
||||
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} →
|
||||
</Link>
|
||||
</Styled.Description>
|
||||
</Styled.Panel>
|
||||
</Styled.PanelRow>
|
||||
|
||||
<RewardsHelpPanel />
|
||||
</Styled.Page>
|
||||
@@ -99,6 +140,24 @@ Styled.Panel = styled(Panel)`
|
||||
height: fit-content;
|
||||
`;
|
||||
|
||||
Styled.Title = styled.h3`
|
||||
font: var(--font-medium-book);
|
||||
color: var(--color-text-2);
|
||||
margin-bottom: -1rem;
|
||||
`;
|
||||
|
||||
Styled.Description = styled.div`
|
||||
color: var(--color-text-0);
|
||||
--link-color: var(--color-text-1);
|
||||
|
||||
a {
|
||||
display: inline;
|
||||
::before {
|
||||
content: ' ';
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
Styled.PanelRow = styled.div`
|
||||
${layoutMixins.gridEqualColumns}
|
||||
gap: 1.5rem;
|
||||
@@ -112,3 +171,12 @@ Styled.PanelRow = styled.div`
|
||||
Styled.PanelRowIncentivesAndBalance = styled(Styled.PanelRow)`
|
||||
grid-template-columns: 2fr 1fr;
|
||||
`;
|
||||
|
||||
Styled.IconButton = styled(IconButton)`
|
||||
color: var(--color-text-0);
|
||||
--color-border: var(--color-layer-6);
|
||||
`;
|
||||
|
||||
Styled.Arrow = styled.div`
|
||||
padding: 1rem;
|
||||
`;
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
import styled, { AnyStyledComponent } from 'styled-components';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { ButtonAction, ButtonSize } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
|
||||
import { useStringGetter, useURLConfigs } from '@/hooks';
|
||||
|
||||
import { Panel } from '@/components/Panel';
|
||||
import { IconName } from '@/components/Icon';
|
||||
import { IconButton } from '@/components/IconButton';
|
||||
import { Link } from '@/components/Link';
|
||||
|
||||
import { openDialog } from '@/state/dialogs';
|
||||
|
||||
export const StakingPanel = () => {
|
||||
const stringGetter = useStringGetter();
|
||||
const dispatch = useDispatch();
|
||||
const { stakingLearnMore } = useURLConfigs();
|
||||
|
||||
return (
|
||||
<Panel
|
||||
slotHeaderContent={<Styled.Title>{stringGetter({ key: STRING_KEYS.STAKING })}</Styled.Title>}
|
||||
slotRight={
|
||||
<Styled.Arrow>
|
||||
<Styled.IconButton
|
||||
action={ButtonAction.Base}
|
||||
iconName={IconName.Arrow}
|
||||
size={ButtonSize.Small}
|
||||
/>
|
||||
</Styled.Arrow>
|
||||
}
|
||||
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
|
||||
>
|
||||
<Styled.Description>
|
||||
{stringGetter({ key: STRING_KEYS.STAKING_DESCRIPTION })}
|
||||
<Link href={stakingLearnMore} onClick={(e) => e.stopPropagation()}>
|
||||
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} →
|
||||
</Link>
|
||||
</Styled.Description>
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.Description = styled.div`
|
||||
color: var(--color-text-0);
|
||||
--link-color: var(--color-text-1);
|
||||
|
||||
a {
|
||||
display: inline;
|
||||
::before {
|
||||
content: ' ';
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
Styled.IconButton = styled(IconButton)`
|
||||
color: var(--color-text-0);
|
||||
--color-border: var(--color-layer-6);
|
||||
`;
|
||||
|
||||
Styled.Arrow = styled.div`
|
||||
padding-right: 1.5rem;
|
||||
`;
|
||||
|
||||
Styled.Title = styled.h3`
|
||||
font: var(--font-medium-book);
|
||||
color: var(--color-text-2);
|
||||
margin-bottom: -1rem;
|
||||
`;
|
||||
@@ -1,4 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import styled, { AnyStyledComponent } from 'styled-components';
|
||||
|
||||
import { TradeLayouts } from '@/constants/layout';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
@@ -7,9 +9,11 @@ import { useStringGetter } from '@/hooks';
|
||||
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
|
||||
import { CanvasOrderbook } from '@/views/CanvasOrderbook';
|
||||
import { Orderbook, orderbookMixins, OrderbookScrollBehavior } from '@/views/tables/Orderbook';
|
||||
import { LiveTrades } from '@/views/tables/LiveTrades';
|
||||
|
||||
import { getCurrentMarketId } from '@/state/perpetualsSelectors';
|
||||
|
||||
enum Tab {
|
||||
Orderbook = 'Orderbook',
|
||||
Trades = 'Trades',
|
||||
@@ -23,22 +27,29 @@ const HISTOGRAM_SIDES_BY_LAYOUT = {
|
||||
|
||||
export const VerticalPanel = ({ tradeLayout }: { tradeLayout: TradeLayouts }) => {
|
||||
const stringGetter = useStringGetter();
|
||||
|
||||
const [value, setValue] = useState(Tab.Orderbook);
|
||||
const [scrollBehavior, setScrollBehavior] = useState<OrderbookScrollBehavior>('snapToCenter');
|
||||
|
||||
const marketId = useSelector(getCurrentMarketId);
|
||||
|
||||
useEffect(() => {
|
||||
setScrollBehavior('snapToCenter');
|
||||
}, [marketId]);
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
<Styled.Tabs
|
||||
fullWidthTabs
|
||||
value={value}
|
||||
onValueChange={(value: Tab) => {
|
||||
setScrollBehavior('snapToCenter');
|
||||
setValue(value);
|
||||
}}
|
||||
items={[
|
||||
{
|
||||
asChild: true,
|
||||
content: <CanvasOrderbook histogramSide={HISTOGRAM_SIDES_BY_LAYOUT[tradeLayout]} />,
|
||||
content: <Orderbook histogramSide={HISTOGRAM_SIDES_BY_LAYOUT[tradeLayout]} />,
|
||||
label: stringGetter({ key: STRING_KEYS.ORDERBOOK_SHORT }),
|
||||
value: Tab.Orderbook,
|
||||
forceMount: true,
|
||||
},
|
||||
{
|
||||
content: <LiveTrades histogramSide={HISTOGRAM_SIDES_BY_LAYOUT[tradeLayout]} />,
|
||||
@@ -46,7 +57,26 @@ export const VerticalPanel = ({ tradeLayout }: { tradeLayout: TradeLayouts }) =>
|
||||
value: Tab.Trades,
|
||||
},
|
||||
]}
|
||||
onWheel={() => setScrollBehavior('free')}
|
||||
withTransitions={false}
|
||||
isShowingOrderbook={value === Tab.Orderbook}
|
||||
scrollBehavior={scrollBehavior}
|
||||
// style={{
|
||||
// scrollSnapType: {
|
||||
// 'snapToCenter': 'y mandatory',
|
||||
// 'free': 'none',
|
||||
// 'snapToCenterUnlessHovered': 'none',
|
||||
// }[scrollBehavior],
|
||||
// }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.Tabs = styled(Tabs)<{
|
||||
isShowingOrderbook: boolean;
|
||||
scrollBehavior: OrderbookScrollBehavior;
|
||||
}>`
|
||||
${orderbookMixins.scrollArea}
|
||||
`;
|
||||
|
||||
+5
-26
@@ -14,7 +14,6 @@ import { LocalStorageKey } from '@/constants/localStorage';
|
||||
import { DEFAULT_MARKETID } from '@/constants/markets';
|
||||
|
||||
import { getLocalStorage } from '@/lib/localStorage';
|
||||
import { processOrderbookToCreateMap } from '@/lib/orderbookHelpers';
|
||||
|
||||
interface CandleDataByMarket {
|
||||
data: Record<string, Candle[]>;
|
||||
@@ -27,13 +26,6 @@ export interface PerpetualsState {
|
||||
liveTrades?: Record<string, MarketTrade[]>;
|
||||
markets?: Record<string, PerpetualMarket>;
|
||||
orderbooks?: Record<string, MarketOrderbook>;
|
||||
orderbooksMap?: Record<
|
||||
string,
|
||||
{
|
||||
asks: Record<string, number>;
|
||||
bids: Record<string, number>;
|
||||
}
|
||||
>;
|
||||
historicalFundings: Record<string, MarketHistoricalFunding[]>;
|
||||
}
|
||||
|
||||
@@ -43,7 +35,6 @@ const initialState: PerpetualsState = {
|
||||
liveTrades: {},
|
||||
markets: undefined,
|
||||
orderbooks: undefined,
|
||||
orderbooksMap: undefined,
|
||||
historicalFundings: {},
|
||||
};
|
||||
|
||||
@@ -105,24 +96,12 @@ export const perpetualsSlice = createSlice({
|
||||
setOrderbook: (
|
||||
state: PerpetualsState,
|
||||
action: PayloadAction<{ orderbook?: Nullable<MarketOrderbook>; marketId: string }>
|
||||
) => {
|
||||
state.orderbooks = merge({}, state.orderbooks, {
|
||||
) => ({
|
||||
...state,
|
||||
orderbooks: merge({}, state.orderbooks, {
|
||||
[action.payload.marketId]: action.payload.orderbook,
|
||||
});
|
||||
|
||||
const { newAsks, newBids } = processOrderbookToCreateMap({
|
||||
orderbookMap: state.orderbooksMap?.[action.payload.marketId],
|
||||
newOrderbook: action.payload.orderbook,
|
||||
});
|
||||
|
||||
state.orderbooksMap = {
|
||||
...(state.orderbooksMap ?? {}),
|
||||
[action.payload.marketId]: {
|
||||
asks: newAsks,
|
||||
bids: newBids,
|
||||
},
|
||||
};
|
||||
},
|
||||
}),
|
||||
}),
|
||||
setTvChartResolution: (
|
||||
state: PerpetualsState,
|
||||
action: PayloadAction<{ marketId: string; resolution: string }>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { mapCandle } from '@/lib/tradingView/utils';
|
||||
import type { RootState } from './_store';
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns marketId of the market the user is currently viewing
|
||||
*/
|
||||
export const getCurrentMarketId = (state: RootState) => state.perpetuals.currentMarketId;
|
||||
@@ -20,6 +21,7 @@ export const getCurrentMarketAssetId = (state: RootState) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns Record of PerpetualMarket indexed by MarketId
|
||||
*/
|
||||
export const getPerpetualMarkets = (state: RootState) => state.perpetuals.markets;
|
||||
@@ -32,11 +34,13 @@ export const getMarketData = (marketId: string) => (state: RootState) =>
|
||||
getPerpetualMarkets(state)?.[marketId];
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns marketIds of all markets
|
||||
*/
|
||||
export const getMarketIds = (state: RootState) => Object.keys(getPerpetualMarkets(state) ?? []);
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns PerpetualMarket data of the market the user is currently viewing
|
||||
*/
|
||||
export const getCurrentMarketData = (state: RootState) => {
|
||||
@@ -45,6 +49,7 @@ export const getCurrentMarketData = (state: RootState) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns MarketConfig data of the market the user is currently viewing
|
||||
*/
|
||||
export const getCurrentMarketConfig = (state: RootState) => getCurrentMarketData(state)?.configs;
|
||||
@@ -57,11 +62,13 @@ export const getMarketConfig = (marketId: string) => (state: RootState) =>
|
||||
getMarketData(marketId)(state)?.configs;
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns Record of list of MarketTrades indexed by marketId
|
||||
*/
|
||||
export const getLiveTrades = (state: RootState) => state.perpetuals.liveTrades;
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns List of MarketTrades of the market the user is currently viewing
|
||||
*/
|
||||
export const getCurrentMarketLiveTrades = (state: RootState) => {
|
||||
@@ -71,11 +78,13 @@ export const getCurrentMarketLiveTrades = (state: RootState) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns Record of subscribed or previously subscribed Orderbook data, indexed by marketId.
|
||||
*/
|
||||
export const getOrderbooks = (state: RootState) => state.perpetuals.orderbooks;
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns Orderbook data for the market the user is currently viewing
|
||||
*/
|
||||
export const getCurrentMarketOrderbook = (state: RootState) => {
|
||||
@@ -85,20 +94,13 @@ export const getCurrentMarketOrderbook = (state: RootState) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns Orderbook data as a Map of price and size for the current market
|
||||
*/
|
||||
export const getCurrentMarketOrderbookMap = (state: RootState) => {
|
||||
const orderbookMap = state.perpetuals.orderbooksMap;
|
||||
const currentMarketId = getCurrentMarketId(state);
|
||||
return orderbookMap?.[currentMarketId || ''];
|
||||
};
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns Record of historical funding indexed by marketId.
|
||||
*/
|
||||
export const getHistoricalFundings = (state: RootState) => state.perpetuals.historicalFundings;
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns Historical funding data for the market the user is currently viewing
|
||||
*/
|
||||
export const getCurrentMarketHistoricalFundings = createSelector(
|
||||
@@ -108,6 +110,7 @@ export const getCurrentMarketHistoricalFundings = createSelector(
|
||||
);
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns Mid market price for the market the user is currently viewing
|
||||
*/
|
||||
export const getCurrentMarketMidMarketPrice = (state: RootState) => {
|
||||
@@ -147,6 +150,7 @@ export const getSelectedResolutionForMarket = (marketId: string) => (state: Root
|
||||
state.perpetuals.candles?.[marketId]?.selectedResolution;
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @returns Current market's next funding rate
|
||||
*/
|
||||
export const getCurrentMarketNextFundingRate = createSelector(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AppTheme } from '@/state/configs';
|
||||
import type { ThemeColors } from '@/constants/styles/colors';
|
||||
import { ThemeColors } from '@/constants/styles/colors';
|
||||
import { ColorToken, OpacityToken } from '@/constants/styles/base';
|
||||
import { generateFadedColorVariant } from '@/lib/styles';
|
||||
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
import { forwardRef } from 'react';
|
||||
import styled, { AnyStyledComponent, css } from 'styled-components';
|
||||
|
||||
import type { Nullable } from '@/constants/abacus';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { TOKEN_DECIMALS } from '@/constants/numbers';
|
||||
import { ORDERBOOK_ROW_HEIGHT } from '@/constants/orderbook';
|
||||
import { useStringGetter } from '@/hooks';
|
||||
|
||||
import { Output, OutputType } from '@/components/Output';
|
||||
import { WithTooltip } from '@/components/WithTooltip';
|
||||
|
||||
type StyleProps = {
|
||||
side?: 'top' | 'bottom';
|
||||
};
|
||||
|
||||
type ElementProps = {
|
||||
spread?: Nullable<number>;
|
||||
spreadPercent?: Nullable<number>;
|
||||
tickSizeDecimals?: Nullable<number>;
|
||||
};
|
||||
|
||||
export const OrderbookRow = styled.div`
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
height: ${ORDERBOOK_ROW_HEIGHT}px;
|
||||
min-height: ${ORDERBOOK_ROW_HEIGHT}px;
|
||||
position: relative;
|
||||
padding-right: 0.5rem;
|
||||
font: var(--font-mini-book);
|
||||
|
||||
> span {
|
||||
flex: 1 1 0%;
|
||||
text-align: right;
|
||||
}
|
||||
`;
|
||||
|
||||
export const SpreadRow = forwardRef<HTMLDivElement, StyleProps & ElementProps>(
|
||||
({ side, spread, spreadPercent, tickSizeDecimals = TOKEN_DECIMALS }, ref) => {
|
||||
const stringGetter = useStringGetter();
|
||||
|
||||
return (
|
||||
<Styled.SpreadRow ref={ref} side={side}>
|
||||
<span>
|
||||
<WithTooltip tooltip="spread">
|
||||
{stringGetter({ key: STRING_KEYS.ORDERBOOK_SPREAD })}
|
||||
</WithTooltip>
|
||||
</span>
|
||||
<span>
|
||||
<Output type={OutputType.Number} value={spread} fractionDigits={tickSizeDecimals} />
|
||||
</span>
|
||||
<span>
|
||||
<Output type={OutputType.Percent} value={spreadPercent} />
|
||||
</span>
|
||||
</Styled.SpreadRow>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.SpreadRow = styled(OrderbookRow)<{ side?: 'top' | 'bottom' }>`
|
||||
height: 2rem;
|
||||
border-top: var(--border);
|
||||
border-bottom: var(--border);
|
||||
span {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
${({ side }) =>
|
||||
side &&
|
||||
{
|
||||
top: css`
|
||||
border-top: none;
|
||||
`,
|
||||
bottom: css`
|
||||
border-bottom: none;
|
||||
`,
|
||||
}[side]}
|
||||
`;
|
||||
@@ -1,284 +0,0 @@
|
||||
import { forwardRef, useCallback, useMemo, useRef } from 'react';
|
||||
import styled, { AnyStyledComponent, css } from 'styled-components';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { Nullable, type PerpetualMarketOrderbookLevel } from '@/constants/abacus';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { ORDERBOOK_HEIGHT, ORDERBOOK_MAX_ROWS_PER_SIDE } from '@/constants/orderbook';
|
||||
import { useStringGetter } from '@/hooks';
|
||||
|
||||
import {
|
||||
useCalculateOrderbookData,
|
||||
useCenterOrderbook,
|
||||
useDrawOrderbook,
|
||||
useSpreadRowScrollListener,
|
||||
} from '@/hooks/Orderbook';
|
||||
|
||||
import { Canvas } from '@/components/Canvas';
|
||||
import { LoadingSpace } from '@/components/Loading/LoadingSpinner';
|
||||
import { Tag } from '@/components/Tag';
|
||||
|
||||
import { getCurrentMarketAssetData } from '@/state/assetsSelectors';
|
||||
import { getCurrentMarketConfig, getCurrentMarketId } from '@/state/perpetualsSelectors';
|
||||
import { setTradeFormInputs } from '@/state/inputs';
|
||||
import { getCurrentInput } from '@/state/inputsSelectors';
|
||||
|
||||
import { OrderbookRow, SpreadRow } from './OrderbookRow';
|
||||
|
||||
type ElementProps = {
|
||||
maxRowsPerSide?: number;
|
||||
layout?: 'vertical' | 'horizontal';
|
||||
};
|
||||
|
||||
type StyleProps = {
|
||||
hideHeader?: boolean;
|
||||
histogramSide?: 'left' | 'right';
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export const CanvasOrderbook = forwardRef(
|
||||
(
|
||||
{
|
||||
histogramSide = 'right',
|
||||
maxRowsPerSide = ORDERBOOK_MAX_ROWS_PER_SIDE,
|
||||
}: ElementProps & StyleProps,
|
||||
ref
|
||||
) => {
|
||||
const { asks, bids, hasOrderbook, histogramRange, spread, spreadPercent } =
|
||||
useCalculateOrderbookData({
|
||||
maxRowsPerSide,
|
||||
});
|
||||
|
||||
const stringGetter = useStringGetter();
|
||||
const currentMarket = useSelector(getCurrentMarketId) ?? '';
|
||||
const currentMarketConfig = useSelector(getCurrentMarketConfig, shallowEqual);
|
||||
const { id = '' } = useSelector(getCurrentMarketAssetData, shallowEqual) ?? {};
|
||||
|
||||
const { tickSizeDecimals = 2 } = currentMarketConfig ?? {};
|
||||
|
||||
/**
|
||||
* Slice asks and bids to maxRowsPerSide using empty rows
|
||||
*/
|
||||
const { asksSlice, bidsSlice } = useMemo(() => {
|
||||
let asksSlice: Array<PerpetualMarketOrderbookLevel | undefined> = [];
|
||||
const emptyAskRows =
|
||||
asks.length < maxRowsPerSide
|
||||
? new Array<undefined>(maxRowsPerSide - asks.length).fill(undefined)
|
||||
: [];
|
||||
asksSlice = [...emptyAskRows, ...asks.reverse()];
|
||||
|
||||
let bidsSlice: Array<PerpetualMarketOrderbookLevel | undefined> = [];
|
||||
const emptyBidRows =
|
||||
bids.length < maxRowsPerSide
|
||||
? new Array<undefined>(maxRowsPerSide - bids.length).fill(undefined)
|
||||
: [];
|
||||
bidsSlice = [...bids, ...emptyBidRows];
|
||||
|
||||
return {
|
||||
asksSlice,
|
||||
bidsSlice,
|
||||
};
|
||||
}, [asks, bids]);
|
||||
|
||||
const orderbookRef = useRef<HTMLDivElement>(null);
|
||||
useCenterOrderbook({ orderbookRef, marketId: currentMarket });
|
||||
|
||||
/**
|
||||
* Display top or bottom spreadRow when center spreadRow is off screen
|
||||
*/
|
||||
const spreadRowRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const displaySide = useSpreadRowScrollListener({
|
||||
orderbookRef,
|
||||
spreadRowRef,
|
||||
});
|
||||
|
||||
/**
|
||||
* Row action
|
||||
*/
|
||||
const currentInput = useSelector(getCurrentInput);
|
||||
const dispatch = useDispatch();
|
||||
const onRowAction = useCallback(
|
||||
(price: Nullable<number>) => {
|
||||
if (currentInput === 'trade' && price) {
|
||||
dispatch(setTradeFormInputs({ limitPriceInput: price?.toString() }));
|
||||
}
|
||||
},
|
||||
[currentInput]
|
||||
);
|
||||
|
||||
const { canvasRef: asksCanvasRef } = useDrawOrderbook({
|
||||
data: [...asksSlice].reverse(),
|
||||
histogramRange,
|
||||
histogramSide,
|
||||
side: 'ask',
|
||||
});
|
||||
|
||||
const { canvasRef: bidsCanvasRef } = useDrawOrderbook({
|
||||
data: bidsSlice,
|
||||
histogramRange,
|
||||
histogramSide,
|
||||
side: 'bid',
|
||||
});
|
||||
|
||||
return (
|
||||
<Styled.OrderbookContainer ref={ref}>
|
||||
<Styled.OrderbookContent $isLoading={!hasOrderbook}>
|
||||
<Styled.Header>
|
||||
<span>
|
||||
{stringGetter({ key: STRING_KEYS.SIZE })} {id && <Tag>{id}</Tag>}
|
||||
</span>
|
||||
<span>
|
||||
{stringGetter({ key: STRING_KEYS.PRICE })} <Tag>USD</Tag>
|
||||
</span>
|
||||
<span>{stringGetter({ key: STRING_KEYS.MINE })}</span>
|
||||
</Styled.Header>
|
||||
|
||||
{displaySide === 'top' && (
|
||||
<Styled.SpreadRow
|
||||
side="top"
|
||||
spread={spread}
|
||||
spreadPercent={spreadPercent}
|
||||
tickSizeDecimals={tickSizeDecimals}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Styled.OrderbookWrapper ref={orderbookRef}>
|
||||
<Styled.OrderbookSideContainer $side="asks">
|
||||
<Styled.HoverRows $bottom>
|
||||
{asksSlice.map((row: PerpetualMarketOrderbookLevel | undefined, idx) =>
|
||||
row ? (
|
||||
<Styled.Row
|
||||
key={idx}
|
||||
title={`${row.price}`}
|
||||
onClick={() => {
|
||||
onRowAction(row.price);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Styled.Row key={idx} />
|
||||
)
|
||||
)}
|
||||
</Styled.HoverRows>
|
||||
<Styled.OrderbookCanvas ref={asksCanvasRef} width="100%" height="100%" />
|
||||
</Styled.OrderbookSideContainer>
|
||||
|
||||
<SpreadRow
|
||||
ref={spreadRowRef}
|
||||
spread={spread?.toNumber()}
|
||||
spreadPercent={spreadPercent}
|
||||
tickSizeDecimals={tickSizeDecimals}
|
||||
/>
|
||||
|
||||
<Styled.OrderbookSideContainer $side="bids">
|
||||
<Styled.HoverRows>
|
||||
{bidsSlice.map((row: PerpetualMarketOrderbookLevel | undefined, idx) =>
|
||||
row ? (
|
||||
<Styled.Row
|
||||
key={idx}
|
||||
title={`${row.price}`}
|
||||
onClick={
|
||||
row?.price
|
||||
? () => {
|
||||
onRowAction(row.price);
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Styled.Row key={idx} />
|
||||
)
|
||||
)}
|
||||
</Styled.HoverRows>
|
||||
<Styled.OrderbookCanvas ref={bidsCanvasRef} width="100%" height="100%" />
|
||||
</Styled.OrderbookSideContainer>
|
||||
</Styled.OrderbookWrapper>
|
||||
{displaySide === 'bottom' && (
|
||||
<Styled.SpreadRow
|
||||
side="bottom"
|
||||
spread={spread}
|
||||
spreadPercent={spreadPercent}
|
||||
tickSizeDecimals={tickSizeDecimals}
|
||||
/>
|
||||
)}
|
||||
</Styled.OrderbookContent>
|
||||
{!hasOrderbook && <LoadingSpace id="canvas-orderbook" />}
|
||||
</Styled.OrderbookContainer>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.OrderbookContainer = styled.div`
|
||||
display: flex;
|
||||
flex: 1 1 0%;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
Styled.OrderbookContent = styled.div<{ $isLoading?: boolean }>`
|
||||
max-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
${({ $isLoading }) => $isLoading && 'flex: 1;'}
|
||||
`;
|
||||
|
||||
Styled.Header = styled(OrderbookRow)`
|
||||
height: 2rem;
|
||||
border-bottom: var(--border);
|
||||
color: var(--color-text-0);
|
||||
`;
|
||||
|
||||
Styled.OrderbookWrapper = styled.div`
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 0%;
|
||||
`;
|
||||
|
||||
Styled.OrderbookSideContainer = styled.div<{ $side: 'bids' | 'asks' }>`
|
||||
min-height: ${ORDERBOOK_HEIGHT}px;
|
||||
${({ $side }) => css`
|
||||
--accent-color: ${$side === 'bids' ? 'var(--color-positive)' : 'var(--color-negative)'};
|
||||
`}
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
Styled.OrderbookCanvas = styled(Canvas)`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
font-feature-settings: var(--fontFeature-monoNumbers);
|
||||
`;
|
||||
|
||||
Styled.HoverRows = styled.div<{ $bottom?: boolean }>`
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
|
||||
${({ $bottom }) => $bottom && 'bottom: 0;'}
|
||||
`;
|
||||
|
||||
Styled.Row = styled(OrderbookRow)<{ onClick?: () => void }>`
|
||||
${({ onClick }) =>
|
||||
onClick
|
||||
? css`
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-layer-4);
|
||||
filter: darkness(0.1);
|
||||
}
|
||||
`
|
||||
: css`
|
||||
cursor: default;
|
||||
`}
|
||||
`;
|
||||
|
||||
Styled.SpreadRow = styled(SpreadRow)`
|
||||
position: absolute;
|
||||
`;
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
|
||||
import { useStringGetter } from '@/hooks';
|
||||
import { useOrderbookValuesForDepthChart } from '@/hooks/Orderbook/useOrderbookValues';
|
||||
import { useOrderbookValuesForDepthChart } from '@/hooks/useOrderbookValues';
|
||||
|
||||
import { TooltipContent } from '@/components/visx/TooltipContent';
|
||||
import { Details } from '@/components/Details';
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import { StringGetterFunction } from '@/constants/localization';
|
||||
|
||||
import { useBreakpoints } from '@/hooks';
|
||||
import { useOrderbookValuesForDepthChart } from '@/hooks/Orderbook/useOrderbookValues';
|
||||
import { useOrderbookValuesForDepthChart } from '@/hooks/useOrderbookValues';
|
||||
|
||||
import { getCurrentMarketConfig } from '@/state/perpetualsSelectors';
|
||||
import { getCurrentMarketAssetData } from '@/state/assetsSelectors';
|
||||
@@ -83,8 +83,18 @@ export const DepthChart = ({
|
||||
const { stepSizeDecimals, tickSizeDecimals } =
|
||||
useSelector(getCurrentMarketConfig, shallowEqual) ?? {};
|
||||
|
||||
const { bids, asks, lowestBid, highestBid, lowestAsk, highestAsk, midMarketPrice, orderbook } =
|
||||
useOrderbookValuesForDepthChart();
|
||||
const {
|
||||
bids,
|
||||
asks,
|
||||
lowestBid,
|
||||
highestBid,
|
||||
lowestAsk,
|
||||
highestAsk,
|
||||
midMarketPrice,
|
||||
spread,
|
||||
spreadPercent,
|
||||
orderbook,
|
||||
} = useOrderbookValuesForDepthChart();
|
||||
|
||||
// Chart state
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ export const GenerateKeys = ({
|
||||
if (message) {
|
||||
log('GenerateKeys/switchNetwork', error, { walletErrorType });
|
||||
setError(message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -17,7 +17,6 @@ import type { EvmAddress } from '@/constants/wallets';
|
||||
import { useAccounts, useDebounce, useStringGetter, useSelectedNetwork } from '@/hooks';
|
||||
import { useAccountBalance, CHAIN_DEFAULT_TOKEN_ADDRESS } from '@/hooks/useAccountBalance';
|
||||
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
|
||||
import { useWalletConnection } from '@/hooks/useWalletConnection';
|
||||
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { formMixins } from '@/styles/formMixins';
|
||||
@@ -121,7 +120,11 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
});
|
||||
|
||||
return () => {
|
||||
abacusStateManager.resetInputState();
|
||||
abacusStateManager.clearTransferInputValues();
|
||||
abacusStateManager.setTransferValue({
|
||||
field: TransferInputField.type,
|
||||
value: null,
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -365,8 +368,6 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
return <LoadingSpace id="DepositForm" />;
|
||||
}
|
||||
|
||||
const [requireUserActionInWallet, setRequireUserActionInWallet] = useState(false);
|
||||
|
||||
return (
|
||||
<Styled.Form onSubmit={onSubmit}>
|
||||
<ChainSelectMenu selectedChain={chainIdStr || undefined} onSelectChain={onSelectChain} />
|
||||
@@ -385,11 +386,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
/>
|
||||
</Styled.WithDetailsReceipt>
|
||||
{errorMessage && <AlertMessage type={AlertType.Error}>{errorMessage}</AlertMessage>}
|
||||
{requireUserActionInWallet && (
|
||||
<AlertMessage type={AlertType.Warning}>
|
||||
{stringGetter({ key: STRING_KEYS.CHECK_WALLET_FOR_REQUEST })}
|
||||
</AlertMessage>
|
||||
)}
|
||||
|
||||
<Styled.Footer>
|
||||
<DepositButtonAndReceipt
|
||||
isDisabled={isDisabled}
|
||||
@@ -398,8 +395,6 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
setSlippage={onSetSlippage}
|
||||
slippage={slippage}
|
||||
sourceToken={sourceToken || undefined}
|
||||
setRequireUserActionInWallet={setRequireUserActionInWallet}
|
||||
setError={setError}
|
||||
/>
|
||||
</Styled.Footer>
|
||||
</Styled.Form>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { type Dispatch, type SetStateAction, useState, type ReactNode, useEffect } from 'react';
|
||||
import { type Dispatch, type ReactNode, type SetStateAction, useState, useMemo } from 'react';
|
||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
import type { RouteData } from '@0xsquid/sdk';
|
||||
import { formatUnits } from 'viem';
|
||||
|
||||
import { ButtonAction, ButtonShape, ButtonSize, ButtonType } from '@/constants/buttons';
|
||||
|
||||
@@ -11,7 +12,6 @@ import { NumberSign, TOKEN_DECIMALS } from '@/constants/numbers';
|
||||
|
||||
import { useStringGetter, useTokenConfigs } from '@/hooks';
|
||||
import { useMatchingEvmNetwork } from '@/hooks/useMatchingEvmNetwork';
|
||||
import { useWalletConnection } from '@/hooks/useWalletConnection';
|
||||
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
@@ -39,8 +39,7 @@ type ElementProps = {
|
||||
isLoading?: boolean;
|
||||
|
||||
chainId?: string | number;
|
||||
setError?: Dispatch<SetStateAction<Error | null>>;
|
||||
setRequireUserActionInWallet: (val: boolean) => void;
|
||||
setError?: Dispatch<SetStateAction<Error | undefined>>;
|
||||
slippage: number;
|
||||
slotError?: ReactNode;
|
||||
setSlippage: (slippage: number) => void;
|
||||
@@ -58,7 +57,6 @@ export const DepositButtonAndReceipt = ({
|
||||
isDisabled,
|
||||
isLoading,
|
||||
slotError,
|
||||
setRequireUserActionInWallet,
|
||||
}: ElementProps) => {
|
||||
const [showFeeBreakdown, setShowFeeBreakdown] = useState(false);
|
||||
const [isEditingSlippage, setIsEditingSlipapge] = useState(false);
|
||||
@@ -66,24 +64,6 @@ export const DepositButtonAndReceipt = ({
|
||||
|
||||
const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual);
|
||||
|
||||
const { connectWallet, isConnectedWagmi } = useWalletConnection();
|
||||
|
||||
const connectWagmi = async () => {
|
||||
try {
|
||||
setRequireUserActionInWallet(false);
|
||||
await connectWallet();
|
||||
setRequireUserActionInWallet(false);
|
||||
} catch (e) {
|
||||
setRequireUserActionInWallet(true);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isConnectedWagmi && canAccountTrade) {
|
||||
connectWagmi();
|
||||
}
|
||||
}, [isConnectedWagmi, canAccountTrade]);
|
||||
|
||||
const {
|
||||
matchNetwork: switchNetwork,
|
||||
isSwitchingNetwork,
|
||||
@@ -100,7 +80,7 @@ export const DepositButtonAndReceipt = ({
|
||||
useSelector(getSubaccountBuyingPower, shallowEqual) || {};
|
||||
|
||||
const { isCctp, summary, requestPayload } = useSelector(getTransferInputs, shallowEqual) || {};
|
||||
const { usdcLabel } = useTokenConfigs();
|
||||
const { usdcDecimals, usdcLabel } = useTokenConfigs();
|
||||
|
||||
const feeSubitems: DetailsItem[] = [];
|
||||
|
||||
@@ -136,9 +116,7 @@ export const DepositButtonAndReceipt = ({
|
||||
{stringGetter({ key: STRING_KEYS.EXPECTED_DEPOSIT_AMOUNT })} <Tag>{usdcLabel}</Tag>
|
||||
</span>
|
||||
),
|
||||
value: (
|
||||
<Output type={OutputType.Fiat} fractionDigits={TOKEN_DECIMALS} value={summary?.toAmount} />
|
||||
),
|
||||
value: <Output type={OutputType.Fiat} fractionDigits={TOKEN_DECIMALS} value={summary?.toAmount} />,
|
||||
subitems: [
|
||||
{
|
||||
key: 'minimum-deposit-amount',
|
||||
@@ -148,11 +126,7 @@ export const DepositButtonAndReceipt = ({
|
||||
</span>
|
||||
),
|
||||
value: (
|
||||
<Output
|
||||
type={OutputType.Fiat}
|
||||
fractionDigits={TOKEN_DECIMALS}
|
||||
value={summary?.toAmountMin}
|
||||
/>
|
||||
<Output type={OutputType.Fiat} fractionDigits={TOKEN_DECIMALS} value={summary?.toAmountMin} />
|
||||
),
|
||||
tooltip: 'minimum-deposit-amount',
|
||||
},
|
||||
@@ -279,8 +253,6 @@ export const DepositButtonAndReceipt = ({
|
||||
>
|
||||
{!canAccountTrade ? (
|
||||
<OnboardingTriggerButton size={ButtonSize.Base} />
|
||||
) : !isConnectedWagmi ? (
|
||||
<Button action={ButtonAction.Primary} onClick={connectWallet} state={{ isLoading: true }} />
|
||||
) : !isMatchingNetwork ? (
|
||||
<Button
|
||||
action={ButtonAction.Primary}
|
||||
|
||||
@@ -101,7 +101,11 @@ export const WithdrawForm = () => {
|
||||
});
|
||||
|
||||
return () => {
|
||||
abacusStateManager.resetInputState();
|
||||
abacusStateManager.clearTransferInputValues();
|
||||
abacusStateManager.setTransferValue({
|
||||
field: TransferInputField.type,
|
||||
value: null,
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -118,7 +118,11 @@ export const TransferForm = ({
|
||||
onChangeAsset(selectedAsset);
|
||||
|
||||
return () => {
|
||||
abacusStateManager.resetInputState();
|
||||
abacusStateManager.clearTransferInputValues();
|
||||
abacusStateManager.setTransferValue({
|
||||
field: TransferInputField.type,
|
||||
value: null,
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ import { openDialog } from '@/state/dialogs';
|
||||
|
||||
import { MustBigNumber } from '@/lib/numbers';
|
||||
import { getHydratedTradingData } from '@/lib/orders';
|
||||
import { tableMixins } from '@/styles/tableMixins';
|
||||
import { breakpoints } from '@/styles';
|
||||
|
||||
const MOBILE_FILLS_PER_PAGE = 50;
|
||||
|
||||
|
||||
@@ -163,7 +163,6 @@ Styled.SizeOutput = styled(Output)<StyleProps>`
|
||||
Styled.LiveTradesTable = styled(OrderbookTradesTable)<StyleProps>`
|
||||
tr {
|
||||
--histogram-bucket-size: 1;
|
||||
background-color: var(--color-layer-2);
|
||||
|
||||
&[data-side=${OrderSide.BUY}] {
|
||||
--accent-color: var(--color-positive);
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import styled, { type AnyStyledComponent, css, keyframes } from 'styled-components';
|
||||
|
||||
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||
import { type OrderbookLine } from '@/constants/abacus';
|
||||
import { type OrderbookLine, TradeInputField } from '@/constants/abacus';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { ORDERBOOK_MAX_ROWS_PER_SIDE } from '@/constants/orderbook';
|
||||
|
||||
import { useBreakpoints, useStringGetter } from '@/hooks';
|
||||
|
||||
@@ -30,6 +29,8 @@ import { OrderbookTradesOutput, OrderbookTradesTable } from './OrderbookTradesTa
|
||||
import { breakpoints } from '@/styles';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
const ORDERBOOK_MAX_ROWS_PER_SIDE = 35;
|
||||
|
||||
type ElementProps = {
|
||||
maxRowsPerSide?: number;
|
||||
layout?: 'vertical' | 'horizontal';
|
||||
|
||||
Reference in New Issue
Block a user