Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b220203c91 | ||
|
|
5ca923984d | ||
|
|
d97626f543 | ||
|
|
835f82dbcc | ||
|
|
051bdda73a | ||
|
|
27b79957d4 | ||
|
|
4bacc901dc | ||
|
|
82d32a91a9 | ||
|
|
2a794f9459 | ||
|
|
5c26a0c270 | ||
|
|
e4991cc31d | ||
|
|
da908c826a |
@@ -11,6 +11,7 @@
|
|||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- Node.js version 18 and `pnpm` installed on your system
|
- Node.js version 18 and `pnpm` installed on your system
|
||||||
|
- Wallet Connect account
|
||||||
|
|
||||||
For deploying with Vercel, create an account with [Vercel](https://vercel.com/signup) if you don't have one already.
|
For deploying with Vercel, create an account with [Vercel](https://vercel.com/signup) if you don't have one already.
|
||||||
|
|
||||||
@@ -61,7 +62,14 @@ pnpm ladle
|
|||||||
|
|
||||||
This will automatically open your default browser at `http://localhost:61000`.
|
This will automatically open your default browser at `http://localhost:61000`.
|
||||||
|
|
||||||
## Part 3: Deploying with Vercel
|
## Part 3: Configuring environment
|
||||||
|
|
||||||
|
Add or modify the relevant endpoints, links and options in `/public/configs/env.json`.
|
||||||
|
You'll need to provide a Wallet Connect project id to enable onboarding and wallet connection:
|
||||||
|
- Create a project on https://cloud.walletconnect.com/app
|
||||||
|
- Copy over the project ID into this [field](https://github.com/dydxprotocol/v4-web/blob/67ecbd75b43e0c264b7b4d2d9b3d969830b0621c/public/configs/env.json#L822C33-L822C46)
|
||||||
|
|
||||||
|
## Part 4: Deploying with Vercel
|
||||||
|
|
||||||
### Step 1: Connect your repository to Vercel
|
### Step 1: Connect your repository to Vercel
|
||||||
|
|
||||||
@@ -78,7 +86,7 @@ If you wish to incorporate analytics via Amplitude and Bugsnag, you can use our
|
|||||||
|
|
||||||
For more details, check out Vercel's [official documentation](https://vercel.com/docs).
|
For more details, check out Vercel's [official documentation](https://vercel.com/docs).
|
||||||
|
|
||||||
## Part 4: Deploying to IPFS
|
## Part 5: Deploying to IPFS
|
||||||
|
|
||||||
### web3.storage: deploy to IPFS via web3.storage using the provided script
|
### web3.storage: deploy to IPFS via web3.storage using the provided script
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -13,6 +13,7 @@
|
|||||||
"build:inject-app-deeplinks": "sh scripts/inject-app-deeplinks.sh",
|
"build:inject-app-deeplinks": "sh scripts/inject-app-deeplinks.sh",
|
||||||
"build:inject-amplitude": "node scripts/inject-amplitude.js",
|
"build:inject-amplitude": "node scripts/inject-amplitude.js",
|
||||||
"build:inject-bugsnag": "node scripts/inject-bugsnag.js",
|
"build:inject-bugsnag": "node scripts/inject-bugsnag.js",
|
||||||
|
"build:inject-intercom": "node scripts/inject-intercom.js",
|
||||||
"build:inject-statuspage": "node scripts/inject-statuspage.js",
|
"build:inject-statuspage": "node scripts/inject-statuspage.js",
|
||||||
"deploy:ipfs": "node scripts/upload-ipfs.js --verbose",
|
"deploy:ipfs": "node scripts/upload-ipfs.js --verbose",
|
||||||
"deploy:update-ipns": "node scripts/update-ipns.js",
|
"deploy:update-ipns": "node scripts/update-ipns.js",
|
||||||
@@ -38,9 +39,9 @@
|
|||||||
"@cosmjs/proto-signing": "^0.31.0",
|
"@cosmjs/proto-signing": "^0.31.0",
|
||||||
"@cosmjs/stargate": "^0.31.0",
|
"@cosmjs/stargate": "^0.31.0",
|
||||||
"@cosmjs/tendermint-rpc": "^0.31.0",
|
"@cosmjs/tendermint-rpc": "^0.31.0",
|
||||||
"@dydxprotocol/v4-abacus": "^0.7.0",
|
"@dydxprotocol/v4-abacus": "^0.7.6",
|
||||||
"@dydxprotocol/v4-client-js": "^0.36.1",
|
"@dydxprotocol/v4-client-js": "^0.40.3",
|
||||||
"@dydxprotocol/v4-localization": "^0.1.30",
|
"@dydxprotocol/v4-localization": "^0.1.32",
|
||||||
"@ethersproject/providers": "^5.7.2",
|
"@ethersproject/providers": "^5.7.2",
|
||||||
"@js-joda/core": "^5.5.3",
|
"@js-joda/core": "^5.5.3",
|
||||||
"@radix-ui/react-collapsible": "^1.0.3",
|
"@radix-ui/react-collapsible": "^1.0.3",
|
||||||
|
|||||||
Generated
+25
-24
@@ -27,14 +27,14 @@ dependencies:
|
|||||||
specifier: ^0.31.0
|
specifier: ^0.31.0
|
||||||
version: 0.31.0
|
version: 0.31.0
|
||||||
'@dydxprotocol/v4-abacus':
|
'@dydxprotocol/v4-abacus':
|
||||||
specifier: ^0.7.0
|
specifier: ^0.7.6
|
||||||
version: 0.7.0
|
version: 0.7.6
|
||||||
'@dydxprotocol/v4-client-js':
|
'@dydxprotocol/v4-client-js':
|
||||||
specifier: ^0.36.1
|
specifier: ^0.40.3
|
||||||
version: 0.36.1
|
version: 0.40.3
|
||||||
'@dydxprotocol/v4-localization':
|
'@dydxprotocol/v4-localization':
|
||||||
specifier: ^0.1.30
|
specifier: ^0.1.32
|
||||||
version: 0.1.30
|
version: 0.1.32
|
||||||
'@ethersproject/providers':
|
'@ethersproject/providers':
|
||||||
specifier: ^5.7.2
|
specifier: ^5.7.2
|
||||||
version: 5.7.2
|
version: 5.7.2
|
||||||
@@ -645,7 +645,7 @@ packages:
|
|||||||
/@confio/ics23@0.6.8:
|
/@confio/ics23@0.6.8:
|
||||||
resolution: {integrity: sha512-wB6uo+3A50m0sW/EWcU64xpV/8wShZ6bMTa7pF8eYsTrSkQA7oLUIJcs/wb8g4y2Oyq701BaGiO6n/ak5WXO1w==}
|
resolution: {integrity: sha512-wB6uo+3A50m0sW/EWcU64xpV/8wShZ6bMTa7pF8eYsTrSkQA7oLUIJcs/wb8g4y2Oyq701BaGiO6n/ak5WXO1w==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@noble/hashes': 1.3.1
|
'@noble/hashes': 1.3.2
|
||||||
protobufjs: 6.11.4
|
protobufjs: 6.11.4
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
@@ -717,7 +717,7 @@ packages:
|
|||||||
'@cosmjs/encoding': 0.30.1
|
'@cosmjs/encoding': 0.30.1
|
||||||
'@cosmjs/math': 0.30.1
|
'@cosmjs/math': 0.30.1
|
||||||
'@cosmjs/utils': 0.30.1
|
'@cosmjs/utils': 0.30.1
|
||||||
'@noble/hashes': 1.3.1
|
'@noble/hashes': 1.3.2
|
||||||
bn.js: 5.2.1
|
bn.js: 5.2.1
|
||||||
elliptic: 6.5.4
|
elliptic: 6.5.4
|
||||||
libsodium-wrappers: 0.7.11
|
libsodium-wrappers: 0.7.11
|
||||||
@@ -979,12 +979,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
|
resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@dydxprotocol/v4-abacus@0.7.0:
|
/@dydxprotocol/v4-abacus@0.7.6:
|
||||||
resolution: {integrity: sha512-XheqfIpOODfQFG860oH0fneVgp9qQKPMDTwrvFXaM/JtKH9ekOUUO6De72EsJ7qOuxWwl1WgoALA8b4tRs0tiw==}
|
resolution: {integrity: sha512-FdDXRaFMfxhyrJJs0dNrb1KG6X95lPHelua1yCn/SVgzwGaAqlJczrzmdh98INntuRAgIxOu69R5mCGyekumyg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-client-js@0.36.1:
|
/@dydxprotocol/v4-client-js@0.40.3:
|
||||||
resolution: {integrity: sha512-KJ3MtWI61wmm+xZtXQd7/hYKIoVFG32TRdyyVaXXO8vpW9Oqd0JD8QSM/wuegkciAh5YmP/BrDzYuu77zHO6yg==}
|
resolution: {integrity: sha512-nMQd6tYisKDKIbfx0BGJSYEOSt+I+t5SsaBSmlgTdso+w2rCRO9vyxS+u6MF9h4w5FsVRfhHo3e6uTWX48WpGQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cosmjs/amino': 0.30.1
|
'@cosmjs/amino': 0.30.1
|
||||||
'@cosmjs/encoding': 0.31.1
|
'@cosmjs/encoding': 0.31.1
|
||||||
@@ -993,14 +993,15 @@ packages:
|
|||||||
'@cosmjs/stargate': 0.30.1
|
'@cosmjs/stargate': 0.30.1
|
||||||
'@cosmjs/tendermint-rpc': 0.30.1
|
'@cosmjs/tendermint-rpc': 0.30.1
|
||||||
'@cosmjs/utils': 0.31.1
|
'@cosmjs/utils': 0.31.1
|
||||||
'@dydxprotocol/v4-proto': 0.2.1
|
'@dydxprotocol/v4-proto': 0.4.1
|
||||||
'@osmonauts/lcd': 0.6.0
|
'@osmonauts/lcd': 0.6.0
|
||||||
'@scure/bip32': 1.3.1
|
'@scure/bip32': 1.3.2
|
||||||
'@scure/bip39': 1.2.1
|
'@scure/bip39': 1.2.1
|
||||||
axios: 1.1.3
|
axios: 1.1.3
|
||||||
bech32: 1.1.4
|
bech32: 1.1.4
|
||||||
bignumber.js: 9.1.1
|
bignumber.js: 9.1.1
|
||||||
ethereum-cryptography: 2.1.2
|
ethereum-cryptography: 2.1.2
|
||||||
|
ethers: 6.6.1
|
||||||
long: 4.0.0
|
long: 4.0.0
|
||||||
protobufjs: 6.11.4
|
protobufjs: 6.11.4
|
||||||
ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)
|
ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)
|
||||||
@@ -1010,12 +1011,12 @@ packages:
|
|||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-localization@0.1.30:
|
/@dydxprotocol/v4-localization@0.1.32:
|
||||||
resolution: {integrity: sha512-xTlQuQmPz7wfGkjd07giYMAxRrolDbJE3DryJSIMB6R1MBq1wLzAcwp/iR/nELRwilRX9c44Tap0gGt+oAajiQ==}
|
resolution: {integrity: sha512-ZtXScxgFLjUt0Ag52RyFnQe9aEl1Aky5fp+vMGOBduVkFiCEMRMkSsSgg6grMdyw/x0AbnxOTRkhYoX2MsK9Ow==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-proto@0.2.1:
|
/@dydxprotocol/v4-proto@0.4.1:
|
||||||
resolution: {integrity: sha512-Q5b/g331DoyMjBpO2/jtrxUX3WF5UaIKZp/unK332xuefHNFnkMYtZ05p0V71iSdO35tBdz8yt0VYP2WtUsp+w==}
|
resolution: {integrity: sha512-2pBkokufWcxfIpiXE6QuQOBXUe154OTp6ojCIdOPW9TFLxzchoygxXnb5dL6rAQVNj9Qbg+hhXBllutt4m99dw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
protobufjs: 6.11.4
|
protobufjs: 6.11.4
|
||||||
dev: false
|
dev: false
|
||||||
@@ -4708,8 +4709,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==}
|
resolution: {integrity: sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@noble/curves': 1.1.0
|
'@noble/curves': 1.1.0
|
||||||
'@noble/hashes': 1.3.1
|
'@noble/hashes': 1.3.2
|
||||||
'@scure/base': 1.1.1
|
'@scure/base': 1.1.3
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@scure/bip32@1.3.2:
|
/@scure/bip32@1.3.2:
|
||||||
@@ -4731,7 +4732,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==}
|
resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@noble/hashes': 1.3.2
|
'@noble/hashes': 1.3.2
|
||||||
'@scure/base': 1.1.1
|
'@scure/base': 1.1.3
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@solana/buffer-layout@4.0.1:
|
/@solana/buffer-layout@4.0.1:
|
||||||
@@ -4745,8 +4746,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-up5VG1dK+GPhykmuMIozJZBbVqpm77vbOG6/r5dS7NBGZonwHfTLdBbsYc3rjmaQ4DpCXUa3tUc4RZHRORvZrw==}
|
resolution: {integrity: sha512-up5VG1dK+GPhykmuMIozJZBbVqpm77vbOG6/r5dS7NBGZonwHfTLdBbsYc3rjmaQ4DpCXUa3tUc4RZHRORvZrw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.22.10
|
'@babel/runtime': 7.22.10
|
||||||
'@noble/curves': 1.1.0
|
'@noble/curves': 1.2.0
|
||||||
'@noble/hashes': 1.3.1
|
'@noble/hashes': 1.3.2
|
||||||
'@solana/buffer-layout': 4.0.1
|
'@solana/buffer-layout': 4.0.1
|
||||||
agentkeepalive: 4.5.0
|
agentkeepalive: 4.5.0
|
||||||
bigint-buffer: 1.1.5
|
bigint-buffer: 1.1.5
|
||||||
@@ -7144,7 +7145,7 @@ packages:
|
|||||||
/bip39@3.1.0:
|
/bip39@3.1.0:
|
||||||
resolution: {integrity: sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==}
|
resolution: {integrity: sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@noble/hashes': 1.3.1
|
'@noble/hashes': 1.3.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/bl@5.1.0:
|
/bl@5.1.0:
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
+19
-19
@@ -40,7 +40,7 @@
|
|||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "Dv4TNT",
|
||||||
"denom": "adv4tnt",
|
"denom": "adv4tnt",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
@@ -56,15 +56,15 @@
|
|||||||
"endpoints": {
|
"endpoints": {
|
||||||
"indexers": [
|
"indexers": [
|
||||||
{
|
{
|
||||||
"api": "http://indexer.v4dev.dydx.exchange",
|
"api": "https://indexer.v4dev.dydx.exchange",
|
||||||
"socket": "wss://indexer.v4dev.dydx.exchange"
|
"socket": "wss://indexer.v4dev.dydx.exchange"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"validators": [
|
"validators": [
|
||||||
"http://validator.v4dev.dydx.exchange"
|
"https://validator.v4dev.dydx.exchange"
|
||||||
],
|
],
|
||||||
"0xsquid": "https://testnet.api.0xsquid.com",
|
"0xsquid": "https://testnet.api.0xsquid.com",
|
||||||
"faucet": "http://faucet.v4dev.dydx.exchange"
|
"faucet": "https://faucet.v4dev.dydx.exchange"
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
"tos": "https://dydx.exchange/v4-terms",
|
"tos": "https://dydx.exchange/v4-terms",
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "Dv4TNT",
|
||||||
"denom": "adv4tnt",
|
"denom": "adv4tnt",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"validators": [
|
"validators": [
|
||||||
"http://35.75.227.118"
|
"http://54.92.118.111"
|
||||||
],
|
],
|
||||||
"0xsquid": "https://testnet.api.0xsquid.com"
|
"0xsquid": "https://testnet.api.0xsquid.com"
|
||||||
},
|
},
|
||||||
@@ -159,7 +159,7 @@
|
|||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "Dv4TNT",
|
||||||
"denom": "adv4tnt",
|
"denom": "adv4tnt",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
@@ -218,7 +218,7 @@
|
|||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "Dv4TNT",
|
||||||
"denom": "adv4tnt",
|
"denom": "adv4tnt",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
@@ -277,7 +277,7 @@
|
|||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "Dv4TNT",
|
||||||
"denom": "adv4tnt",
|
"denom": "adv4tnt",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
@@ -340,7 +340,7 @@
|
|||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "Dv4TNT",
|
||||||
"denom": "adv4tnt",
|
"denom": "adv4tnt",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
@@ -403,7 +403,7 @@
|
|||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "Dv4TNT",
|
||||||
"denom": "adv4tnt",
|
"denom": "adv4tnt",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
@@ -468,7 +468,7 @@
|
|||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "Dv4TNT",
|
||||||
"denom": "adv4tnt",
|
"denom": "adv4tnt",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
@@ -532,7 +532,7 @@
|
|||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "Dv4TNT",
|
||||||
"denom": "adv4tnt",
|
"denom": "adv4tnt",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
@@ -596,7 +596,7 @@
|
|||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "Dv4TNT",
|
||||||
"denom": "adv4tnt",
|
"denom": "adv4tnt",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
@@ -660,7 +660,7 @@
|
|||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "Dv4TNT",
|
||||||
"denom": "adv4tnt",
|
"denom": "adv4tnt",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
@@ -724,7 +724,7 @@
|
|||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "Dv4TNT",
|
||||||
"denom": "adv4tnt",
|
"denom": "adv4tnt",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
@@ -789,8 +789,8 @@
|
|||||||
"tokens": {
|
"tokens": {
|
||||||
"comment": "Change according to mainnet release",
|
"comment": "Change according to mainnet release",
|
||||||
"chain": {
|
"chain": {
|
||||||
"name": "DYDX",
|
"name": "TokenName",
|
||||||
"denom": "adv4tnt",
|
"denom": "tokenDenom",
|
||||||
"decimals": 18,
|
"decimals": 18,
|
||||||
"image": "/currencies/dydx.png"
|
"image": "/currencies/dydx.png"
|
||||||
},
|
},
|
||||||
@@ -844,4 +844,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/* eslint-disable no-console */
|
||||||
|
import fs from 'fs/promises';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const INTERCOM_APP_ID = process.env.INTERCOM_APP_ID;
|
||||||
|
|
||||||
|
const currentPath = fileURLToPath(import.meta.url);
|
||||||
|
const projectRoot = path.dirname(currentPath);
|
||||||
|
const htmlFilePath = path.resolve(projectRoot, '../dist/index.html');
|
||||||
|
|
||||||
|
if (INTERCOM_APP_ID) {
|
||||||
|
try {
|
||||||
|
const html = await fs.readFile(htmlFilePath, 'utf-8');
|
||||||
|
|
||||||
|
const intercomScripts = `
|
||||||
|
<!-- Intercom -->
|
||||||
|
<script>
|
||||||
|
window.intercomSettings = {
|
||||||
|
api_base: 'https://api-iam.intercom.io',
|
||||||
|
app_id: '${INTERCOM_APP_ID}',
|
||||||
|
custom_launcher_selector: '.custom_intercom',
|
||||||
|
hide_default_launcher: true,
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// We pre-filled your app ID in the widget URL: 'https://widget.intercom.io/widget/${INTERCOM_APP_ID}'
|
||||||
|
(function () {
|
||||||
|
var w = window;
|
||||||
|
var ic = w.Intercom;
|
||||||
|
if (typeof ic === 'function') {
|
||||||
|
ic('reattach_activator');
|
||||||
|
ic('update', w.intercomSettings);
|
||||||
|
} else {
|
||||||
|
var d = document;
|
||||||
|
var i = function () {
|
||||||
|
i.c(arguments);
|
||||||
|
};
|
||||||
|
i.q = [];
|
||||||
|
i.c = function (args) {
|
||||||
|
i.q.push(args);
|
||||||
|
};
|
||||||
|
w.Intercom = i;
|
||||||
|
var l = function () {
|
||||||
|
var s = d.createElement('script');
|
||||||
|
s.type = 'text/javascript';
|
||||||
|
s.async = true;
|
||||||
|
s.src = 'https://widget.intercom.io/widget/${INTERCOM_APP_ID}';
|
||||||
|
var x = d.getElementsByTagName('script')[0];
|
||||||
|
x.parentNode.insertBefore(s, x);
|
||||||
|
};
|
||||||
|
if (document.readyState === 'complete') {
|
||||||
|
l();
|
||||||
|
} else if (w.attachEvent) {
|
||||||
|
w.attachEvent('onload', l);
|
||||||
|
} else {
|
||||||
|
w.addEventListener('load', l, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const injectedHtml = html.replace(
|
||||||
|
'<div id="root"></div>',
|
||||||
|
`<div id="root"></div>\n${intercomScripts}\n`
|
||||||
|
);
|
||||||
|
|
||||||
|
await fs.writeFile(htmlFilePath, injectedHtml, 'utf-8');
|
||||||
|
|
||||||
|
console.log('Intercom scripts successfully injected.');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error injecting Intercom scripts:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
-2
@@ -7,7 +7,13 @@ import { GrazProvider } from 'graz';
|
|||||||
|
|
||||||
import { AppRoute, DEFAULT_TRADE_ROUTE } from '@/constants/routes';
|
import { AppRoute, DEFAULT_TRADE_ROUTE } from '@/constants/routes';
|
||||||
|
|
||||||
import { useBreakpoints, useInitializePage, useShouldShowFooter, useAnalytics } from '@/hooks';
|
import {
|
||||||
|
useBreakpoints,
|
||||||
|
useTokenConfigs,
|
||||||
|
useInitializePage,
|
||||||
|
useShouldShowFooter,
|
||||||
|
useAnalytics,
|
||||||
|
} from '@/hooks';
|
||||||
import { DydxProvider } from '@/hooks/useDydxClient';
|
import { DydxProvider } from '@/hooks/useDydxClient';
|
||||||
import { AccountsProvider } from '@/hooks/useAccounts';
|
import { AccountsProvider } from '@/hooks/useAccounts';
|
||||||
import { DialogAreaProvider, useDialogArea } from '@/hooks/useDialogArea';
|
import { DialogAreaProvider, useDialogArea } from '@/hooks/useDialogArea';
|
||||||
@@ -27,6 +33,8 @@ import ProfilePage from '@/pages/Profile';
|
|||||||
import { SettingsPage } from '@/pages/settings/Settings';
|
import { SettingsPage } from '@/pages/settings/Settings';
|
||||||
import TradePage from '@/pages/trade/Trade';
|
import TradePage from '@/pages/trade/Trade';
|
||||||
import { RewardsPage } from '@/pages/rewards/RewardsPage';
|
import { RewardsPage } from '@/pages/rewards/RewardsPage';
|
||||||
|
import { TermsOfUsePage } from '@/pages/TermsOfUsePage';
|
||||||
|
import { PrivacyPolicyPage } from '@/pages/PrivacyPolicyPage';
|
||||||
|
|
||||||
import { HeaderDesktop } from '@/layout/Header/HeaderDesktop';
|
import { HeaderDesktop } from '@/layout/Header/HeaderDesktop';
|
||||||
import { FooterDesktop } from '@/layout/Footer/FooterDesktop';
|
import { FooterDesktop } from '@/layout/Footer/FooterDesktop';
|
||||||
@@ -55,6 +63,7 @@ const Content = () => {
|
|||||||
const { isTablet, isNotTablet } = useBreakpoints();
|
const { isTablet, isNotTablet } = useBreakpoints();
|
||||||
const isShowingHeader = isNotTablet;
|
const isShowingHeader = isNotTablet;
|
||||||
const isShowingFooter = useShouldShowFooter();
|
const isShowingFooter = useShouldShowFooter();
|
||||||
|
const { chainTokenLabel } = useTokenConfigs();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Styled.Content isShowingHeader={isShowingHeader} isShowingFooter={isShowingFooter}>
|
<Styled.Content isShowingHeader={isShowingHeader} isShowingFooter={isShowingFooter}>
|
||||||
@@ -69,7 +78,7 @@ const Content = () => {
|
|||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
<Route path={AppRoute.Markets} element={<MarketsPage />} />
|
<Route path={AppRoute.Markets} element={<MarketsPage />} />
|
||||||
<Route path={AppRoute.Rewards} element={<RewardsPage />} />
|
<Route path={`/${chainTokenLabel}`} element={<RewardsPage />} />
|
||||||
{isTablet && (
|
{isTablet && (
|
||||||
<>
|
<>
|
||||||
<Route path={AppRoute.Alerts} element={<AlertsPage />} />
|
<Route path={AppRoute.Alerts} element={<AlertsPage />} />
|
||||||
@@ -82,6 +91,9 @@ const Content = () => {
|
|||||||
<Route path={`${AppRoute.Portfolio}/*`} element={<PortfolioPage />} />
|
<Route path={`${AppRoute.Portfolio}/*`} element={<PortfolioPage />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
<Route path={AppRoute.Terms} element={<TermsOfUsePage />} />
|
||||||
|
<Route path={AppRoute.Privacy} element={<PrivacyPolicyPage />} />
|
||||||
|
|
||||||
<Route path="*" element={<Navigate to={DEFAULT_TRADE_ROUTE} replace />} />
|
<Route path="*" element={<Navigate to={DEFAULT_TRADE_ROUTE} replace />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|||||||
@@ -3,31 +3,43 @@ import styled, { AnyStyledComponent } from 'styled-components';
|
|||||||
|
|
||||||
import { type MenuConfig } from '@/constants/menus';
|
import { type MenuConfig } from '@/constants/menus';
|
||||||
|
|
||||||
import { Dialog, DialogPlacement } from '@/components/Dialog';
|
import { Dialog, DialogPlacement, type DialogProps } from '@/components/Dialog';
|
||||||
import { ComboboxMenu } from '@/components/ComboboxMenu';
|
import { ComboboxMenu, type ComboboxMenuProps } from '@/components/ComboboxMenu';
|
||||||
|
|
||||||
type ElementProps<MenuItemValue extends string | number, MenuGroupValue extends string | number> = {
|
type ElementProps<MenuItemValue extends string | number, MenuGroupValue extends string | number> = {
|
||||||
isOpen?: boolean;
|
|
||||||
setIsOpen?: (open: boolean) => void;
|
|
||||||
title?: React.ReactNode;
|
title?: React.ReactNode;
|
||||||
description?: React.ReactNode;
|
description?: React.ReactNode;
|
||||||
slotTrigger?: React.ReactNode;
|
|
||||||
slotHeaderInner?: React.ReactNode;
|
|
||||||
slotFooter?: React.ReactNode;
|
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
|
||||||
items: MenuConfig<MenuItemValue, MenuGroupValue>;
|
items: MenuConfig<MenuItemValue, MenuGroupValue>;
|
||||||
onItemSelected?: () => void;
|
|
||||||
inputPlaceholder?: string;
|
|
||||||
slotEmpty?: React.ReactNode;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type StyleProps = {
|
type StyleProps = {
|
||||||
placement: DialogPlacement,
|
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ComboboxDialogMenu = <MenuItemValue extends string | number, MenuGroupValue extends string | number>({
|
type PickComboxMenuProps<
|
||||||
|
MenuItemValue extends string | number,
|
||||||
|
MenuGroupValue extends string | number
|
||||||
|
> = Pick<
|
||||||
|
ComboboxMenuProps<MenuItemValue, MenuGroupValue>,
|
||||||
|
'inputPlaceholder' | 'onItemSelected' | 'slotEmpty' | 'withSearch' | 'withStickyLayout'
|
||||||
|
>;
|
||||||
|
|
||||||
|
type PickDialogProps = Pick<
|
||||||
|
DialogProps,
|
||||||
|
| 'description'
|
||||||
|
| 'isOpen'
|
||||||
|
| 'placement'
|
||||||
|
| 'setIsOpen'
|
||||||
|
| 'slotHeaderInner'
|
||||||
|
| 'slotTrigger'
|
||||||
|
| 'slotFooter'
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const ComboboxDialogMenu = <
|
||||||
|
MenuItemValue extends string | number,
|
||||||
|
MenuGroupValue extends string | number
|
||||||
|
>({
|
||||||
isOpen = false,
|
isOpen = false,
|
||||||
setIsOpen,
|
setIsOpen,
|
||||||
title,
|
title,
|
||||||
@@ -40,11 +52,16 @@ export const ComboboxDialogMenu = <MenuItemValue extends string | number, MenuGr
|
|||||||
onItemSelected,
|
onItemSelected,
|
||||||
inputPlaceholder,
|
inputPlaceholder,
|
||||||
slotEmpty,
|
slotEmpty,
|
||||||
|
withSearch,
|
||||||
|
withStickyLayout = true,
|
||||||
children,
|
children,
|
||||||
|
|
||||||
placement = DialogPlacement.Default,
|
placement = DialogPlacement.Default,
|
||||||
className,
|
className,
|
||||||
}: ElementProps<MenuItemValue, MenuGroupValue> & StyleProps) => (
|
}: ElementProps<MenuItemValue, MenuGroupValue> &
|
||||||
|
PickComboxMenuProps<MenuItemValue, MenuGroupValue> &
|
||||||
|
PickDialogProps &
|
||||||
|
StyleProps) => (
|
||||||
// TODO: sub-menu state management
|
// TODO: sub-menu state management
|
||||||
<Styled.Dialog
|
<Styled.Dialog
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
@@ -54,7 +71,6 @@ export const ComboboxDialogMenu = <MenuItemValue extends string | number, MenuGr
|
|||||||
slotHeaderInner={slotHeaderInner}
|
slotHeaderInner={slotHeaderInner}
|
||||||
slotTrigger={slotTrigger}
|
slotTrigger={slotTrigger}
|
||||||
slotFooter={slotFooter}
|
slotFooter={slotFooter}
|
||||||
|
|
||||||
placement={placement}
|
placement={placement}
|
||||||
className={className}
|
className={className}
|
||||||
>
|
>
|
||||||
@@ -64,7 +80,8 @@ export const ComboboxDialogMenu = <MenuItemValue extends string | number, MenuGr
|
|||||||
title={title}
|
title={title}
|
||||||
inputPlaceholder={inputPlaceholder}
|
inputPlaceholder={inputPlaceholder}
|
||||||
slotEmpty={slotEmpty}
|
slotEmpty={slotEmpty}
|
||||||
withStickyLayout
|
withSearch={withSearch}
|
||||||
|
withStickyLayout={withStickyLayout}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
</Styled.Dialog>
|
</Styled.Dialog>
|
||||||
@@ -98,4 +115,5 @@ Styled.Dialog = styled(Dialog)`
|
|||||||
|
|
||||||
Styled.ComboboxMenu = styled(ComboboxMenu)`
|
Styled.ComboboxMenu = styled(ComboboxMenu)`
|
||||||
--comboboxMenu-backgroundColor: var(--comboboxDialogMenu-backgroundColor);
|
--comboboxMenu-backgroundColor: var(--comboboxDialogMenu-backgroundColor);
|
||||||
|
--comboboxMenu-item-gap: var(--comboxDialogMenu-item-gap, 0.5rem);
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { layoutMixins } from '@/styles/layoutMixins';
|
|||||||
|
|
||||||
import { Tag } from '@/components/Tag';
|
import { Tag } from '@/components/Tag';
|
||||||
|
|
||||||
type ElementProps<MenuItemValue extends string, MenuGroupValue extends string> = {
|
type ElementProps<MenuItemValue extends string | number, MenuGroupValue extends string | number> = {
|
||||||
items: MenuConfig<MenuItemValue, MenuGroupValue>;
|
items: MenuConfig<MenuItemValue, MenuGroupValue>;
|
||||||
onItemSelected?: () => void;
|
onItemSelected?: () => void;
|
||||||
|
|
||||||
@@ -23,6 +23,11 @@ type StyleProps = {
|
|||||||
withStickyLayout?: boolean;
|
withStickyLayout?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ComboboxMenuProps<
|
||||||
|
MenuItemValue extends string | number,
|
||||||
|
MenuGroupValue extends string | number
|
||||||
|
> = ElementProps<MenuItemValue, MenuGroupValue> & StyleProps;
|
||||||
|
|
||||||
export const ComboboxMenu = <MenuItemValue extends string, MenuGroupValue extends string>({
|
export const ComboboxMenu = <MenuItemValue extends string, MenuGroupValue extends string>({
|
||||||
items,
|
items,
|
||||||
onItemSelected,
|
onItemSelected,
|
||||||
@@ -34,7 +39,7 @@ export const ComboboxMenu = <MenuItemValue extends string, MenuGroupValue extend
|
|||||||
|
|
||||||
className,
|
className,
|
||||||
withStickyLayout,
|
withStickyLayout,
|
||||||
}: ElementProps<MenuItemValue, MenuGroupValue> & StyleProps) => {
|
}: ComboboxMenuProps<MenuItemValue, MenuGroupValue>) => {
|
||||||
const [highlightedCommand, setHighlightedCommand] = useState<MenuItemValue>();
|
const [highlightedCommand, setHighlightedCommand] = useState<MenuItemValue>();
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
// const inputRef = useRef<HTMLInputElement | null>(null);
|
// const inputRef = useRef<HTMLInputElement | null>(null);
|
||||||
@@ -171,6 +176,7 @@ Styled.Command = styled(Command)<{ $withStickyLayout?: boolean }>`
|
|||||||
--comboboxMenu-item-highlighted-backgroundColor: var(--color-layer-3);
|
--comboboxMenu-item-highlighted-backgroundColor: var(--color-layer-3);
|
||||||
--comboboxMenu-item-highlighted-textColor: var(--color-text-1);
|
--comboboxMenu-item-highlighted-textColor: var(--color-text-1);
|
||||||
--comboboxMenu-item-backgroundColor: ;
|
--comboboxMenu-item-backgroundColor: ;
|
||||||
|
--comboboxMenu-item-gap: 0.5rem;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
align-content: start;
|
align-content: start;
|
||||||
@@ -269,18 +275,17 @@ Styled.List = styled(Command.List)<{ $withStickyLayout?: boolean }>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Item = styled(Command.Item)`
|
Styled.Item = styled(Command.Item)`
|
||||||
|
${layoutMixins.scrollSnapItem}
|
||||||
${popoverMixins.item}
|
${popoverMixins.item}
|
||||||
--item-checked-backgroundColor: var(--comboboxMenu-item-checked-backgroundColor);
|
--item-checked-backgroundColor: var(--comboboxMenu-item-checked-backgroundColor);
|
||||||
--item-checked-textColor: var(--comboboxMenu-item-checked-textColor);
|
--item-checked-textColor: var(--comboboxMenu-item-checked-textColor);
|
||||||
--item-highlighted-textColor: var(--comboboxMenu-item-highlighted-textColor);
|
--item-highlighted-textColor: var(--comboboxMenu-item-highlighted-textColor);
|
||||||
|
--item-gap: var(--comboboxMenu-item-gap);
|
||||||
${layoutMixins.scrollSnapItem}
|
|
||||||
|
|
||||||
background-color: var(--comboboxMenu-backgroundColor, inherit);
|
background-color: var(--comboboxMenu-backgroundColor, inherit);
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
|
||||||
|
|
||||||
&[aria-disabled='true'] {
|
&[aria-disabled='true'] {
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ type StyleProps = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type DialogProps = ElementProps & StyleProps;
|
||||||
|
|
||||||
const DialogPortal = ({
|
const DialogPortal = ({
|
||||||
withPortal,
|
withPortal,
|
||||||
container,
|
container,
|
||||||
@@ -82,7 +84,7 @@ export const Dialog = ({
|
|||||||
hasHeaderBorder = false,
|
hasHeaderBorder = false,
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
}: ElementProps & StyleProps) => {
|
}: DialogProps) => {
|
||||||
const closeButtonRef = useRef<HTMLButtonElement>();
|
const closeButtonRef = useRef<HTMLButtonElement>();
|
||||||
|
|
||||||
const showOverlay = ![DialogPlacement.Inline, DialogPlacement.FullScreen].includes(placement);
|
const showOverlay = ![DialogPlacement.Inline, DialogPlacement.FullScreen].includes(placement);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
CaretIcon,
|
CaretIcon,
|
||||||
CautionCircleStrokeIcon,
|
CautionCircleStrokeIcon,
|
||||||
CautionCircleIcon,
|
CautionCircleIcon,
|
||||||
|
ChatIcon,
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
ChevronLeftIcon,
|
ChevronLeftIcon,
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
@@ -80,6 +81,7 @@ export enum IconName {
|
|||||||
Caret = 'Caret',
|
Caret = 'Caret',
|
||||||
CautionCircle = 'CautionCircle',
|
CautionCircle = 'CautionCircle',
|
||||||
CautionCircleStroked = 'CautionCircleStroked',
|
CautionCircleStroked = 'CautionCircleStroked',
|
||||||
|
Chat = 'Chat',
|
||||||
Check = 'Check',
|
Check = 'Check',
|
||||||
ChevronLeft = 'ChevronLeft',
|
ChevronLeft = 'ChevronLeft',
|
||||||
ChevronRight = 'ChevronRight',
|
ChevronRight = 'ChevronRight',
|
||||||
@@ -148,6 +150,7 @@ const icons = {
|
|||||||
[IconName.Caret]: CaretIcon,
|
[IconName.Caret]: CaretIcon,
|
||||||
[IconName.CautionCircle]: CautionCircleIcon,
|
[IconName.CautionCircle]: CautionCircleIcon,
|
||||||
[IconName.CautionCircleStroked]: CautionCircleStrokeIcon,
|
[IconName.CautionCircleStroked]: CautionCircleStrokeIcon,
|
||||||
|
[IconName.Chat]: ChatIcon,
|
||||||
[IconName.Check]: CheckIcon,
|
[IconName.Check]: CheckIcon,
|
||||||
[IconName.ChevronLeft]: ChevronLeftIcon,
|
[IconName.ChevronLeft]: ChevronLeftIcon,
|
||||||
[IconName.ChevronRight]: ChevronRightIcon,
|
[IconName.ChevronRight]: ChevronRightIcon,
|
||||||
|
|||||||
@@ -44,4 +44,4 @@ export type EvmDerivedAddresses = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AMOUNT_RESERVED_FOR_GAS_USDC = 100_000;
|
export const AMOUNT_RESERVED_FOR_GAS_USDC = 0.1;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export type MenuItem<MenuItemValue, MenuItemTypes = string> = {
|
|||||||
value: MenuItemValue;
|
value: MenuItemValue;
|
||||||
|
|
||||||
slotBefore?: React.ReactNode;
|
slotBefore?: React.ReactNode;
|
||||||
label: string;
|
label: React.ReactNode;
|
||||||
labelRight?: React.ReactNode;
|
labelRight?: React.ReactNode;
|
||||||
tag?: React.ReactNode;
|
tag?: React.ReactNode;
|
||||||
slotAfter?: React.ReactNode;
|
slotAfter?: React.ReactNode;
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ export enum AppRoute {
|
|||||||
Profile = '/profile',
|
Profile = '/profile',
|
||||||
Alerts = '/alerts',
|
Alerts = '/alerts',
|
||||||
Settings = '/settings',
|
Settings = '/settings',
|
||||||
Rewards = '/DV4TNT',
|
Terms = '/terms',
|
||||||
|
Privacy = '/privacy',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum PortfolioRoute {
|
export enum PortfolioRoute {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { ExternalProvider } from '@ethersproject/providers';
|
import type { ExternalProvider } from '@ethersproject/providers';
|
||||||
import { USDC_DENOM, type onboarding, DYDX_DENOM } from '@dydxprotocol/v4-client-js';
|
import { type onboarding } from '@dydxprotocol/v4-client-js';
|
||||||
import type { suggestChain } from 'graz';
|
import type { suggestChain } from 'graz';
|
||||||
|
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
@@ -352,15 +352,5 @@ export const DYDX_CHAIN_INFO: Parameters<typeof suggestChain>[0] = {
|
|||||||
// TODO: export this type from abacus instead
|
// TODO: export this type from abacus instead
|
||||||
export enum DydxChainAsset {
|
export enum DydxChainAsset {
|
||||||
USDC = 'usdc',
|
USDC = 'usdc',
|
||||||
DYDX = 'dydx',
|
CHAINTOKEN = 'chain',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DYDX_CHAIN_ASSET_COIN_DENOM: Record<DydxChainAsset, string> = {
|
|
||||||
[DydxChainAsset.USDC]: USDC_DENOM,
|
|
||||||
[DydxChainAsset.DYDX]: DYDX_DENOM,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DYDX_CHAIN_ASSET_TAGS: Record<DydxChainAsset, string> = {
|
|
||||||
[DydxChainAsset.USDC]: 'USDC',
|
|
||||||
[DydxChainAsset.DYDX]: 'Dv4TNT',
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useApiState } from './useApiState';
|
import { useApiState } from './useApiState';
|
||||||
import { useBreakpoints } from './useBreakpoints';
|
import { useBreakpoints } from './useBreakpoints';
|
||||||
|
import { useTokenConfigs } from './useTokenConfigs';
|
||||||
import { useCommandMenu } from './useCommandMenu';
|
import { useCommandMenu } from './useCommandMenu';
|
||||||
import { useCurrentMarketId } from './useCurrentMarketId';
|
import { useCurrentMarketId } from './useCurrentMarketId';
|
||||||
import { useDebounce } from './useDebounce';
|
import { useDebounce } from './useDebounce';
|
||||||
@@ -25,6 +26,7 @@ import { useSubaccount } from './useSubaccount';
|
|||||||
export {
|
export {
|
||||||
useApiState,
|
useApiState,
|
||||||
useBreakpoints,
|
useBreakpoints,
|
||||||
|
useTokenConfigs,
|
||||||
useCommandMenu,
|
useCommandMenu,
|
||||||
useCurrentMarketId,
|
useCurrentMarketId,
|
||||||
useDebounce,
|
useDebounce,
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import { StargateClient } from '@cosmjs/stargate';
|
|||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import { formatUnits } from 'viem';
|
import { formatUnits } from 'viem';
|
||||||
|
|
||||||
import { USDC_DENOM, DYDX_DENOM } from '@dydxprotocol/v4-client-js';
|
|
||||||
|
|
||||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||||
import { QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
import { QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
||||||
import { EvmAddress } from '@/constants/wallets';
|
import { EvmAddress } from '@/constants/wallets';
|
||||||
@@ -18,6 +16,7 @@ import { getBalances, getStakingBalances } from '@/state/accountSelectors';
|
|||||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||||
|
|
||||||
import { useAccounts } from './useAccounts';
|
import { useAccounts } from './useAccounts';
|
||||||
|
import { useTokenConfigs } from './useTokenConfigs';
|
||||||
|
|
||||||
type UseAccountBalanceProps = {
|
type UseAccountBalanceProps = {
|
||||||
// Token Items
|
// Token Items
|
||||||
@@ -52,6 +51,7 @@ export const useAccountBalance = ({
|
|||||||
|
|
||||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||||
const balances = useSelector(getBalances, shallowEqual);
|
const balances = useSelector(getBalances, shallowEqual);
|
||||||
|
const { chainTokenDenom, usdcDenom } = useTokenConfigs();
|
||||||
const evmChainId = Number(ENVIRONMENT_CONFIG_MAP[selectedNetwork].ethereumChainId);
|
const evmChainId = Number(ENVIRONMENT_CONFIG_MAP[selectedNetwork].ethereumChainId);
|
||||||
const stakingBalances = useSelector(getStakingBalances, shallowEqual);
|
const stakingBalances = useSelector(getStakingBalances, shallowEqual);
|
||||||
|
|
||||||
@@ -93,18 +93,14 @@ export const useAccountBalance = ({
|
|||||||
const { formatted: evmBalance } = evmQuery.data || {};
|
const { formatted: evmBalance } = evmQuery.data || {};
|
||||||
const balance = !assetSymbol ? '0' : isCosmosChain ? cosmosQuery.data : evmBalance;
|
const balance = !assetSymbol ? '0' : isCosmosChain ? cosmosQuery.data : evmBalance;
|
||||||
|
|
||||||
const nativeTokenCoinBalance = balances?.[DYDX_DENOM];
|
const nativeTokenCoinBalance = balances?.[chainTokenDenom];
|
||||||
const nativeTokenBalance = MustBigNumber(nativeTokenCoinBalance?.amount)
|
const nativeTokenBalance = MustBigNumber(nativeTokenCoinBalance?.amount);
|
||||||
.div(QUANTUM_MULTIPLIER)
|
|
||||||
.toNumber();
|
|
||||||
|
|
||||||
const usdcCoinBalance = balances?.[USDC_DENOM];
|
const usdcCoinBalance = balances?.[usdcDenom];
|
||||||
const usdcBalance = MustBigNumber(usdcCoinBalance?.amount).div(QUANTUM_MULTIPLIER).toNumber();
|
const usdcBalance = MustBigNumber(usdcCoinBalance?.amount).toNumber();
|
||||||
|
|
||||||
const nativeStakingCoinBalanace = stakingBalances?.[DYDX_DENOM];
|
const nativeStakingCoinBalanace = stakingBalances?.[chainTokenDenom];
|
||||||
const nativeStakingBalance = MustBigNumber(nativeStakingCoinBalanace?.amount)
|
const nativeStakingBalance = MustBigNumber(nativeStakingCoinBalanace?.amount).toNumber();
|
||||||
.div(QUANTUM_MULTIPLIER)
|
|
||||||
.toNumber();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
balance,
|
balance,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useCallback, useContext, createContext, useEffect, useState, useMemo }
|
|||||||
|
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { AES, enc } from 'crypto-js';
|
import { AES, enc } from 'crypto-js';
|
||||||
import { LocalWallet, USDC_DENOM, type Subaccount } from '@dydxprotocol/v4-client-js';
|
import { LocalWallet, type Subaccount } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { OnboardingGuard, OnboardingState, type EvmDerivedAddresses } from '@/constants/account';
|
import { OnboardingGuard, OnboardingState, type EvmDerivedAddresses } from '@/constants/account';
|
||||||
import { DialogTypes } from '@/constants/dialogs';
|
import { DialogTypes } from '@/constants/dialogs';
|
||||||
@@ -130,16 +130,8 @@ const useAccountsContext = () => {
|
|||||||
// dYdX subaccounts
|
// dYdX subaccounts
|
||||||
const [dydxSubaccounts, setDydxSubaccounts] = useState<Subaccount[] | undefined>();
|
const [dydxSubaccounts, setDydxSubaccounts] = useState<Subaccount[] | undefined>();
|
||||||
|
|
||||||
const { getAccountBalance, getSubaccounts } = useMemo(
|
const { getSubaccounts } = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
getAccountBalance: async ({
|
|
||||||
dydxAddress,
|
|
||||||
denom = USDC_DENOM,
|
|
||||||
}: {
|
|
||||||
dydxAddress: DydxAddress;
|
|
||||||
denom?: string;
|
|
||||||
}) => await compositeClient?.validatorClient.get.getAccountBalance(dydxAddress, denom),
|
|
||||||
|
|
||||||
getSubaccounts: async ({ dydxAddress }: { dydxAddress: DydxAddress }) => {
|
getSubaccounts: async ({ dydxAddress }: { dydxAddress: DydxAddress }) => {
|
||||||
try {
|
try {
|
||||||
const response = await compositeClient?.indexerClient.account.getSubaccounts(dydxAddress);
|
const response = await compositeClient?.indexerClient.account.getSubaccounts(dydxAddress);
|
||||||
@@ -326,7 +318,6 @@ const useAccountsContext = () => {
|
|||||||
disconnect,
|
disconnect,
|
||||||
|
|
||||||
// dydxClient Account methods
|
// dydxClient Account methods
|
||||||
getAccountBalance,
|
|
||||||
getSubaccounts,
|
getSubaccounts,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import type { ResolutionString } from 'public/tradingview/charting_library';
|
|||||||
|
|
||||||
import type { ConnectNetworkEvent, NetworkConfig } from '@/constants/abacus';
|
import type { ConnectNetworkEvent, NetworkConfig } from '@/constants/abacus';
|
||||||
import { type Candle, RESOLUTION_MAP } from '@/constants/candles';
|
import { type Candle, RESOLUTION_MAP } from '@/constants/candles';
|
||||||
|
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||||
|
import { DydxChainAsset } from '@/constants/wallets';
|
||||||
|
|
||||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||||
|
|
||||||
@@ -36,6 +38,7 @@ const useDydxClientContext = () => {
|
|||||||
// ------ Network ------ //
|
// ------ Network ------ //
|
||||||
|
|
||||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||||
|
const tokensConfigs = ENVIRONMENT_CONFIG_MAP[selectedNetwork].tokens;
|
||||||
|
|
||||||
const [networkConfig, setNetworkConfig] = useState<NetworkConfig>();
|
const [networkConfig, setNetworkConfig] = useState<NetworkConfig>();
|
||||||
|
|
||||||
@@ -65,7 +68,14 @@ const useDydxClientContext = () => {
|
|||||||
new Network(
|
new Network(
|
||||||
selectedNetwork,
|
selectedNetwork,
|
||||||
new IndexerConfig(networkConfig.indexerUrl, networkConfig.websocketUrl),
|
new IndexerConfig(networkConfig.indexerUrl, networkConfig.websocketUrl),
|
||||||
new ValidatorConfig(networkConfig.validatorUrl, networkConfig.chainId, {
|
new ValidatorConfig(networkConfig.validatorUrl, networkConfig.chainId,
|
||||||
|
{
|
||||||
|
USDC_DENOM: tokensConfigs[DydxChainAsset.USDC].denom,
|
||||||
|
USDC_DECIMALS: tokensConfigs[DydxChainAsset.USDC].decimals,
|
||||||
|
USDC_GAS_DENOM: tokensConfigs[DydxChainAsset.USDC].gasDenom,
|
||||||
|
CHAINTOKEN_DENOM: tokensConfigs[DydxChainAsset.CHAINTOKEN].denom,
|
||||||
|
CHAINTOKEN_DECIMALS: tokensConfigs[DydxChainAsset.CHAINTOKEN].decimals,
|
||||||
|
}, {
|
||||||
broadcastPollIntervalMs: 3_000,
|
broadcastPollIntervalMs: 3_000,
|
||||||
broadcastTimeoutMs: 60_000,
|
broadcastTimeoutMs: 60_000,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { DialogTypes } from '@/constants/dialogs';
|
|
||||||
import { LocalStorageKey } from '@/constants/localStorage';
|
import { LocalStorageKey } from '@/constants/localStorage';
|
||||||
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork, ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork, ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||||
|
|
||||||
@@ -9,7 +8,6 @@ import { useAccounts, useLocalStorage } from '@/hooks';
|
|||||||
|
|
||||||
import { setSelectedNetwork } from '@/state/app';
|
import { setSelectedNetwork } from '@/state/app';
|
||||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||||
import { openDialog } from '@/state/dialogs';
|
|
||||||
|
|
||||||
import { validateAgainstAvailableEnvironments } from '@/lib/network';
|
import { validateAgainstAvailableEnvironments } from '@/lib/network';
|
||||||
|
|
||||||
@@ -27,17 +25,6 @@ export const useSelectedNetwork = (): {
|
|||||||
validateFn: validateAgainstAvailableEnvironments,
|
validateFn: validateAgainstAvailableEnvironments,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (
|
|
||||||
import.meta.env.MODE === 'production' &&
|
|
||||||
ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId === 'dydx-testnet-4'
|
|
||||||
) {
|
|
||||||
dispatch(
|
|
||||||
openDialog({ type: DialogTypes.ExchangeOffline, dialogProps: { preventClose: true } })
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, [selectedNetwork]);
|
|
||||||
|
|
||||||
const switchNetwork = useCallback(
|
const switchNetwork = useCallback(
|
||||||
(network: DydxNetwork) => {
|
(network: DydxNetwork) => {
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|||||||
+27
-27
@@ -3,15 +3,10 @@ import { shallowEqual, useSelector, useDispatch } from 'react-redux';
|
|||||||
import type { Nullable } from '@dydxprotocol/v4-abacus';
|
import type { Nullable } from '@dydxprotocol/v4-abacus';
|
||||||
import Long from 'long';
|
import Long from 'long';
|
||||||
import type { IndexedTx } from '@cosmjs/stargate';
|
import type { IndexedTx } from '@cosmjs/stargate';
|
||||||
import type { EncodeObject, Coin } from '@cosmjs/proto-signing';
|
import type { EncodeObject } from '@cosmjs/proto-signing';
|
||||||
import { Method } from '@cosmjs/tendermint-rpc';
|
import { Method } from '@cosmjs/tendermint-rpc';
|
||||||
|
|
||||||
import {
|
import { type LocalWallet, SubaccountClient } from '@dydxprotocol/v4-client-js';
|
||||||
type LocalWallet,
|
|
||||||
SubaccountClient,
|
|
||||||
DYDX_DENOM,
|
|
||||||
USDC_DENOM,
|
|
||||||
} from '@dydxprotocol/v4-client-js';
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
AccountBalance,
|
AccountBalance,
|
||||||
@@ -34,6 +29,7 @@ import { MustBigNumber } from '@/lib/numbers';
|
|||||||
import { log } from '@/lib/telemetry';
|
import { log } from '@/lib/telemetry';
|
||||||
|
|
||||||
import { useAccounts } from './useAccounts';
|
import { useAccounts } from './useAccounts';
|
||||||
|
import { useTokenConfigs } from './useTokenConfigs';
|
||||||
import { useDydxClient } from './useDydxClient';
|
import { useDydxClient } from './useDydxClient';
|
||||||
|
|
||||||
type SubaccountContextType = ReturnType<typeof useSubaccountContext>;
|
type SubaccountContextType = ReturnType<typeof useSubaccountContext>;
|
||||||
@@ -52,6 +48,7 @@ export const useSubaccount = () => useContext(SubaccountContext);
|
|||||||
|
|
||||||
export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: LocalWallet }) => {
|
export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: LocalWallet }) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const { usdcDenom } = useTokenConfigs();
|
||||||
const { compositeClient, faucetClient } = useDydxClient();
|
const { compositeClient, faucetClient } = useDydxClient();
|
||||||
|
|
||||||
const { getFaucetFunds } = useMemo(
|
const { getFaucetFunds } = useMemo(
|
||||||
@@ -77,13 +74,12 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
() => ({
|
() => ({
|
||||||
depositToSubaccount: async ({
|
depositToSubaccount: async ({
|
||||||
subaccountClient,
|
subaccountClient,
|
||||||
assetId = 0,
|
|
||||||
amount,
|
amount,
|
||||||
}: {
|
}: {
|
||||||
subaccountClient: SubaccountClient;
|
subaccountClient: SubaccountClient;
|
||||||
assetId?: number;
|
assetId?: number;
|
||||||
amount: Long;
|
amount: number;
|
||||||
}) => await compositeClient?.validatorClient.post.deposit(subaccountClient, assetId, amount),
|
}) => await compositeClient?.depositToSubaccount(subaccountClient, amount.toString()),
|
||||||
|
|
||||||
withdrawFromSubaccount: async ({
|
withdrawFromSubaccount: async ({
|
||||||
subaccountClient,
|
subaccountClient,
|
||||||
@@ -91,7 +87,7 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
}: {
|
}: {
|
||||||
subaccountClient: SubaccountClient;
|
subaccountClient: SubaccountClient;
|
||||||
amount: number;
|
amount: number;
|
||||||
}) => await compositeClient?.withdrawFromSubaccount(subaccountClient, amount),
|
}) => await compositeClient?.withdrawFromSubaccount(subaccountClient, amount.toString()),
|
||||||
|
|
||||||
transferFromSubaccountToAddress: async ({
|
transferFromSubaccountToAddress: async ({
|
||||||
subaccountClient,
|
subaccountClient,
|
||||||
@@ -134,12 +130,21 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
amount: number;
|
amount: number;
|
||||||
recipient: string;
|
recipient: string;
|
||||||
}) =>
|
}) =>
|
||||||
await compositeClient?.validatorClient.post.sendToken(
|
await compositeClient?.validatorClient.post.send(
|
||||||
subaccountClient,
|
subaccountClient.wallet,
|
||||||
recipient,
|
() =>
|
||||||
DYDX_DENOM,
|
new Promise((resolve) => {
|
||||||
Long.fromNumber(amount * QUANTUM_MULTIPLIER),
|
const msg = compositeClient?.sendTokenMessage(
|
||||||
|
subaccountClient.wallet,
|
||||||
|
amount.toString(),
|
||||||
|
recipient,
|
||||||
|
);
|
||||||
|
|
||||||
|
resolve([msg]);
|
||||||
|
}),
|
||||||
false,
|
false,
|
||||||
|
compositeClient?.validatorClient?.post.defaultDydxGasPrice,
|
||||||
|
undefined,
|
||||||
Method.BroadcastTxCommit
|
Method.BroadcastTxCommit
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -156,7 +161,7 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
|
|
||||||
const transaction = JSON.parse(payload);
|
const transaction = JSON.parse(payload);
|
||||||
|
|
||||||
const msg = compositeClient.withdrawFromSubaccountMessage(subaccountClient, amount);
|
const msg = compositeClient.withdrawFromSubaccountMessage(subaccountClient, amount.toString());
|
||||||
const ibcMsg: EncodeObject = {
|
const ibcMsg: EncodeObject = {
|
||||||
typeUrl: transaction.msgTypeUrl,
|
typeUrl: transaction.msgTypeUrl,
|
||||||
value: transaction.msg,
|
value: transaction.msg,
|
||||||
@@ -195,13 +200,9 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
async (balance: AccountBalance) => {
|
async (balance: AccountBalance) => {
|
||||||
if (!localDydxWallet) return;
|
if (!localDydxWallet) return;
|
||||||
|
|
||||||
const amountAfterDust = MustBigNumber(balance.amount)
|
const amount = parseFloat(balance.amount) - AMOUNT_RESERVED_FOR_GAS_USDC;
|
||||||
.minus(AMOUNT_RESERVED_FOR_GAS_USDC) // keep 0.1 USDC in user's wallet for gas
|
|
||||||
.toString();
|
|
||||||
|
|
||||||
const amount = Long.fromString(amountAfterDust || '0');
|
if (amount > 0) {
|
||||||
|
|
||||||
if (amount.greaterThan(Long.ZERO)) {
|
|
||||||
const subaccountClient = new SubaccountClient(localDydxWallet, 0);
|
const subaccountClient = new SubaccountClient(localDydxWallet, 0);
|
||||||
await depositToSubaccount({ amount, subaccountClient });
|
await depositToSubaccount({ amount, subaccountClient });
|
||||||
}
|
}
|
||||||
@@ -210,7 +211,7 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
);
|
);
|
||||||
|
|
||||||
const balances = useSelector(getBalances, shallowEqual);
|
const balances = useSelector(getBalances, shallowEqual);
|
||||||
const usdcCoinBalance = balances?.[USDC_DENOM];
|
const usdcCoinBalance = balances?.[usdcDenom];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (usdcCoinBalance) {
|
if (usdcCoinBalance) {
|
||||||
@@ -219,7 +220,7 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
}, [usdcCoinBalance]);
|
}, [usdcCoinBalance]);
|
||||||
|
|
||||||
const deposit = useCallback(
|
const deposit = useCallback(
|
||||||
async (amount: Long) => {
|
async (amount: number) => {
|
||||||
if (!subaccountClient) {
|
if (!subaccountClient) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -247,8 +248,7 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
if (!subaccountClient) {
|
if (!subaccountClient) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
return (await (coinDenom === usdcDenom
|
||||||
return (await (coinDenom === USDC_DENOM
|
|
||||||
? transferFromSubaccountToAddress
|
? transferFromSubaccountToAddress
|
||||||
: transferNativeToken)({ subaccountClient, amount, recipient })) as IndexedTx;
|
: transferNativeToken)({ subaccountClient, amount, recipient })) as IndexedTx;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||||
|
import { DydxChainAsset } from '@/constants/wallets';
|
||||||
|
|
||||||
|
import { useSelectedNetwork } from '@/hooks';
|
||||||
|
|
||||||
|
export const useTokenConfigs = (): {
|
||||||
|
tokensConfigs: {
|
||||||
|
[DydxChainAsset.USDC]: {
|
||||||
|
denom: string;
|
||||||
|
name: string;
|
||||||
|
decimals: number;
|
||||||
|
gasDenom?: string;
|
||||||
|
},
|
||||||
|
[DydxChainAsset.CHAINTOKEN]: {
|
||||||
|
denom: string;
|
||||||
|
name: string;
|
||||||
|
decimals: number;
|
||||||
|
gasDenom?: string;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
usdcDenom: string;
|
||||||
|
usdcLabel: string;
|
||||||
|
chainTokenDenom: string;
|
||||||
|
chainTokenLabel: string;
|
||||||
|
} => {
|
||||||
|
const { selectedNetwork } = useSelectedNetwork();
|
||||||
|
const tokensConfigs = ENVIRONMENT_CONFIG_MAP[selectedNetwork].tokens;
|
||||||
|
|
||||||
|
return {
|
||||||
|
tokensConfigs,
|
||||||
|
usdcDenom: tokensConfigs[DydxChainAsset.USDC].denom,
|
||||||
|
usdcLabel: tokensConfigs[DydxChainAsset.USDC].name,
|
||||||
|
chainTokenDenom: tokensConfigs[DydxChainAsset.CHAINTOKEN].denom,
|
||||||
|
chainTokenLabel: tokensConfigs[DydxChainAsset.CHAINTOKEN].name,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { LocalStorageKey } from '@/constants/localStorage';
|
import { LocalStorageKey } from '@/constants/localStorage';
|
||||||
|
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type DydxAddress,
|
type DydxAddress,
|
||||||
@@ -28,6 +30,8 @@ import {
|
|||||||
WalletType as CosmosWalletType,
|
WalletType as CosmosWalletType,
|
||||||
} from 'graz';
|
} from 'graz';
|
||||||
|
|
||||||
|
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||||
|
|
||||||
import { resolveWagmiConnector } from '@/lib/wagmi';
|
import { resolveWagmiConnector } from '@/lib/wagmi';
|
||||||
import { getWalletConnection, parseWalletError } from '@/lib/wallet';
|
import { getWalletConnection, parseWalletError } from '@/lib/wallet';
|
||||||
import { log } from '@/lib/telemetry';
|
import { log } from '@/lib/telemetry';
|
||||||
@@ -84,6 +88,9 @@ export const useWalletConnection = () => {
|
|||||||
|
|
||||||
// Wallet connection
|
// Wallet connection
|
||||||
|
|
||||||
|
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||||
|
const walletConnectConfig = ENVIRONMENT_CONFIG_MAP[selectedNetwork].wallets.walletconnect;
|
||||||
|
|
||||||
const { connectAsync: connectWagmi } =
|
const { connectAsync: connectWagmi } =
|
||||||
walletType && walletConnectionType
|
walletType && walletConnectionType
|
||||||
? useConnectWagmi({
|
? useConnectWagmi({
|
||||||
@@ -92,6 +99,7 @@ export const useWalletConnection = () => {
|
|||||||
walletConnection: {
|
walletConnection: {
|
||||||
type: walletConnectionType,
|
type: walletConnectionType,
|
||||||
},
|
},
|
||||||
|
walletConnectConfig,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
: useConnectWagmi();
|
: useConnectWagmi();
|
||||||
@@ -127,6 +135,7 @@ export const useWalletConnection = () => {
|
|||||||
connector: resolveWagmiConnector({
|
connector: resolveWagmiConnector({
|
||||||
walletType,
|
walletType,
|
||||||
walletConnection,
|
walletConnection,
|
||||||
|
walletConnectConfig,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -217,7 +226,7 @@ export const useWalletConnection = () => {
|
|||||||
evmAddressWagmi,
|
evmAddressWagmi,
|
||||||
signerWagmi,
|
signerWagmi,
|
||||||
publicClientWagmi,
|
publicClientWagmi,
|
||||||
|
|
||||||
// Wallet connection (Cosmos)
|
// Wallet connection (Cosmos)
|
||||||
dydxAddress,
|
dydxAddress,
|
||||||
dydxAddressGraz,
|
dydxAddressGraz,
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.625 6.1875h6.75m-6.75 2.25H9M1.6875 9.57c0 1.2.84225 2.2455 2.03025 2.4203.84675.1245 1.7025.2197 2.56725.2842.2625.0195.5025.1575.64875.3758L9 15.75l2.0663-3.0997c.0724-.1078.1685-.1977.2809-.2628.1125-.0651.2382-.1038.3678-.113.8589-.0641 1.7152-.1589 2.5672-.2842 1.188-.1748 2.0303-1.2195 2.0303-2.42105v-4.5135c0-1.2015-.8423-2.24625-2.0303-2.421A36.294434 36.294434 0 0 0 9 2.25c-1.794 0-3.558.13125-5.28225.38475-1.188.17475-2.03025 1.22025-2.03025 2.421V9.57Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||||
|
After Width: | Height: | Size: 672 B |
@@ -1 +1 @@
|
|||||||
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M15 8C15 9.53527 14.6867 10.8758 14.2269 11.7954C13.77 12.7092 13.3116 12.9664 13.0527 12.9968L12.6636 12.8953C12.4116 12.7511 12.092 12.4331 11.7731 11.7954C11.3133 10.8758 11 9.53527 11 8C11 6.46473 11.3133 5.12424 11.7731 4.20457C12.0924 3.56607 12.4124 3.24815 12.6645 3.10417L13.0519 3.00311C13.3107 3.0331 13.7696 3.28991 14.2269 4.20457C14.6867 5.12424 15 6.46473 15 8ZM12.2928 2.16768L1.41963 5.00415C0.628571 5.08768 0 6.39699 0 7.99992C0 9.60346 0.629045 10.9131 1.42053 10.9958L2.50023 11.2774V12.9998C2.50023 13.8283 3.17181 14.4998 4.00023 14.4998C4.82866 14.4998 5.50023 13.8283 5.50023 12.9998V12.0601L12.2914 13.8317C12.5186 13.9417 12.7559 14 13 14C14.6569 14 16 11.3137 16 8C16 4.68629 14.6569 2 13 2C12.7564 2 12.5196 2.05808 12.2928 2.16768ZM10.9931 3.5402L2.49607 5.75681C2.80523 6.30634 3 7.10764 3 7.99992C3 8.89214 2.80525 9.69339 2.49614 10.2429L10.9929 12.4595C10.3833 11.3612 10 9.77013 10 8C10 6.22968 10.3834 4.63843 10.9931 3.5402ZM2 7.99992C2 8.70677 1.85462 9.29725 1.66623 9.67403C1.59961 9.80728 1.54246 9.88955 1.5 9.93955C1.45754 9.88955 1.40039 9.80728 1.33377 9.67403C1.14538 9.29725 1 8.70677 1 7.99992C1 7.29308 1.14538 6.70259 1.33377 6.32582C1.40039 6.19256 1.45754 6.11029 1.5 6.06029C1.54246 6.11029 1.59961 6.19256 1.66623 6.32582C1.85462 6.70259 2 7.29308 2 7.99992ZM1.41964 10.0124C1.41962 10.0124 1.42071 10.0118 1.42296 10.0109C1.42079 10.0121 1.41966 10.0125 1.41964 10.0124ZM1.57704 10.0109C1.57929 10.0118 1.58038 10.0124 1.58036 10.0124C1.58033 10.0125 1.57921 10.0121 1.57704 10.0109ZM1.58036 5.9874C1.58038 5.98747 1.57929 5.98808 1.57704 5.98899C1.57921 5.98778 1.58034 5.98732 1.58036 5.9874ZM1.42296 5.98899C1.42071 5.98808 1.41962 5.98747 1.41964 5.9874C1.41966 5.98732 1.42079 5.98778 1.42296 5.98899ZM3.50023 12.9998V11.5383L4.50023 11.7992V12.9998C4.50023 13.276 4.27638 13.4998 4.00023 13.4998C3.72409 13.4998 3.50023 13.276 3.50023 12.9998Z" fill="currentColor"/></svg>
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M15 8C15 9.53527 14.6867 10.8758 14.2269 11.7954C13.77 12.7092 13.3116 12.9664 13.0527 12.9968L12.6636 12.8953C12.4116 12.7511 12.092 12.4331 11.7731 11.7954C11.3133 10.8758 11 9.53527 11 8C11 6.46473 11.3133 5.12424 11.7731 4.20457C12.0924 3.56607 12.4124 3.24815 12.6645 3.10417L13.0519 3.00311C13.3107 3.0331 13.7696 3.28991 14.2269 4.20457C14.6867 5.12424 15 6.46473 15 8ZM12.2928 2.16768L1.41963 5.00415C0.628571 5.08768 0 6.39699 0 7.99992C0 9.60346 0.629045 10.9131 1.42053 10.9958L2.50023 11.2774V12.9998C2.50023 13.8283 3.17181 14.4998 4.00023 14.4998C4.82866 14.4998 5.50023 13.8283 5.50023 12.9998V12.0601L12.2914 13.8317C12.5186 13.9417 12.7559 14 13 14C14.6569 14 16 11.3137 16 8C16 4.68629 14.6569 2 13 2C12.7564 2 12.5196 2.05808 12.2928 2.16768ZM10.9931 3.5402L2.49607 5.75681C2.80523 6.30634 3 7.10764 3 7.99992C3 8.89214 2.80525 9.69339 2.49614 10.2429L10.9929 12.4595C10.3833 11.3612 10 9.77013 10 8C10 6.22968 10.3834 4.63843 10.9931 3.5402ZM2 7.99992C2 8.70677 1.85462 9.29725 1.66623 9.67403C1.59961 9.80728 1.54246 9.88955 1.5 9.93955C1.45754 9.88955 1.40039 9.80728 1.33377 9.67403C1.14538 9.29725 1 8.70677 1 7.99992C1 7.29308 1.14538 6.70259 1.33377 6.32582C1.40039 6.19256 1.45754 6.11029 1.5 6.06029C1.54246 6.11029 1.59961 6.19256 1.66623 6.32582C1.85462 6.70259 2 7.29308 2 7.99992ZM1.41964 10.0124C1.41962 10.0124 1.42071 10.0118 1.42296 10.0109C1.42079 10.0121 1.41966 10.0125 1.41964 10.0124ZM1.57704 10.0109C1.57929 10.0118 1.58038 10.0124 1.58036 10.0124C1.58033 10.0125 1.57921 10.0121 1.57704 10.0109ZM1.58036 5.9874C1.58038 5.98747 1.57929 5.98808 1.57704 5.98899C1.57921 5.98778 1.58034 5.98732 1.58036 5.9874ZM1.42296 5.98899C1.42071 5.98808 1.41962 5.98747 1.41964 5.9874C1.41966 5.98732 1.42079 5.98778 1.42296 5.98899ZM3.50023 12.9998V11.5383L4.50023 11.7992V12.9998C4.50023 13.276 4.27638 13.4998 4.00023 13.4998C3.72409 13.4998 3.50023 13.276 3.50023 12.9998Z" fill="currentColor"/></svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
@@ -8,6 +8,7 @@ export { default as CalculatorIcon } from './calculator.svg';
|
|||||||
export { default as CaretIcon } from './caret-down.svg';
|
export { default as CaretIcon } from './caret-down.svg';
|
||||||
export { default as CautionCircleIcon } from './caution-circle.svg';
|
export { default as CautionCircleIcon } from './caution-circle.svg';
|
||||||
export { default as CautionCircleStrokeIcon } from './caution-circle-stroke.svg';
|
export { default as CautionCircleStrokeIcon } from './caution-circle-stroke.svg';
|
||||||
|
export { default as ChatIcon } from './chat-bubble.svg';
|
||||||
export { default as CheckIcon } from './check.svg';
|
export { default as CheckIcon } from './check.svg';
|
||||||
export { default as ChevronLeftIcon } from './chevron-left.svg';
|
export { default as ChevronLeftIcon } from './chevron-left.svg';
|
||||||
export { default as ChevronRightIcon } from './chevron-right.svg';
|
export { default as ChevronRightIcon } from './chevron-right.svg';
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import styled, { type AnyStyledComponent, css } from 'styled-components';
|
import styled, { type AnyStyledComponent, css } from 'styled-components';
|
||||||
|
|
||||||
import { AbacusApiStatus } from '@/constants/abacus';
|
import { AbacusApiStatus } from '@/constants/abacus';
|
||||||
|
import { ButtonSize } from '@/constants/buttons';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
|
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||||
|
|
||||||
import { useApiState, useStringGetter } from '@/hooks';
|
import { useApiState, useSelectedNetwork, useStringGetter } from '@/hooks';
|
||||||
|
import { ChatIcon, LinkOutIcon } from '@/icons';
|
||||||
|
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
|
import { Button } from '@/components/Button';
|
||||||
import { Details } from '@/components/Details';
|
import { Details } from '@/components/Details';
|
||||||
import { Output, OutputType } from '@/components/Output';
|
import { Output, OutputType } from '@/components/Output';
|
||||||
import { WithTooltip } from '@/components/WithTooltip';
|
import { WithTooltip } from '@/components/WithTooltip';
|
||||||
@@ -24,6 +28,8 @@ enum ExchangeStatus {
|
|||||||
export const FooterDesktop = () => {
|
export const FooterDesktop = () => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const { height, indexerHeight, status, statusErrorMessage } = useApiState();
|
const { height, indexerHeight, status, statusErrorMessage } = useApiState();
|
||||||
|
const { selectedNetwork } = useSelectedNetwork();
|
||||||
|
const { statusPage } = ENVIRONMENT_CONFIG_MAP[selectedNetwork].links;
|
||||||
|
|
||||||
const { exchangeStatus, label } =
|
const { exchangeStatus, label } =
|
||||||
!status || status === AbacusApiStatus.NORMAL
|
!status || status === AbacusApiStatus.NORMAL
|
||||||
@@ -38,20 +44,37 @@ export const FooterDesktop = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Styled.Footer>
|
<Styled.Footer>
|
||||||
<WithTooltip
|
<Styled.Row>
|
||||||
slotTooltip={
|
<WithTooltip
|
||||||
statusErrorMessage && (
|
slotTooltip={
|
||||||
<dl>
|
statusErrorMessage && (
|
||||||
<dd>{statusErrorMessage}</dd>
|
<dl>
|
||||||
</dl>
|
<dd>{statusErrorMessage}</dd>
|
||||||
)
|
</dl>
|
||||||
}
|
)
|
||||||
>
|
}
|
||||||
<Styled.Row>
|
>
|
||||||
<Styled.StatusDot exchangeStatus={exchangeStatus} />
|
<Styled.FooterButton
|
||||||
<span>{label}</span>
|
slotLeft={<Styled.StatusDot exchangeStatus={exchangeStatus} />}
|
||||||
</Styled.Row>
|
slotRight={statusPage && <LinkOutIcon />}
|
||||||
</WithTooltip>
|
size={ButtonSize.XSmall}
|
||||||
|
state={{ isDisabled: !statusPage }}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Styled.FooterButton>
|
||||||
|
</WithTooltip>
|
||||||
|
|
||||||
|
{globalThis?.Intercom && (
|
||||||
|
<Styled.FooterButton
|
||||||
|
slotLeft={<ChatIcon />}
|
||||||
|
size={ButtonSize.XSmall}
|
||||||
|
onClick={() => globalThis.Intercom('show')}
|
||||||
|
>
|
||||||
|
{stringGetter({ key: STRING_KEYS.HELP_AND_SUPPORT })}
|
||||||
|
</Styled.FooterButton>
|
||||||
|
)}
|
||||||
|
</Styled.Row>
|
||||||
|
|
||||||
{import.meta.env.MODE !== 'production' && (
|
{import.meta.env.MODE !== 'production' && (
|
||||||
<Styled.Details
|
<Styled.Details
|
||||||
withSeparators
|
withSeparators
|
||||||
@@ -82,20 +105,22 @@ Styled.Footer = styled.footer`
|
|||||||
${layoutMixins.stickyFooter}
|
${layoutMixins.stickyFooter}
|
||||||
${layoutMixins.spacedRow}
|
${layoutMixins.spacedRow}
|
||||||
grid-area: Footer;
|
grid-area: Footer;
|
||||||
|
|
||||||
font-size: 0.66em;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Row = styled.div`
|
Styled.Row = styled.div`
|
||||||
${layoutMixins.row}
|
${layoutMixins.row}
|
||||||
padding: 0 1rem;
|
${layoutMixins.spacedRow}
|
||||||
gap: 0.5rem;
|
width: var(--sidebar-width);
|
||||||
|
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
border-right: 1px solid var(--color-border);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.StatusDot = styled.div<{ exchangeStatus: ExchangeStatus }>`
|
Styled.StatusDot = styled.div<{ exchangeStatus: ExchangeStatus }>`
|
||||||
width: 1em;
|
width: 0.5rem;
|
||||||
height: 1em;
|
height: 0.5rem;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
|
||||||
background-color: ${({ exchangeStatus }) =>
|
background-color: ${({ exchangeStatus }) =>
|
||||||
({
|
({
|
||||||
@@ -104,12 +129,28 @@ Styled.StatusDot = styled.div<{ exchangeStatus: ExchangeStatus }>`
|
|||||||
}[exchangeStatus])};
|
}[exchangeStatus])};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
Styled.FooterButton = styled(Button)`
|
||||||
|
--button-height: 1.5rem;
|
||||||
|
--button-radius: 0.25rem;
|
||||||
|
--button-backgroundColor: var(--color-layer-2);
|
||||||
|
--button-border: none;
|
||||||
|
--button-textColor: var(--color-text-0);
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
--button-backgroundColor: var(--color-layer-3);
|
||||||
|
--button-textColor: var(--color-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
Styled.WarningOutput = styled(Output)`
|
Styled.WarningOutput = styled(Output)`
|
||||||
color: var(--color-warning);
|
color: var(--color-warning);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Details = styled(Details)`
|
Styled.Details = styled(Details)`
|
||||||
${layoutMixins.scrollArea}
|
${layoutMixins.scrollArea}
|
||||||
|
font: var(--font-tiny-book);
|
||||||
padding: 0 0.5em;
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import { ButtonShape } from '@/constants/buttons';
|
|||||||
import { DialogTypes } from '@/constants/dialogs';
|
import { DialogTypes } from '@/constants/dialogs';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { AppRoute } from '@/constants/routes';
|
import { AppRoute } from '@/constants/routes';
|
||||||
import { useStringGetter } from '@/hooks';
|
|
||||||
import { LogoShortIcon, BellStrokeIcon } from '@/icons';
|
import { LogoShortIcon, BellStrokeIcon } from '@/icons';
|
||||||
|
|
||||||
|
import { useTokenConfigs, useStringGetter } from '@/hooks';
|
||||||
|
|
||||||
import { Icon, IconName } from '@/components/Icon';
|
import { Icon, IconName } from '@/components/Icon';
|
||||||
import { IconButton } from '@/components/IconButton';
|
import { IconButton } from '@/components/IconButton';
|
||||||
import { NavigationMenu } from '@/components/NavigationMenu';
|
import { NavigationMenu } from '@/components/NavigationMenu';
|
||||||
@@ -27,6 +28,7 @@ import { layoutMixins } from '@/styles/layoutMixins';
|
|||||||
export const HeaderDesktop = () => {
|
export const HeaderDesktop = () => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const { chainTokenLabel } = useTokenConfigs();
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{
|
{
|
||||||
@@ -43,9 +45,9 @@ export const HeaderDesktop = () => {
|
|||||||
href: AppRoute.Trade,
|
href: AppRoute.Trade,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'Dv4TNT',
|
value: chainTokenLabel,
|
||||||
label: 'Dv4TNT',
|
label: chainTokenLabel,
|
||||||
href: AppRoute.Rewards,
|
href: `/${chainTokenLabel}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'PORTFOLIO',
|
value: 'PORTFOLIO',
|
||||||
@@ -78,13 +80,13 @@ export const HeaderDesktop = () => {
|
|||||||
value: 'TERMS_OF_USE',
|
value: 'TERMS_OF_USE',
|
||||||
slotBefore: <Icon iconName={IconName.File} />,
|
slotBefore: <Icon iconName={IconName.File} />,
|
||||||
label: stringGetter({ key: STRING_KEYS.TERMS_OF_USE }),
|
label: stringGetter({ key: STRING_KEYS.TERMS_OF_USE }),
|
||||||
href: 'https://dydx.exchange/terms',
|
href: AppRoute.Terms,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'PRIVACY_POLICY',
|
value: 'PRIVACY_POLICY',
|
||||||
slotBefore: <Icon iconName={IconName.Privacy} />,
|
slotBefore: <Icon iconName={IconName.Privacy} />,
|
||||||
label: stringGetter({ key: STRING_KEYS.PRIVACY_POLICY }),
|
label: stringGetter({ key: STRING_KEYS.PRIVACY_POLICY }),
|
||||||
href: 'https://dydx.exchange/privacy',
|
href: AppRoute.Privacy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'HELP',
|
value: 'HELP',
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import {
|
|||||||
OrderSide,
|
OrderSide,
|
||||||
OrderTimeInForce,
|
OrderTimeInForce,
|
||||||
OrderExecution,
|
OrderExecution,
|
||||||
DYDX_DENOM,
|
|
||||||
GAS_PRICE_DYDX_DENOM,
|
|
||||||
} from '@dydxprotocol/v4-client-js';
|
} from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -66,16 +64,37 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const parsedParams = paramsInJson ? JSON.parse(paramsInJson) : {};
|
const parsedParams = paramsInJson ? JSON.parse(paramsInJson) : {};
|
||||||
const { indexerUrl, websocketUrl, validatorUrl, chainId } = parsedParams;
|
const {
|
||||||
|
indexerUrl,
|
||||||
|
websocketUrl,
|
||||||
|
validatorUrl,
|
||||||
|
chainId,
|
||||||
|
USDC_DENOM,
|
||||||
|
USDC_DECIMALS,
|
||||||
|
USDC_GAS_DENOM,
|
||||||
|
CHAINTOKEN_DENOM,
|
||||||
|
CHAINTOKEN_DECIMALS,
|
||||||
|
} = parsedParams;
|
||||||
|
|
||||||
const compositeClient = await CompositeClient.connect(
|
const compositeClient = await CompositeClient.connect(
|
||||||
new Network(
|
new Network(
|
||||||
chainId,
|
chainId,
|
||||||
new IndexerConfig(indexerUrl, websocketUrl),
|
new IndexerConfig(indexerUrl, websocketUrl),
|
||||||
new ValidatorConfig(validatorUrl, chainId, {
|
new ValidatorConfig(
|
||||||
broadcastPollIntervalMs: 3_000,
|
validatorUrl,
|
||||||
broadcastTimeoutMs: 60_000,
|
chainId,
|
||||||
})
|
{
|
||||||
|
USDC_DENOM,
|
||||||
|
USDC_DECIMALS,
|
||||||
|
USDC_GAS_DENOM,
|
||||||
|
CHAINTOKEN_DENOM,
|
||||||
|
CHAINTOKEN_DECIMALS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
broadcastPollIntervalMs: 3_000,
|
||||||
|
broadcastTimeoutMs: 60_000,
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -204,13 +223,13 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
|||||||
params ?? {};
|
params ?? {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const tx = await this.compositeClient?.cancelOrder(
|
const tx = await this.compositeClient?.cancelRawOrder(
|
||||||
new SubaccountClient(this.localWallet, subaccountNumber),
|
new SubaccountClient(this.localWallet, subaccountNumber),
|
||||||
clientId,
|
clientId,
|
||||||
orderFlags,
|
orderFlags,
|
||||||
clobPairId,
|
clobPairId,
|
||||||
goodTilBlock ?? undefined,
|
goodTilBlock || undefined,
|
||||||
goodTilBlockTime ?? undefined
|
goodTilBlockTime || undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
const parsedTx = this.parseToPrimitives(tx);
|
const parsedTx = this.parseToPrimitives(tx);
|
||||||
@@ -273,16 +292,18 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
|||||||
this.localWallet,
|
this.localWallet,
|
||||||
() =>
|
() =>
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
const msg = compositeClient?.validatorClient.post.composer.composeMsgSendToken(
|
if (!this.localWallet) {
|
||||||
subaccountClient.address,
|
throw new Error('Missing compositeClient or localWallet');
|
||||||
|
}
|
||||||
|
const msg = compositeClient?.sendTokenMessage(
|
||||||
|
this.localWallet,
|
||||||
|
amount,
|
||||||
recipient,
|
recipient,
|
||||||
DYDX_DENOM,
|
|
||||||
Long.fromNumber(amount * QUANTUM_MULTIPLIER)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
resolve([msg]);
|
resolve([msg]);
|
||||||
}),
|
}),
|
||||||
GAS_PRICE_DYDX_DENOM
|
this.compositeClient?.validatorClient?.post.defaultDydxGasPrice,
|
||||||
);
|
);
|
||||||
|
|
||||||
const parsedTx = this.parseToPrimitives(tx);
|
const parsedTx = this.parseToPrimitives(tx);
|
||||||
|
|||||||
+33
-13
@@ -95,15 +95,28 @@ const injectedConnectorOptions = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const walletconnect2ConnectorOptions: ConstructorParameters<typeof WalletConnectConnector>[0] = {
|
type WalletConnectConfig = {
|
||||||
|
client: {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
iconUrl: string;
|
||||||
|
};
|
||||||
|
v2: {
|
||||||
|
projectId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getWalletconnect2ConnectorOptions = (
|
||||||
|
config: WalletConnectConfig
|
||||||
|
): ConstructorParameters<typeof WalletConnectConnector>[0] => ({
|
||||||
chains,
|
chains,
|
||||||
options: {
|
options: {
|
||||||
projectId: import.meta.env.VITE_WALLETCONNECT2_PROJECT_ID,
|
projectId: config.v2.projectId,
|
||||||
metadata: {
|
metadata: {
|
||||||
name: 'dYdX',
|
name: config.client.name,
|
||||||
description: '',
|
description: config.client.description,
|
||||||
url: import.meta.env.VITE_BASE_URL,
|
url: import.meta.env.VITE_BASE_URL,
|
||||||
icons: [`${import.meta.env.VITE_BASE_URL}/cbw-image.png}`],
|
icons: [config.client.iconUrl],
|
||||||
},
|
},
|
||||||
showQrModal: true,
|
showQrModal: true,
|
||||||
qrModalOptions: {
|
qrModalOptions: {
|
||||||
@@ -115,9 +128,9 @@ const walletconnect2ConnectorOptions: ConstructorParameters<typeof WalletConnect
|
|||||||
explorerRecommendedWalletIds: WALLET_CONNECT_EXPLORER_RECOMMENDED_IDS,
|
explorerRecommendedWalletIds: WALLET_CONNECT_EXPLORER_RECOMMENDED_IDS,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
|
|
||||||
const connectors = [
|
const getConnectors = (walletConnectConfig: WalletConnectConfig) => [
|
||||||
new MetaMaskConnector({
|
new MetaMaskConnector({
|
||||||
chains,
|
chains,
|
||||||
options: {
|
options: {
|
||||||
@@ -131,7 +144,7 @@ const connectors = [
|
|||||||
reloadOnDisconnect: false,
|
reloadOnDisconnect: false,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
new WalletConnectConnector(walletconnect2ConnectorOptions),
|
new WalletConnectConnector(getWalletconnect2ConnectorOptions(walletConnectConfig)),
|
||||||
new InjectedConnector(injectedConnectorOptions),
|
new InjectedConnector(injectedConnectorOptions),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -153,27 +166,34 @@ const createInjectedConnectorWithProvider = (provider: ExternalProvider) =>
|
|||||||
provider as unknown as Awaited<ReturnType<InjectedConnector['getProvider']>>;
|
provider as unknown as Awaited<ReturnType<InjectedConnector['getProvider']>>;
|
||||||
})(injectedConnectorOptions) as InjectedConnector;
|
})(injectedConnectorOptions) as InjectedConnector;
|
||||||
|
|
||||||
const createWalletConnect2ConnectorWithId = (walletconnect2Id: string) =>
|
const createWalletConnect2ConnectorWithId = (
|
||||||
new WalletConnectConnector({
|
walletconnectId: string,
|
||||||
|
walletConnectConfig: WalletConnectConfig
|
||||||
|
) => {
|
||||||
|
const walletconnect2ConnectorOptions = getWalletconnect2ConnectorOptions(walletConnectConfig);
|
||||||
|
return new WalletConnectConnector({
|
||||||
...walletconnect2ConnectorOptions,
|
...walletconnect2ConnectorOptions,
|
||||||
options: {
|
options: {
|
||||||
...walletconnect2ConnectorOptions.options,
|
...walletconnect2ConnectorOptions.options,
|
||||||
qrModalOptions: {
|
qrModalOptions: {
|
||||||
...walletconnect2ConnectorOptions.options.qrModalOptions,
|
...walletconnect2ConnectorOptions.options.qrModalOptions,
|
||||||
explorerRecommendedWalletIds: [walletconnect2Id],
|
explorerRecommendedWalletIds: [walletconnectId],
|
||||||
explorerExcludedWalletIds: 'ALL',
|
explorerExcludedWalletIds: 'ALL',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Custom connector from wallet selection
|
// Custom connector from wallet selection
|
||||||
|
|
||||||
export const resolveWagmiConnector = ({
|
export const resolveWagmiConnector = ({
|
||||||
walletType,
|
walletType,
|
||||||
walletConnection,
|
walletConnection,
|
||||||
|
walletConnectConfig,
|
||||||
}: {
|
}: {
|
||||||
walletType: WalletType;
|
walletType: WalletType;
|
||||||
walletConnection: WalletConnection;
|
walletConnection: WalletConnection;
|
||||||
|
walletConnectConfig: WalletConnectConfig;
|
||||||
}) => {
|
}) => {
|
||||||
const walletConfig = wallets[walletType];
|
const walletConfig = wallets[walletType];
|
||||||
const walletConnectionConfig = walletConnectionTypes[walletConnection.type];
|
const walletConnectionConfig = walletConnectionTypes[walletConnection.type];
|
||||||
@@ -181,6 +201,6 @@ export const resolveWagmiConnector = ({
|
|||||||
return walletConnection.type === WalletConnectionType.InjectedEip1193 && walletConnection.provider
|
return walletConnection.type === WalletConnectionType.InjectedEip1193 && walletConnection.provider
|
||||||
? createInjectedConnectorWithProvider(walletConnection.provider)
|
? createInjectedConnectorWithProvider(walletConnection.provider)
|
||||||
: walletConnection.type === WalletConnectionType.WalletConnect2 && walletConfig.walletconnect2Id
|
: walletConnection.type === WalletConnectionType.WalletConnect2 && walletConfig.walletconnect2Id
|
||||||
? createWalletConnect2ConnectorWithId(walletConfig.walletconnect2Id)
|
? createWalletConnect2ConnectorWithId(walletConfig.walletconnect2Id, walletConnectConfig)
|
||||||
: connectors.find(({ id }: { id: string }) => id === walletConnectionConfig.wagmiConnectorId);
|
: getConnectors(walletConnectConfig).find(({ id }: { id: string }) => id === walletConnectionConfig.wagmiConnectorId);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
|
|
||||||
|
import { articleMixins } from '@/styles/articleMixins';
|
||||||
|
|
||||||
|
export const PrivacyPolicyPage = () => (
|
||||||
|
<Styled.Article>
|
||||||
|
<header>
|
||||||
|
<h1>Privacy Policy</h1>
|
||||||
|
</header>
|
||||||
|
</Styled.Article>
|
||||||
|
);
|
||||||
|
|
||||||
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
|
Styled.Article = styled.article`
|
||||||
|
${articleMixins.article}
|
||||||
|
`;
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
|
|
||||||
|
import { articleMixins } from '@/styles/articleMixins';
|
||||||
|
|
||||||
|
export const TermsOfUsePage = () => (
|
||||||
|
<Styled.Article>
|
||||||
|
<header>
|
||||||
|
<h1>Terms of Use</h1>
|
||||||
|
</header>
|
||||||
|
</Styled.Article>
|
||||||
|
);
|
||||||
|
|
||||||
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
|
Styled.Article = styled.article`
|
||||||
|
${articleMixins.article}
|
||||||
|
`;
|
||||||
@@ -3,7 +3,7 @@ import styled, { AnyStyledComponent } from 'styled-components';
|
|||||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
import { useAccountBalance, useAccounts, useStringGetter } from '@/hooks';
|
import { useAccountBalance, useAccounts, useTokenConfigs, useStringGetter } from '@/hooks';
|
||||||
|
|
||||||
import { ButtonAction, ButtonSize } from '@/constants/buttons';
|
import { ButtonAction, ButtonSize } from '@/constants/buttons';
|
||||||
import { DialogTypes } from '@/constants/dialogs';
|
import { DialogTypes } from '@/constants/dialogs';
|
||||||
@@ -30,6 +30,7 @@ export const DYDXBalancePanel = () => {
|
|||||||
const { walletType } = useAccounts();
|
const { walletType } = useAccounts();
|
||||||
const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual);
|
const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual);
|
||||||
const { nativeTokenBalance, nativeStakingBalance } = useAccountBalance();
|
const { nativeTokenBalance, nativeStakingBalance } = useAccountBalance();
|
||||||
|
const { chainTokenLabel } = useTokenConfigs();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Panel
|
<Panel
|
||||||
@@ -37,7 +38,7 @@ export const DYDXBalancePanel = () => {
|
|||||||
<Styled.Header>
|
<Styled.Header>
|
||||||
<Styled.Title>
|
<Styled.Title>
|
||||||
{/* <AssetIcon symbol="DYDX" /> */}
|
{/* <AssetIcon symbol="DYDX" /> */}
|
||||||
Dv4TNT
|
{chainTokenLabel}
|
||||||
</Styled.Title>
|
</Styled.Title>
|
||||||
<Styled.ReceiveAndTransferButtons>
|
<Styled.ReceiveAndTransferButtons>
|
||||||
{!canAccountTrade ? (
|
{!canAccountTrade ? (
|
||||||
@@ -106,7 +107,13 @@ export const DYDXBalancePanel = () => {
|
|||||||
{
|
{
|
||||||
key: 'totalBalance',
|
key: 'totalBalance',
|
||||||
label: 'Total balance',
|
label: 'Total balance',
|
||||||
value: <Output type={OutputType.Asset} value={nativeTokenBalance + nativeStakingBalance} tag="Dv4TNT" />,
|
value: (
|
||||||
|
<Output
|
||||||
|
type={OutputType.Asset}
|
||||||
|
value={nativeTokenBalance + nativeStakingBalance}
|
||||||
|
tag={chainTokenLabel}
|
||||||
|
/>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
@@ -174,7 +181,6 @@ Styled.WalletAndStakedBalance = styled(Details)`
|
|||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
|
||||||
|
|||||||
@@ -13,4 +13,6 @@ declare global {
|
|||||||
|
|
||||||
'abacus:connectNetwork': CustomEvent;
|
'abacus:connectNetwork': CustomEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var Intercom: any;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ export const dialogsSlice = createSlice({
|
|||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
openDialog: (state: DialogsState, action: PayloadAction<DialogInfo<DialogTypes>>) => {
|
openDialog: (state: DialogsState, action: PayloadAction<DialogInfo<DialogTypes>>) => {
|
||||||
|
if (state.activeDialog?.type === action.payload.type) return;
|
||||||
|
|
||||||
if (state.activeDialog) {
|
if (state.activeDialog) {
|
||||||
state.dialogQueue.push(action.payload);
|
state.dialogQueue.push(action.payload);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import {
|
||||||
|
css,
|
||||||
|
type FlattenInterpolation,
|
||||||
|
type FlattenSimpleInterpolation,
|
||||||
|
type ThemeProps,
|
||||||
|
} from 'styled-components';
|
||||||
|
|
||||||
|
export const articleMixins: Record<
|
||||||
|
string,
|
||||||
|
FlattenSimpleInterpolation | FlattenInterpolation<ThemeProps<any>>
|
||||||
|
> = {
|
||||||
|
article: css`
|
||||||
|
padding: 2rem;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
user-select: text;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 60rem;
|
||||||
|
max-width: 100vw;
|
||||||
|
|
||||||
|
header {
|
||||||
|
color: var(--color-text-0);
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font: var(--font-extra-book);
|
||||||
|
color: var(--color-text-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font: var(--font-large-book);
|
||||||
|
color: var(--color-text-2);
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3,
|
||||||
|
strong {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: var(--color-text-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
@@ -36,11 +36,10 @@
|
|||||||
--single-unit-height: 9.375rem;
|
--single-unit-height: 9.375rem;
|
||||||
|
|
||||||
/* Modal constants */
|
/* Modal constants */
|
||||||
--sidebar-modal-width: 18.75rem;
|
--dialog-small-width: 18.75rem;
|
||||||
--modal-small-width: 18.75rem;
|
--dialog-medium-width: 20.5rem;
|
||||||
--modal-medium-width: 20.5rem;
|
--dialog-large-width: 26.25rem;
|
||||||
--modal-large-width: 26.25rem;
|
--dialog-header-height: 4rem;
|
||||||
--modal-header-height: 4rem;
|
|
||||||
|
|
||||||
/* Market Selector constants */
|
/* Market Selector constants */
|
||||||
--marketsDropdown-openWidth: 45rem;
|
--marketsDropdown-openWidth: 45rem;
|
||||||
|
|||||||
@@ -188,13 +188,14 @@ export const popoverMixins = {
|
|||||||
--item-highlighted-backgroundColor: var(--color-layer-2);
|
--item-highlighted-backgroundColor: var(--color-layer-2);
|
||||||
--item-highlighted-textColor: var(--color-text-2);
|
--item-highlighted-textColor: var(--color-text-2);
|
||||||
|
|
||||||
|
--item-gap: 0.5em;
|
||||||
--item-radius: 0px;
|
--item-radius: 0px;
|
||||||
--item-padding: 0.5em 1em;
|
--item-padding: 0.5em 1em;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5em;
|
gap: var(--item-gap);
|
||||||
|
|
||||||
padding: var(--item-padding);
|
padding: var(--item-padding);
|
||||||
border-radius: var(--item-radius);
|
border-radius: var(--item-radius);
|
||||||
|
|||||||
@@ -75,16 +75,14 @@ export const AccountInfoConnectedState = () => {
|
|||||||
<Styled.Header>
|
<Styled.Header>
|
||||||
<span>{stringGetter({ key: STRING_KEYS.ACCOUNT })}</span>
|
<span>{stringGetter({ key: STRING_KEYS.ACCOUNT })}</span>
|
||||||
<Styled.TransferButtons>
|
<Styled.TransferButtons>
|
||||||
{import.meta.env.MODE !== 'production' && (
|
<Styled.Button
|
||||||
<Styled.Button
|
state={{ isDisabled: !dydxAccounts }}
|
||||||
state={{ isDisabled: !dydxAccounts }}
|
onClick={() => dispatch(openDialog({ type: DialogTypes.Withdraw }))}
|
||||||
onClick={() => dispatch(openDialog({ type: DialogTypes.Withdraw }))}
|
shape={ButtonShape.Pill}
|
||||||
shape={ButtonShape.Pill}
|
size={ButtonSize.XSmall}
|
||||||
size={ButtonSize.XSmall}
|
>
|
||||||
>
|
{stringGetter({ key: STRING_KEYS.WITHDRAW })}
|
||||||
{stringGetter({ key: STRING_KEYS.WITHDRAW })}
|
</Styled.Button>
|
||||||
</Styled.Button>
|
|
||||||
)}
|
|
||||||
<Styled.Button
|
<Styled.Button
|
||||||
state={{ isDisabled: !dydxAccounts }}
|
state={{ isDisabled: !dydxAccounts }}
|
||||||
onClick={() => dispatch(openDialog({ type: DialogTypes.Deposit }))}
|
onClick={() => dispatch(openDialog({ type: DialogTypes.Deposit }))}
|
||||||
|
|||||||
@@ -32,12 +32,9 @@ export const DepositDialog = ({ setIsOpen }: ElementProps) => {
|
|||||||
>
|
>
|
||||||
<Styled.Content>
|
<Styled.Content>
|
||||||
{showTestDeposit ? <TestnetDepositForm onDeposit={closeDialog} /> : <DepositForm />}
|
{showTestDeposit ? <TestnetDepositForm onDeposit={closeDialog} /> : <DepositForm />}
|
||||||
{/* TODO TRCL-1693 - uncomment when deposit form is ready */}
|
<Styled.TextToggle onClick={() => setShowTestDeposit(!showTestDeposit)}>
|
||||||
{import.meta.env.MODE !== 'production' && (
|
{showTestDeposit ? 'Show deposit form (Under Construction)' : 'Show test faucet'}
|
||||||
<Styled.TextToggle onClick={() => setShowTestDeposit(!showTestDeposit)}>
|
</Styled.TextToggle>
|
||||||
{showTestDeposit ? 'Show deposit form (Under Construction)' : 'Show test faucet'}
|
|
||||||
</Styled.TextToggle>
|
|
||||||
)}
|
|
||||||
</Styled.Content>
|
</Styled.Content>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
|||||||
import { AbacusApiStatus } from '@/constants/abacus';
|
import { AbacusApiStatus } from '@/constants/abacus';
|
||||||
import { DialogTypes } from '@/constants/dialogs';
|
import { DialogTypes } from '@/constants/dialogs';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
|
||||||
import { UNICODE } from '@/constants/unicode';
|
|
||||||
|
|
||||||
import { useApiState, useStringGetter } from '@/hooks';
|
import { useApiState, useStringGetter } from '@/hooks';
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
@@ -32,16 +30,8 @@ export const ExchangeOfflineDialog = ({ preventClose, setIsOpen }: ElementProps)
|
|||||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||||
const activeDialog = useSelector(getActiveDialog, shallowEqual);
|
const activeDialog = useSelector(getActiveDialog, shallowEqual);
|
||||||
|
|
||||||
const showOfflineMessage =
|
|
||||||
import.meta.env.MODE === 'production' &&
|
|
||||||
ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId === 'dydx-testnet-4';
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (activeDialog?.type === DialogTypes.ExchangeOffline && status === AbacusApiStatus.NORMAL) {
|
||||||
activeDialog?.type === DialogTypes.ExchangeOffline &&
|
|
||||||
status === AbacusApiStatus.NORMAL &&
|
|
||||||
!showOfflineMessage
|
|
||||||
) {
|
|
||||||
dispatch(closeDialog());
|
dispatch(closeDialog());
|
||||||
}
|
}
|
||||||
}, [status, selectedNetwork]);
|
}, [status, selectedNetwork]);
|
||||||
@@ -54,16 +44,7 @@ export const ExchangeOfflineDialog = ({ preventClose, setIsOpen }: ElementProps)
|
|||||||
title={stringGetter({ key: STRING_KEYS.UNAVAILABLE })}
|
title={stringGetter({ key: STRING_KEYS.UNAVAILABLE })}
|
||||||
>
|
>
|
||||||
<Styled.Content>
|
<Styled.Content>
|
||||||
{showOfflineMessage ? (
|
<p>{statusErrorMessage}</p>
|
||||||
<>
|
|
||||||
<p>Testnet is currently offline. Please check back!</p>
|
|
||||||
<Styled.Link href="https://v4-teacher.vercel.app/testnets/schedule">
|
|
||||||
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} {UNICODE.ARROW_RIGHT}
|
|
||||||
</Styled.Link>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<p>{statusErrorMessage}</p>
|
|
||||||
)}
|
|
||||||
{import.meta.env.MODE !== 'production' && <NetworkSelectMenu />}
|
{import.meta.env.MODE !== 'production' && <NetworkSelectMenu />}
|
||||||
</Styled.Content>
|
</Styled.Content>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@@ -1,69 +1,94 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
import styled, { AnyStyledComponent } from 'styled-components';
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
import { useDispatch } from 'react-redux';
|
|
||||||
import { Close } from '@radix-ui/react-dialog';
|
|
||||||
|
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { useStringGetter } from '@/hooks';
|
import { useStringGetter } from '@/hooks';
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { ChatIcon, FeedbackIcon, FileIcon, TerminalIcon } from '@/icons';
|
||||||
|
|
||||||
import { Button } from '@/components/Button';
|
import { ComboboxDialogMenu } from '@/components/ComboboxDialogMenu';
|
||||||
import { Dialog } from '@/components/Dialog';
|
|
||||||
import { ButtonAction, ButtonType } from '@/constants/buttons';
|
import { isTruthy } from '@/lib/isTruthy';
|
||||||
import { Icon, IconName } from '@/components/Icon';
|
|
||||||
|
|
||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
setIsOpen: (open: boolean) => void;
|
setIsOpen: (open: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const HELP_URL = `https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform?usp=sf_link`;
|
const HELP_LINKS = {
|
||||||
|
apiDocumentation: 'https://v4-teacher.vercel.app/',
|
||||||
|
helpCenter: null,
|
||||||
|
feedback: null,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* HelpDialog
|
|
||||||
* - Will temporarily be used as a 'Give Feedback' dialog.
|
|
||||||
* - It will ask users to navigate to a Google Form in order to record feedback.
|
|
||||||
*/
|
|
||||||
export const HelpDialog = ({ setIsOpen }: ElementProps) => {
|
export const HelpDialog = ({ setIsOpen }: ElementProps) => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
|
|
||||||
|
const HELP_ITEMS = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
group: 'help-items',
|
||||||
|
items: [
|
||||||
|
HELP_LINKS.helpCenter && {
|
||||||
|
value: 'help-center',
|
||||||
|
label: stringGetter({ key: STRING_KEYS.HELP_CENTER }),
|
||||||
|
description: stringGetter({ key: STRING_KEYS.HELP_CENTER_DESCRIPTION }),
|
||||||
|
onSelect: () => {
|
||||||
|
HELP_LINKS.helpCenter && globalThis.open(HELP_LINKS.helpCenter, '_blank');
|
||||||
|
setIsOpen(false);
|
||||||
|
},
|
||||||
|
slotBefore: <FileIcon />,
|
||||||
|
},
|
||||||
|
HELP_LINKS.apiDocumentation && {
|
||||||
|
value: 'api-documentation',
|
||||||
|
label: stringGetter({ key: STRING_KEYS.API_DOCUMENTATION }),
|
||||||
|
description: stringGetter({ key: STRING_KEYS.API_DOCUMENTATION_DESCRIPTION }),
|
||||||
|
onSelect: () => {
|
||||||
|
HELP_LINKS.apiDocumentation && globalThis.open(HELP_LINKS.apiDocumentation, '_blank');
|
||||||
|
setIsOpen(false);
|
||||||
|
},
|
||||||
|
slotBefore: <TerminalIcon />,
|
||||||
|
},
|
||||||
|
globalThis?.Intercom && {
|
||||||
|
value: 'live-chat',
|
||||||
|
label: stringGetter({ key: STRING_KEYS.LIVE_CHAT }),
|
||||||
|
description: stringGetter({ key: STRING_KEYS.LIVE_CHAT_DESCRIPTION }),
|
||||||
|
onSelect: () => {
|
||||||
|
globalThis.Intercom('show');
|
||||||
|
setIsOpen(false);
|
||||||
|
},
|
||||||
|
slotBefore: <ChatIcon />,
|
||||||
|
},
|
||||||
|
HELP_LINKS.feedback && {
|
||||||
|
value: 'feedback',
|
||||||
|
label: stringGetter({ key: STRING_KEYS.PROVIDE_FEEDBACK }),
|
||||||
|
description: stringGetter({ key: STRING_KEYS.PROVIDE_FEEDBACK_DESCRIPTION }),
|
||||||
|
onSelect: () => {
|
||||||
|
HELP_LINKS.feedback && globalThis.open(HELP_LINKS.feedback, '_blank');
|
||||||
|
setIsOpen(false);
|
||||||
|
},
|
||||||
|
slotBefore: <FeedbackIcon />,
|
||||||
|
},
|
||||||
|
].filter(isTruthy),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[stringGetter]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Styled.ComboboxDialogMenu
|
||||||
isOpen
|
isOpen
|
||||||
|
withSearch={false}
|
||||||
setIsOpen={setIsOpen}
|
setIsOpen={setIsOpen}
|
||||||
title={stringGetter({ key: STRING_KEYS.PROVIDE_FEEDBACK })}
|
title={stringGetter({ key: STRING_KEYS.HELP })}
|
||||||
description={stringGetter({ key: STRING_KEYS.PROVIDE_FEEDBACK_DESCRIPTION })}
|
items={HELP_ITEMS}
|
||||||
>
|
/>
|
||||||
<Styled.Content>
|
|
||||||
<p>
|
|
||||||
You will be navigated to a Google Form where you will be able to provide feedback. Thank
|
|
||||||
you for your contribution!
|
|
||||||
</p>
|
|
||||||
<Styled.ButtonRow>
|
|
||||||
<Close asChild>
|
|
||||||
<Button
|
|
||||||
action={ButtonAction.Primary}
|
|
||||||
type={ButtonType.Link}
|
|
||||||
href={HELP_URL}
|
|
||||||
slotRight={<Icon iconName={IconName.LinkOut} />}
|
|
||||||
>
|
|
||||||
{stringGetter({ key: STRING_KEYS.CONTINUE })}
|
|
||||||
</Button>
|
|
||||||
</Close>
|
|
||||||
</Styled.ButtonRow>
|
|
||||||
</Styled.Content>
|
|
||||||
</Dialog>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Styled: Record<string, AnyStyledComponent> = {};
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
Styled.ButtonRow = styled.div`
|
Styled.ComboboxDialogMenu = styled(ComboboxDialogMenu)`
|
||||||
${layoutMixins.row}
|
--dialog-width: var(--dialog-small-width);
|
||||||
|
--dialog-content-paddingTop: 1rem;
|
||||||
gap: 0.5rem;
|
--dialog-content-paddingBottom: 1rem;
|
||||||
justify-content: end;
|
--comboxDialogMenu-item-gap: 1rem;
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Content = styled.div`
|
|
||||||
${layoutMixins.column}
|
|
||||||
gap: 1rem;
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export const OnboardingDialog = ({ setIsOpen }: ElementProps) => {
|
|||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const { isMobile } = useBreakpoints();
|
const { isMobile } = useBreakpoints();
|
||||||
|
|
||||||
const { walletType } = useAccounts();
|
const { disconnect, walletType } = useAccounts();
|
||||||
|
|
||||||
const currentOnboardingStep = useSelector(calculateOnboardingStep);
|
const currentOnboardingStep = useSelector(calculateOnboardingStep);
|
||||||
|
|
||||||
@@ -45,10 +45,17 @@ export const OnboardingDialog = ({ setIsOpen }: ElementProps) => {
|
|||||||
if (!currentOnboardingStep) setIsOpen?.(false);
|
if (!currentOnboardingStep) setIsOpen?.(false);
|
||||||
}, [currentOnboardingStep]);
|
}, [currentOnboardingStep]);
|
||||||
|
|
||||||
|
const setIsOpenFromDialog = (open: boolean) => {
|
||||||
|
if (!open && currentOnboardingStep === OnboardingSteps.AcknowledgeTerms) {
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
setIsOpen?.(open);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Styled.Dialog
|
<Styled.Dialog
|
||||||
isOpen={Boolean(currentOnboardingStep)}
|
isOpen={Boolean(currentOnboardingStep)}
|
||||||
setIsOpen={setIsOpen}
|
setIsOpen={setIsOpenFromDialog}
|
||||||
{...(currentOnboardingStep &&
|
{...(currentOnboardingStep &&
|
||||||
{
|
{
|
||||||
[OnboardingSteps.ChooseWallet]: {
|
[OnboardingSteps.ChooseWallet]: {
|
||||||
@@ -87,10 +94,10 @@ export const OnboardingDialog = ({ setIsOpen }: ElementProps) => {
|
|||||||
title: stringGetter({ key: STRING_KEYS.ACKNOWLEDGE_TERMS }),
|
title: stringGetter({ key: STRING_KEYS.ACKNOWLEDGE_TERMS }),
|
||||||
children: (
|
children: (
|
||||||
<Styled.Content>
|
<Styled.Content>
|
||||||
<AcknowledgeTerms />
|
<AcknowledgeTerms onClose={() => setIsOpenFromDialog?.(false)} />
|
||||||
</Styled.Content>
|
</Styled.Content>
|
||||||
),
|
),
|
||||||
width: '20rem',
|
width: '30rem',
|
||||||
},
|
},
|
||||||
[OnboardingSteps.DepositFunds]: {
|
[OnboardingSteps.DepositFunds]: {
|
||||||
title: stringGetter({ key: STRING_KEYS.DEPOSIT }),
|
title: stringGetter({ key: STRING_KEYS.DEPOSIT }),
|
||||||
|
|||||||
@@ -2,17 +2,21 @@ import styled, { type AnyStyledComponent } from 'styled-components';
|
|||||||
|
|
||||||
import { useAccounts, useStringGetter } from '@/hooks';
|
import { useAccounts, useStringGetter } from '@/hooks';
|
||||||
|
|
||||||
|
import { AppRoute } from '@/constants/routes';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { ButtonAction } from '@/constants/buttons';
|
import { ButtonAction } from '@/constants/buttons';
|
||||||
|
|
||||||
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
import { Button } from '@/components/Button';
|
import { Button } from '@/components/Button';
|
||||||
import { Link } from '@/components/Link';
|
import { Link } from '@/components/Link';
|
||||||
|
|
||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
|
onClose?: () => void;
|
||||||
onContinue?: () => void;
|
onContinue?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AcknowledgeTerms = ({ onContinue }: ElementProps) => {
|
export const AcknowledgeTerms = ({ onClose, onContinue }: ElementProps) => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
|
|
||||||
const { saveHasAcknowledgedTerms } = useAccounts();
|
const { saveHasAcknowledgedTerms } = useAccounts();
|
||||||
@@ -24,26 +28,40 @@ export const AcknowledgeTerms = ({ onContinue }: ElementProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span>
|
<p>
|
||||||
{stringGetter({
|
{stringGetter({
|
||||||
key: STRING_KEYS.LEGAL_UPDATES_DESCRIPTION,
|
key: STRING_KEYS.TOS_TITLE,
|
||||||
params: {
|
params: {
|
||||||
TOU: (
|
TERMS_LINK: (
|
||||||
<Styled.Link href="https://dydx.exchange/v4-terms">
|
<Styled.Link href={`/#${AppRoute.Terms}`}>
|
||||||
{stringGetter({ key: STRING_KEYS.TERMS_OF_USE })}
|
{stringGetter({ key: STRING_KEYS.TERMS_OF_USE })}
|
||||||
</Styled.Link>
|
</Styled.Link>
|
||||||
),
|
),
|
||||||
PRIVACY_POLICY: (
|
PRIVACY_POLICY_LINK: (
|
||||||
<Styled.Link href="https://dydx.exchange/privacy">
|
<Styled.Link href={`/#${AppRoute.Privacy}`}>
|
||||||
{stringGetter({ key: STRING_KEYS.PRIVACY_POLICY })}
|
{stringGetter({ key: STRING_KEYS.PRIVACY_POLICY })}
|
||||||
</Styled.Link>
|
</Styled.Link>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
</span>
|
</p>
|
||||||
<Button onClick={onAcknowledgement} action={ButtonAction.Primary}>
|
<Styled.TOS>
|
||||||
{stringGetter({ key: STRING_KEYS.I_AGREE })}
|
<ul>
|
||||||
</Button>
|
<li>{stringGetter({ key: STRING_KEYS.TOS_LINE1 })}</li>
|
||||||
|
<li>{stringGetter({ key: STRING_KEYS.TOS_LINE2 })}</li>
|
||||||
|
<li>{stringGetter({ key: STRING_KEYS.TOS_LINE3 })}</li>
|
||||||
|
<li>{stringGetter({ key: STRING_KEYS.TOS_LINE4 })}</li>
|
||||||
|
<li>{stringGetter({ key: STRING_KEYS.TOS_LINE5 })}</li>
|
||||||
|
</ul>
|
||||||
|
</Styled.TOS>
|
||||||
|
<Styled.Row>
|
||||||
|
<Styled.Button onClick={onClose} action={ButtonAction.Base}>
|
||||||
|
{stringGetter({ key: STRING_KEYS.CLOSE })}
|
||||||
|
</Styled.Button>
|
||||||
|
<Styled.Button onClick={onAcknowledgement} action={ButtonAction.Primary}>
|
||||||
|
{stringGetter({ key: STRING_KEYS.I_AGREE })}
|
||||||
|
</Styled.Button>
|
||||||
|
</Styled.Row>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -58,3 +76,23 @@ Styled.Link = styled(Link)`
|
|||||||
color: var(--color-accent);
|
color: var(--color-accent);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
Styled.TOS = styled.section`
|
||||||
|
background-color: var(--color-layer-4);
|
||||||
|
padding: 1rem 1rem 1rem 2rem;
|
||||||
|
border-radius: 0.875rem;
|
||||||
|
> ul {
|
||||||
|
${layoutMixins.column};
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Row = styled.div`
|
||||||
|
${layoutMixins.row};
|
||||||
|
|
||||||
|
gap: 1rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Button = styled(Button)`
|
||||||
|
flex-grow: 1;
|
||||||
|
`;
|
||||||
|
|||||||
@@ -264,7 +264,6 @@ const Styled: Record<string, AnyStyledComponent> = {};
|
|||||||
|
|
||||||
Styled.StatusCardsContainer = styled.div`
|
Styled.StatusCardsContainer = styled.div`
|
||||||
display: grid;
|
display: grid;
|
||||||
margin-top: 1rem;
|
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { DydxChainAsset } from '@/constants/wallets';
|
|||||||
|
|
||||||
import { formMixins } from '@/styles/formMixins';
|
import { formMixins } from '@/styles/formMixins';
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
import { useAccounts, useStringGetter } from '@/hooks';
|
import { useAccounts, useTokenConfigs, useStringGetter } from '@/hooks';
|
||||||
|
|
||||||
import { AssetIcon } from '@/components/AssetIcon';
|
import { AssetIcon } from '@/components/AssetIcon';
|
||||||
import { CopyButton } from '@/components/CopyButton';
|
import { CopyButton } from '@/components/CopyButton';
|
||||||
@@ -24,9 +24,10 @@ type ElementProps = {
|
|||||||
setIsOpen: (open: boolean) => void;
|
setIsOpen: (open: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ReceiveDialog = ({ selectedAsset = DydxChainAsset.DYDX, setIsOpen }: ElementProps) => {
|
export const ReceiveDialog = ({ selectedAsset = DydxChainAsset.CHAINTOKEN, setIsOpen }: ElementProps) => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const { dydxAddress } = useAccounts();
|
const { dydxAddress } = useAccounts();
|
||||||
|
const { chainTokenLabel, usdcLabel } = useTokenConfigs();
|
||||||
|
|
||||||
const [asset, setAsset] = useState(selectedAsset);
|
const [asset, setAsset] = useState(selectedAsset);
|
||||||
|
|
||||||
@@ -35,16 +36,17 @@ export const ReceiveDialog = ({ selectedAsset = DydxChainAsset.DYDX, setIsOpen }
|
|||||||
value: DydxChainAsset.USDC,
|
value: DydxChainAsset.USDC,
|
||||||
label: (
|
label: (
|
||||||
<Styled.InlineRow>
|
<Styled.InlineRow>
|
||||||
<AssetIcon symbol="USDC" /> USDC
|
<AssetIcon symbol="USDC" /> {usdcLabel}
|
||||||
</Styled.InlineRow>
|
</Styled.InlineRow>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: DydxChainAsset.DYDX,
|
value: DydxChainAsset.CHAINTOKEN,
|
||||||
label: (
|
label: (
|
||||||
<Styled.InlineRow>
|
<Styled.InlineRow>
|
||||||
|
{/* TODO: conditionally display the native token assetIcon */}
|
||||||
{/* <AssetIcon symbol="DYDX" /> */}
|
{/* <AssetIcon symbol="DYDX" /> */}
|
||||||
Dv4TNT
|
{chainTokenLabel}
|
||||||
</Styled.InlineRow>
|
</Styled.InlineRow>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,11 +11,7 @@ import { ButtonShape, ButtonSize } from '@/constants/buttons';
|
|||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||||
import { NumberSign } from '@/constants/numbers';
|
import { NumberSign } from '@/constants/numbers';
|
||||||
import {
|
import { DydxChainAsset } from '@/constants/wallets';
|
||||||
DYDX_CHAIN_ASSET_COIN_DENOM,
|
|
||||||
DYDX_CHAIN_ASSET_TAGS,
|
|
||||||
DydxChainAsset,
|
|
||||||
} from '@/constants/wallets';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useAccountBalance,
|
useAccountBalance,
|
||||||
@@ -25,6 +21,7 @@ import {
|
|||||||
useSelectedNetwork,
|
useSelectedNetwork,
|
||||||
useStringGetter,
|
useStringGetter,
|
||||||
useSubaccount,
|
useSubaccount,
|
||||||
|
useTokenConfigs,
|
||||||
} from '@/hooks';
|
} from '@/hooks';
|
||||||
|
|
||||||
import { formMixins } from '@/styles/formMixins';
|
import { formMixins } from '@/styles/formMixins';
|
||||||
@@ -57,7 +54,7 @@ type TransferFormProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const TransferForm = ({
|
export const TransferForm = ({
|
||||||
selectedAsset = DydxChainAsset.DYDX,
|
selectedAsset = DydxChainAsset.CHAINTOKEN,
|
||||||
onDone,
|
onDone,
|
||||||
className,
|
className,
|
||||||
}: TransferFormProps) => {
|
}: TransferFormProps) => {
|
||||||
@@ -72,6 +69,7 @@ export const TransferForm = ({
|
|||||||
const { transfer } = useSubaccount();
|
const { transfer } = useSubaccount();
|
||||||
const { nativeTokenBalance, usdcBalance } = useAccountBalance();
|
const { nativeTokenBalance, usdcBalance } = useAccountBalance();
|
||||||
const { selectedNetwork } = useSelectedNetwork();
|
const { selectedNetwork } = useSelectedNetwork();
|
||||||
|
const { tokensConfigs, usdcLabel, chainTokenLabel } = useTokenConfigs();
|
||||||
|
|
||||||
// User Input
|
// User Input
|
||||||
const [asset, setAsset] = useState<DydxChainAsset>(selectedAsset);
|
const [asset, setAsset] = useState<DydxChainAsset>(selectedAsset);
|
||||||
@@ -138,7 +136,7 @@ export const TransferForm = ({
|
|||||||
try {
|
try {
|
||||||
// Subtract fees from amount if sending native tokens
|
// Subtract fees from amount if sending native tokens
|
||||||
const amountToTransfer = (
|
const amountToTransfer = (
|
||||||
asset === DydxChainAsset.DYDX ? amountBN.minus(fee) : amountBN
|
asset === DydxChainAsset.CHAINTOKEN ? amountBN.minus(fee) : amountBN
|
||||||
).toNumber();
|
).toNumber();
|
||||||
|
|
||||||
const screenResults = await screenAddresses({
|
const screenResults = await screenAddresses({
|
||||||
@@ -161,7 +159,7 @@ export const TransferForm = ({
|
|||||||
const txResponse = await transfer(
|
const txResponse = await transfer(
|
||||||
amountToTransfer,
|
amountToTransfer,
|
||||||
recipientAddress as string,
|
recipientAddress as string,
|
||||||
DYDX_CHAIN_ASSET_COIN_DENOM[asset]
|
tokensConfigs[asset].denom,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (txResponse?.code === 0) {
|
if (txResponse?.code === 0) {
|
||||||
@@ -220,16 +218,16 @@ export const TransferForm = ({
|
|||||||
value: DydxChainAsset.USDC,
|
value: DydxChainAsset.USDC,
|
||||||
label: (
|
label: (
|
||||||
<Styled.InlineRow>
|
<Styled.InlineRow>
|
||||||
<AssetIcon symbol="USDC" /> {DYDX_CHAIN_ASSET_TAGS[DydxChainAsset.USDC]}
|
<AssetIcon symbol="USDC" /> {usdcLabel}
|
||||||
</Styled.InlineRow>
|
</Styled.InlineRow>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: DydxChainAsset.DYDX,
|
value: DydxChainAsset.CHAINTOKEN,
|
||||||
label: (
|
label: (
|
||||||
<Styled.InlineRow>
|
<Styled.InlineRow>
|
||||||
{/* <AssetIcon symbol="DYDX" /> */}
|
{/* <AssetIcon symbol="DYDX" /> */}
|
||||||
{DYDX_CHAIN_ASSET_TAGS[DydxChainAsset.DYDX]}
|
{chainTokenLabel}
|
||||||
</Styled.InlineRow>
|
</Styled.InlineRow>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -251,7 +249,7 @@ export const TransferForm = ({
|
|||||||
key: 'amount',
|
key: 'amount',
|
||||||
label: (
|
label: (
|
||||||
<span>
|
<span>
|
||||||
{stringGetter({ key: STRING_KEYS.AVAILABLE })} <Tag>{DYDX_CHAIN_ASSET_TAGS[asset]}</Tag>
|
{stringGetter({ key: STRING_KEYS.AVAILABLE })} <Tag>{tokensConfigs[asset].name}</Tag>
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
value: (
|
value: (
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { shallowEqual, useSelector } from 'react-redux';
|
|||||||
import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons';
|
import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { NumberSign } from '@/constants/numbers';
|
import { NumberSign } from '@/constants/numbers';
|
||||||
import { DYDX_CHAIN_ASSET_TAGS, DydxChainAsset } from '@/constants/wallets';
|
import { DydxChainAsset } from '@/constants/wallets';
|
||||||
|
|
||||||
import { useAccountBalance, useStringGetter } from '@/hooks';
|
import { useAccountBalance, useTokenConfigs, useStringGetter } from '@/hooks';
|
||||||
|
|
||||||
import { Button } from '@/components/Button';
|
import { Button } from '@/components/Button';
|
||||||
import { DiffOutput } from '@/components/DiffOutput';
|
import { DiffOutput } from '@/components/DiffOutput';
|
||||||
@@ -37,6 +37,7 @@ export const TransferButtonAndReceipt = ({
|
|||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual);
|
const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual);
|
||||||
const { size } = useSelector(getTransferInputs, shallowEqual) || {};
|
const { size } = useSelector(getTransferInputs, shallowEqual) || {};
|
||||||
|
const { tokensConfigs } = useTokenConfigs();
|
||||||
|
|
||||||
const { equity: equityInfo, leverage: leverageInfo } =
|
const { equity: equityInfo, leverage: leverageInfo } =
|
||||||
useSelector(getSubaccount, shallowEqual) || {};
|
useSelector(getSubaccount, shallowEqual) || {};
|
||||||
@@ -60,7 +61,7 @@ export const TransferButtonAndReceipt = ({
|
|||||||
key: 'fees',
|
key: 'fees',
|
||||||
label: (
|
label: (
|
||||||
<span>
|
<span>
|
||||||
{stringGetter({ key: STRING_KEYS.FEES })} <Tag>{DYDX_CHAIN_ASSET_TAGS[selectedAsset]}</Tag>
|
{stringGetter({ key: STRING_KEYS.FEES })} <Tag>{tokensConfigs[selectedAsset].name}</Tag>
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
value: <Output type={OutputType.Asset} value={fees} />,
|
value: <Output type={OutputType.Asset} value={fees} />,
|
||||||
@@ -69,7 +70,7 @@ export const TransferButtonAndReceipt = ({
|
|||||||
key: 'balance',
|
key: 'balance',
|
||||||
label: (
|
label: (
|
||||||
<span>
|
<span>
|
||||||
{stringGetter({ key: STRING_KEYS.BALANCE })} <Tag>{DYDX_CHAIN_ASSET_TAGS[selectedAsset]}</Tag>
|
{stringGetter({ key: STRING_KEYS.BALANCE })} <Tag>{tokensConfigs[selectedAsset].name}</Tag>
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
value: (
|
value: (
|
||||||
|
|||||||
@@ -9,7 +9,13 @@ import { DialogTypes } from '@/constants/dialogs';
|
|||||||
import { STRING_KEYS, TOOLTIP_STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS, TOOLTIP_STRING_KEYS } from '@/constants/localization';
|
||||||
import { DydxChainAsset, wallets } from '@/constants/wallets';
|
import { DydxChainAsset, wallets } from '@/constants/wallets';
|
||||||
|
|
||||||
import { useAccounts, useBreakpoints, useStringGetter, useAccountBalance } from '@/hooks';
|
import {
|
||||||
|
useAccounts,
|
||||||
|
useBreakpoints,
|
||||||
|
useTokenConfigs,
|
||||||
|
useStringGetter,
|
||||||
|
useAccountBalance,
|
||||||
|
} from '@/hooks';
|
||||||
|
|
||||||
import { OnboardingTriggerButton } from '@/views/dialogs/OnboardingTriggerButton';
|
import { OnboardingTriggerButton } from '@/views/dialogs/OnboardingTriggerButton';
|
||||||
|
|
||||||
@@ -39,6 +45,7 @@ export const AccountMenu = () => {
|
|||||||
const onboardingState = useSelector(getOnboardingState);
|
const onboardingState = useSelector(getOnboardingState);
|
||||||
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
|
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
|
||||||
const { nativeTokenBalance } = useAccountBalance();
|
const { nativeTokenBalance } = useAccountBalance();
|
||||||
|
const { usdcLabel, chainTokenLabel } = useTokenConfigs();
|
||||||
|
|
||||||
const { evmAddress, walletType, dydxAddress, hdKey } = useAccounts();
|
const { evmAddress, walletType, dydxAddress, hdKey } = useAccounts();
|
||||||
|
|
||||||
@@ -107,17 +114,23 @@ export const AccountMenu = () => {
|
|||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<Styled.label>
|
<Styled.label>
|
||||||
{stringGetter({ key: STRING_KEYS.ASSET_BALANCE, params: { ASSET: 'Dv4TNT' } })}
|
{stringGetter({
|
||||||
|
key: STRING_KEYS.ASSET_BALANCE,
|
||||||
|
params: { ASSET: chainTokenLabel },
|
||||||
|
})}
|
||||||
{/* <AssetIcon symbol="DYDX" /> */}
|
{/* <AssetIcon symbol="DYDX" /> */}
|
||||||
</Styled.label>
|
</Styled.label>
|
||||||
<Styled.BalanceOutput type={OutputType.Asset} value={nativeTokenBalance} />
|
<Styled.BalanceOutput type={OutputType.Asset} value={nativeTokenBalance} />
|
||||||
</div>
|
</div>
|
||||||
<AssetActions asset={DydxChainAsset.DYDX} dispatch={dispatch} />
|
<AssetActions asset={DydxChainAsset.CHAINTOKEN} dispatch={dispatch} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<Styled.label>
|
<Styled.label>
|
||||||
{stringGetter({ key: STRING_KEYS.ASSET_BALANCE, params: { ASSET: 'USDC' } })}
|
{stringGetter({
|
||||||
|
key: STRING_KEYS.ASSET_BALANCE,
|
||||||
|
params: { ASSET: usdcLabel },
|
||||||
|
})}
|
||||||
<AssetIcon symbol="USDC" />
|
<AssetIcon symbol="USDC" />
|
||||||
</Styled.label>
|
</Styled.label>
|
||||||
<Styled.BalanceOutput
|
<Styled.BalanceOutput
|
||||||
|
|||||||
Reference in New Issue
Block a user