Compare commits
23
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
514a2d3ab3 | ||
|
|
c58d94e477 | ||
|
|
68f3552569 | ||
|
|
18b12591ca | ||
|
|
3f963ffb07 | ||
|
|
aac024fd5e | ||
|
|
4913c690ec | ||
|
|
b0db577b28 | ||
|
|
9815437a80 | ||
|
|
890a4b2c0e | ||
|
|
8d3cc76d14 | ||
|
|
c7ad4b3028 | ||
|
|
c88d5dd411 | ||
|
|
d6ab547055 | ||
|
|
2fe6c2bb3b | ||
|
|
e6858ca917 | ||
|
|
d92b49f4fa | ||
|
|
e7da21962a | ||
|
|
b479531e34 | ||
|
|
0d4c5a547a | ||
|
|
5b235ee53f | ||
|
|
18dee0586b | ||
|
|
9f1f5987ee |
+7
-2
@@ -4,6 +4,11 @@ VITE_ALCHEMY_API_KEY=
|
|||||||
|
|
||||||
VITE_PK_ENCRYPTION_KEY=
|
VITE_PK_ENCRYPTION_KEY=
|
||||||
|
|
||||||
VITE_WALLETCONNECT2_PROJECT_ID=
|
VITE_V3_TOKEN_ADDRESS=
|
||||||
|
VITE_TOKEN_MIGRATION_URI=
|
||||||
|
|
||||||
VITE_V3_TOKEN_ADDRESS=
|
AMPLITUDE_API_KEY=
|
||||||
|
BUGSNAG_API_KEY=
|
||||||
|
IOS_APP_ID=
|
||||||
|
INTERCOM_APP_ID=
|
||||||
|
STATUS_PAGE_SCRIPT_URI=
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
Copyright (C) 2023 dYdX Trading Inc.
|
Copyright (C) 2023 dYdX Trading Inc.
|
||||||
|
|
||||||
Subject to your compliance with applicable law, you are granted the right to use the Licensed Work (defined below) under the terms of the GNU Affero General Public License as set forth below; provided, however, that if you violate any such applicable law in your use of the Licensed Work, all of your rights and licenses to use (including any rights to reproduce, distribute, install or modify) the Licensed Work will automatically and immediately terminate.
|
Subject to your compliance with applicable law and the v4 Terms of Use, available at dydx.exchange/legal, you are granted the right to use the Program or Licensed Work (defined below) under the terms of the GNU Affero General Public License as set forth below; provided, however, that if you violate any such applicable law in your use of the Program or Licensed Work, all of your rights and licenses to use (including any rights to reproduce, distribute, install or modify) the Program or Licensed Work will automatically and immediately terminate.
|
||||||
|
|
||||||
|
|
||||||
|
The “Program” or “Licensed Work” shall mean any of the following: dydxprotocol/cosmos-sdk, dydxprotocol/cometbft, dydxprotocol/v4-chain, dydxprotocol/v4-clients, dydxprotocol/v4-web, dydxprotocol/v4-abacus, dydxprotocol/v4-localization, dydxprotocol/v4-documentation, and any dYdX or dYdX Trading Inc. repository reflecting a copy of, or link to, this license.
|
||||||
|
|
||||||
|
|
||||||
The GNU Affero General Public License
|
The GNU Affero General Public License
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Alternatively, follow the [IPFS Kubo installation guide](https://docs.ipfs.tech
|
|||||||
|
|
||||||
## Part 1: Setting up your local environment
|
## Part 1: Setting up your local environment
|
||||||
|
|
||||||
### Step 1: Clone the repo
|
### 1. Clone the repo
|
||||||
|
|
||||||
Clone the repository and navigate to its directory:
|
Clone the repository and navigate to its directory:
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ git clone https://github.com/dydxprotocol/v4-web.git
|
|||||||
cd v4-web
|
cd v4-web
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 2: Install pnpm and dependencies
|
### 2. Install pnpm and dependencies
|
||||||
|
|
||||||
Install pnpm and the project dependencies:
|
Install pnpm and the project dependencies:
|
||||||
|
|
||||||
@@ -69,7 +69,24 @@ You'll need to provide a Wallet Connect project id to enable onboarding and wall
|
|||||||
- Create a project on https://cloud.walletconnect.com/app
|
- 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)
|
- 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
|
## Part 4: Set Enviornment variables
|
||||||
|
Set environment variables via `.env`.
|
||||||
|
|
||||||
|
- `VITE_BASE_URL` (required): The base URL of the deployment (e.g., `https://www.example.com`).
|
||||||
|
- `VITE_ALCHEMY_API_KEY` (optional): Add an Alchemy API key for EVM interactions; the app will fall back to public RPCs if not provided.
|
||||||
|
- `VITE_PK_ENCRYPTION_KEY` (optional): AES encryption key used for signature obfuscation; necessary for enabling the "Remember Me" feature.
|
||||||
|
- `VITE_V3_TOKEN_ADDRESS` (optional): Address of the V3 $DYDX token.
|
||||||
|
- `VITE_TOKEN_MIGRATION_URI` (optional): The URL of the token migration website.
|
||||||
|
- `AMPLITUDE_API_KEY` (optional): Amplitude API key for enabling Amplitude; used with `pnpm run build:inject-amplitude`.
|
||||||
|
- `BUGSNAG_API_KEY` (optional): API key for enabling Bugsnag; used with `pnpm run build:inject-bugsnag`.
|
||||||
|
- `IOS_APP_ID` (optional): iOS app ID used for enabling deep linking to the iOS app; used with `pnpm run build:inject-app-deeplinks`.
|
||||||
|
- `INTERCOM_APP_ID` (optional): Used for enabling Intercom; utilized with `pnpm run build:inject-intercom`.
|
||||||
|
- `STATUS_PAGE_SCRIPT_URI` (optional): Used for enabling the status page; used with `pnpm run build:inject-statuspage`.
|
||||||
|
|
||||||
|
|
||||||
|
# Deployments
|
||||||
|
|
||||||
|
## Deploying with Vercel
|
||||||
|
|
||||||
### Step 1: Connect your repository to Vercel
|
### Step 1: Connect your repository to Vercel
|
||||||
|
|
||||||
@@ -86,7 +103,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 5: Deploying to IPFS
|
## 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
|
||||||
|
|
||||||
@@ -118,3 +135,18 @@ To access your content on IPFS:
|
|||||||
2. **Public IPFS gateway:** Access your content via a public IPFS gateway, such as [https://dweb.link](https://dweb.link/) or [https://w3s.link/](https://w3s.link/). Use the gateway URL with your CID appended, like `https://dweb.link/ipfs/your_cid`.
|
2. **Public IPFS gateway:** Access your content via a public IPFS gateway, such as [https://dweb.link](https://dweb.link/) or [https://w3s.link/](https://w3s.link/). Use the gateway URL with your CID appended, like `https://dweb.link/ipfs/your_cid`.
|
||||||
|
|
||||||
Replace `your_cid` with the actual CID.
|
Replace `your_cid` with the actual CID.
|
||||||
|
|
||||||
|
## Cloudflare Settings
|
||||||
|
|
||||||
|
We recommend that you add your website to Cloudflare for additional security settings.
|
||||||
|
|
||||||
|
To block OFAC Sanctioned countries:
|
||||||
|
1. Navigate Websites > Domain > Security > WAF
|
||||||
|
|
||||||
|
2. Create Rule with the following settings:
|
||||||
|
* If incoming requests match
|
||||||
|
`(ip.geoip.country eq "CU") or (ip.geoip.country eq "IR") or (ip.geoip.country eq "KP") or (ip.geoip.country eq "SY") or (ip.geoip.country eq "MM") or (ip.geoip.subdivision_1_iso_code eq "UA-09") or (ip.geoip.subdivision_1_iso_code eq "UA-14") or (ip.geoip.subdivision_1_iso_code eq "UA-43")`
|
||||||
|
* This rule will bring up a Cloudflare page when a restricted geography tries to access your site. You will have the option to display:
|
||||||
|
1. Custom Text
|
||||||
|
- (e.g. `Because you appear to be a resident of, or trading from, a jurisdiction that violates our terms of use, or have engaged in activity that violates our terms of use, you have been blocked. You may withdraw your funds from the protocol at any time.`)
|
||||||
|
2. Default Cloudflare WAF block page
|
||||||
|
|||||||
+3
-3
@@ -39,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.6",
|
"@dydxprotocol/v4-abacus": "^1.0.10",
|
||||||
"@dydxprotocol/v4-client-js": "^0.40.3",
|
"@dydxprotocol/v4-client-js": "^1.0.0",
|
||||||
"@dydxprotocol/v4-localization": "^0.1.32",
|
"@dydxprotocol/v4-localization": "^1.0.0",
|
||||||
"@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
+15
-15
@@ -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.6
|
specifier: ^1.0.10
|
||||||
version: 0.7.6
|
version: 1.0.10
|
||||||
'@dydxprotocol/v4-client-js':
|
'@dydxprotocol/v4-client-js':
|
||||||
specifier: ^0.40.3
|
specifier: ^1.0.0
|
||||||
version: 0.40.3
|
version: 1.0.0
|
||||||
'@dydxprotocol/v4-localization':
|
'@dydxprotocol/v4-localization':
|
||||||
specifier: ^0.1.32
|
specifier: ^1.0.0
|
||||||
version: 0.1.32
|
version: 1.0.0
|
||||||
'@ethersproject/providers':
|
'@ethersproject/providers':
|
||||||
specifier: ^5.7.2
|
specifier: ^5.7.2
|
||||||
version: 5.7.2
|
version: 5.7.2
|
||||||
@@ -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.6:
|
/@dydxprotocol/v4-abacus@1.0.10:
|
||||||
resolution: {integrity: sha512-FdDXRaFMfxhyrJJs0dNrb1KG6X95lPHelua1yCn/SVgzwGaAqlJczrzmdh98INntuRAgIxOu69R5mCGyekumyg==}
|
resolution: {integrity: sha512-SdxI/JcyxM1ydtR9ImWujeurea3gbxj37qYnw1wz829BQiZ05uNEtll3xJCI0MjpG+01ARsxVys7SHbpjSxwOg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-client-js@0.40.3:
|
/@dydxprotocol/v4-client-js@1.0.0:
|
||||||
resolution: {integrity: sha512-nMQd6tYisKDKIbfx0BGJSYEOSt+I+t5SsaBSmlgTdso+w2rCRO9vyxS+u6MF9h4w5FsVRfhHo3e6uTWX48WpGQ==}
|
resolution: {integrity: sha512-ehfHO+zQy795TcJRwtiawadFHZyh4HnpJNP26hCGsIjLE5q6LLHweQHpK/1N/sXU1PBOuQwc7iaJnFop6gYauQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cosmjs/amino': 0.30.1
|
'@cosmjs/amino': 0.30.1
|
||||||
'@cosmjs/encoding': 0.31.1
|
'@cosmjs/encoding': 0.31.1
|
||||||
@@ -1011,8 +1011,8 @@ packages:
|
|||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-localization@0.1.32:
|
/@dydxprotocol/v4-localization@1.0.0:
|
||||||
resolution: {integrity: sha512-ZtXScxgFLjUt0Ag52RyFnQe9aEl1Aky5fp+vMGOBduVkFiCEMRMkSsSgg6grMdyw/x0AbnxOTRkhYoX2MsK9Ow==}
|
resolution: {integrity: sha512-U7QjOlzpfSAVEchkNDB3xYRx7okzdeYi83XsnHwI+EHa2quFm/2Y2dhrBkT5fqpZmhcwxb/vG8AZmFSToOf9hA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-proto@0.4.1:
|
/@dydxprotocol/v4-proto@0.4.1:
|
||||||
@@ -7656,7 +7656,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-WIdaQ8uW1vIbYvNnAVunkC6yxTrneJC7VQ5UUQ0kuw8b0C0A39KTIpoQHCfc8tV7o9vF4niwRhdXEdfAgQEsQQ==}
|
resolution: {integrity: sha512-WIdaQ8uW1vIbYvNnAVunkC6yxTrneJC7VQ5UUQ0kuw8b0C0A39KTIpoQHCfc8tV7o9vF4niwRhdXEdfAgQEsQQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
cosmos-directory-types: 0.0.6
|
cosmos-directory-types: 0.0.6
|
||||||
node-fetch-native: 1.4.0
|
node-fetch-native: 1.4.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/cosmos-directory-types@0.0.6:
|
/cosmos-directory-types@0.0.6:
|
||||||
@@ -11287,8 +11287,8 @@ packages:
|
|||||||
engines: {node: '>=10.5.0'}
|
engines: {node: '>=10.5.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/node-fetch-native@1.4.0:
|
/node-fetch-native@1.4.1:
|
||||||
resolution: {integrity: sha512-F5kfEj95kX8tkDhUCYdV8dg3/8Olx/94zB8+ZNthFs6Bz31UpUi8Xh40TN3thLwXgrwXry1pEg9lJ++tLWTcqA==}
|
resolution: {integrity: sha512-NsXBU0UgBxo2rQLOeWNZqS3fvflWePMECr8CoSWoSTqCqGbVVsvl9vZu1HfQicYN0g5piV9Gh8RTEvo/uP752w==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/node-fetch@2.6.12:
|
/node-fetch@2.6.12:
|
||||||
|
|||||||
@@ -8,67 +8,43 @@
|
|||||||
],
|
],
|
||||||
"components": [
|
"components": [
|
||||||
{
|
{
|
||||||
"/": "/trade/*"
|
"/": "/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/r/*"
|
"/": "/#/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/portfolio/overview"
|
"/": "*/markets"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/portfolio/positions"
|
"/": "*/trade"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/portfolio/orders"
|
"/": "*/trade/*"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/portfolio/fees"
|
"/": "*/portfolio"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/portfolio/history"
|
"/": "*/portfolio/overview"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/portfolio/history/trades"
|
"/": "*/portfolio/positions"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/portfolio/history/transfers"
|
"/": "*/portfolio/orders"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/portfolio/history/funding"
|
"/": "*/portfolio/fees"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/rewards"
|
"/": "*/portfolio/history/trades"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/my-profile"
|
"/": "*/portfolio/history/transfers"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/rankings/hedgies"
|
"/": "*/portfolio/history/funding"
|
||||||
},
|
|
||||||
{
|
|
||||||
"/": "/rankings/competition"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/": "/rankings/diamond"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/": "/rankings/platinum"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/": "/rankings/gold"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/": "/rankings/silver"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/": "/rankings/bronze"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/": "/rankings/pnl-absolute"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/": "/rankings/pnl-percent"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/": "/walletsegue",
|
"/": "/walletsegue",
|
||||||
|
|||||||
+311
-87
@@ -1,4 +1,9 @@
|
|||||||
{
|
{
|
||||||
|
"apps": {
|
||||||
|
"iOS": {
|
||||||
|
"scheme": "dydxv4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"deployments": {
|
"deployments": {
|
||||||
"MAINNET": {
|
"MAINNET": {
|
||||||
"environments": [
|
"environments": [
|
||||||
@@ -22,10 +27,11 @@
|
|||||||
"dydxprotocol-staging-west",
|
"dydxprotocol-staging-west",
|
||||||
"dydxprotocol-testnet",
|
"dydxprotocol-testnet",
|
||||||
"dydxprotocol-testnet-dydx",
|
"dydxprotocol-testnet-dydx",
|
||||||
"dydxprotocol-testnet-dsrv",
|
|
||||||
"dydxprotocol-testnet-nodefleet",
|
"dydxprotocol-testnet-nodefleet",
|
||||||
"dydxprotocol-testnet-kingnodes",
|
"dydxprotocol-testnet-kingnodes",
|
||||||
"dydxprotocol-testnet-liquify"
|
"dydxprotocol-testnet-liquify",
|
||||||
|
"dydxprotocol-testnet-polkachu",
|
||||||
|
"dydxprotocol-testnet-bware"
|
||||||
],
|
],
|
||||||
"default": "dydxprotocol-testnet"
|
"default": "dydxprotocol-testnet"
|
||||||
}
|
}
|
||||||
@@ -37,6 +43,7 @@
|
|||||||
"dydxChainId": "dydxprotocol-testnet",
|
"dydxChainId": "dydxprotocol-testnet",
|
||||||
"chainName": "dYdX Chain",
|
"chainName": "dYdX Chain",
|
||||||
"chainLogo": "dydx-chain.png",
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
@@ -70,7 +77,19 @@
|
|||||||
"tos": "https://dydx.exchange/v4-terms",
|
"tos": "https://dydx.exchange/v4-terms",
|
||||||
"privacy": "https://dydx.exchange/privacy",
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
"blogs": "https://www.dydx.foundation/blog"
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
|
"foundation": "https://www.dydx.foundation",
|
||||||
|
"help": "https://help.dydx.exchange/",
|
||||||
|
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
||||||
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
|
"community": "https://discord.com/invite/dydx",
|
||||||
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
|
"stakingLearnMore": "https://help.dydx.exchange",
|
||||||
|
"keplrDashboard": "https://testnet.keplr.app/",
|
||||||
|
"accountExportLearnMore": "https://help.dydx.exchange",
|
||||||
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
|
||||||
},
|
},
|
||||||
"wallets": {
|
"wallets": {
|
||||||
"walletconnect": {
|
"walletconnect": {
|
||||||
@@ -97,6 +116,7 @@
|
|||||||
"dydxChainId": "dydxprotocol-testnet",
|
"dydxChainId": "dydxprotocol-testnet",
|
||||||
"chainName": "dYdX Chain",
|
"chainName": "dYdX Chain",
|
||||||
"chainLogo": "dydx-chain.png",
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
@@ -129,7 +149,19 @@
|
|||||||
"tos": "https://dydx.exchange/v4-terms",
|
"tos": "https://dydx.exchange/v4-terms",
|
||||||
"privacy": "https://dydx.exchange/privacy",
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
"blogs": "https://www.dydx.foundation/blog"
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
|
"foundation": "https://www.dydx.foundation",
|
||||||
|
"help": "https://help.dydx.exchange/",
|
||||||
|
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
||||||
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
|
"community": "https://discord.com/invite/dydx",
|
||||||
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
|
"stakingLearnMore": "https://help.dydx.exchange",
|
||||||
|
"keplrDashboard": "https://testnet.keplr.app/",
|
||||||
|
"accountExportLearnMore": "https://help.dydx.exchange",
|
||||||
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
|
||||||
},
|
},
|
||||||
"wallets": {
|
"wallets": {
|
||||||
"walletconnect": {
|
"walletconnect": {
|
||||||
@@ -156,6 +188,7 @@
|
|||||||
"dydxChainId": "dydxprotocol-testnet",
|
"dydxChainId": "dydxprotocol-testnet",
|
||||||
"chainName": "dYdX Chain",
|
"chainName": "dYdX Chain",
|
||||||
"chainLogo": "dydx-chain.png",
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
@@ -175,8 +208,8 @@
|
|||||||
"endpoints": {
|
"endpoints": {
|
||||||
"indexers": [
|
"indexers": [
|
||||||
{
|
{
|
||||||
"api": "http://indexer.v4dev4.dydx.exchange",
|
"api": "https://indexer.v4dev4.dydx.exchange",
|
||||||
"socket": "ws://indexer.v4dev4.dydx.exchange"
|
"socket": "wss://indexer.v4dev4.dydx.exchange"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"validators": [
|
"validators": [
|
||||||
@@ -188,7 +221,19 @@
|
|||||||
"tos": "https://dydx.exchange/v4-terms",
|
"tos": "https://dydx.exchange/v4-terms",
|
||||||
"privacy": "https://dydx.exchange/privacy",
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
"blogs": "https://www.dydx.foundation/blog"
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
|
"foundation": "https://www.dydx.foundation",
|
||||||
|
"help": "https://help.dydx.exchange/",
|
||||||
|
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
||||||
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
|
"community": "https://discord.com/invite/dydx",
|
||||||
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
|
"stakingLearnMore": "https://help.dydx.exchange",
|
||||||
|
"keplrDashboard": "https://testnet.keplr.app/",
|
||||||
|
"accountExportLearnMore": "https://help.dydx.exchange",
|
||||||
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
|
||||||
},
|
},
|
||||||
"wallets": {
|
"wallets": {
|
||||||
"walletconnect": {
|
"walletconnect": {
|
||||||
@@ -215,6 +260,7 @@
|
|||||||
"dydxChainId": "dydxprotocol-testnet",
|
"dydxChainId": "dydxprotocol-testnet",
|
||||||
"chainName": "dYdX Chain",
|
"chainName": "dYdX Chain",
|
||||||
"chainLogo": "dydx-chain.png",
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
@@ -247,7 +293,19 @@
|
|||||||
"tos": "https://dydx.exchange/v4-terms",
|
"tos": "https://dydx.exchange/v4-terms",
|
||||||
"privacy": "https://dydx.exchange/privacy",
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
"blogs": "https://www.dydx.foundation/blog"
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
|
"foundation": "https://www.dydx.foundation",
|
||||||
|
"help": "https://help.dydx.exchange/",
|
||||||
|
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
||||||
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
|
"community": "https://discord.com/invite/dydx",
|
||||||
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
|
"stakingLearnMore": "https://help.dydx.exchange",
|
||||||
|
"keplrDashboard": "https://testnet.keplr.app/",
|
||||||
|
"accountExportLearnMore": "https://help.dydx.exchange",
|
||||||
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
|
||||||
},
|
},
|
||||||
"wallets": {
|
"wallets": {
|
||||||
"walletconnect": {
|
"walletconnect": {
|
||||||
@@ -274,6 +332,7 @@
|
|||||||
"dydxChainId": "dydxprotocol-testnet",
|
"dydxChainId": "dydxprotocol-testnet",
|
||||||
"chainName": "dYdX Chain",
|
"chainName": "dYdX Chain",
|
||||||
"chainLogo": "dydx-chain.png",
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
@@ -307,10 +366,20 @@
|
|||||||
"tos": "https://dydx.exchange/v4-terms",
|
"tos": "https://dydx.exchange/v4-terms",
|
||||||
"privacy": "https://dydx.exchange/privacy",
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
"documentation": "https://v4-teacher.vercel.app/",
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
"community": "https://discord.com/invite/dydx",
|
"community": "https://discord.com/invite/dydx",
|
||||||
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
||||||
"blogs": "https://www.dydx.foundation/blog"
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
|
"help": "https://help.dydx.exchange",
|
||||||
|
"foundation": "https://www.dydx.foundation",
|
||||||
|
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
||||||
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
|
"stakingLearnMore": "https://help.dydx.exchange",
|
||||||
|
"keplrDashboard": "https://testnet.keplr.app/",
|
||||||
|
"accountExportLearnMore": "https://help.dydx.exchange",
|
||||||
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
|
||||||
},
|
},
|
||||||
"wallets": {
|
"wallets": {
|
||||||
"walletconnect": {
|
"walletconnect": {
|
||||||
@@ -337,6 +406,7 @@
|
|||||||
"dydxChainId": "dydxprotocol-testnet",
|
"dydxChainId": "dydxprotocol-testnet",
|
||||||
"chainName": "dYdX Chain",
|
"chainName": "dYdX Chain",
|
||||||
"chainLogo": "dydx-chain.png",
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
@@ -370,10 +440,20 @@
|
|||||||
"tos": "https://dydx.exchange/v4-terms",
|
"tos": "https://dydx.exchange/v4-terms",
|
||||||
"privacy": "https://dydx.exchange/privacy",
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
"documentation": "https://v4-teacher.vercel.app/",
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
"community": "https://discord.com/invite/dydx",
|
"community": "https://discord.com/invite/dydx",
|
||||||
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
||||||
"blogs": "https://www.dydx.foundation/blog"
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
|
"help": "https://help.dydx.exchange",
|
||||||
|
"foundation": "https://www.dydx.foundation",
|
||||||
|
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
||||||
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
|
"stakingLearnMore": "https://help.dydx.exchange",
|
||||||
|
"keplrDashboard": "https://testnet.keplr.app/",
|
||||||
|
"accountExportLearnMore": "https://help.dydx.exchange",
|
||||||
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
|
||||||
},
|
},
|
||||||
"wallets": {
|
"wallets": {
|
||||||
"walletconnect": {
|
"walletconnect": {
|
||||||
@@ -400,6 +480,7 @@
|
|||||||
"dydxChainId": "dydx-testnet-4",
|
"dydxChainId": "dydx-testnet-4",
|
||||||
"chainName": "dYdX Chain",
|
"chainName": "dYdX Chain",
|
||||||
"chainLogo": "dydx-chain.png",
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
@@ -424,6 +505,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"validators": [
|
"validators": [
|
||||||
|
"https://dydx-testnet-full-rpc.public.blastapi.io/",
|
||||||
|
"https://dydx-testnet-rpc.polkachu.com/",
|
||||||
"https://dydx-testnet.nodefleet.org",
|
"https://dydx-testnet.nodefleet.org",
|
||||||
"https://test-dydx.kingnodes.com",
|
"https://test-dydx.kingnodes.com",
|
||||||
"https://dydx-rpc.liquify.com/api=8878132/dydx"
|
"https://dydx-rpc.liquify.com/api=8878132/dydx"
|
||||||
@@ -435,10 +518,20 @@
|
|||||||
"tos": "https://dydx.exchange/v4-terms",
|
"tos": "https://dydx.exchange/v4-terms",
|
||||||
"privacy": "https://dydx.exchange/privacy",
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
"documentation": "https://v4-teacher.vercel.app/",
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
"community": "https://discord.com/invite/dydx",
|
"community": "https://discord.com/invite/dydx",
|
||||||
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
||||||
"blogs": "https://www.dydx.foundation/blog"
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
|
"foundation": "https://www.dydx.foundation",
|
||||||
|
"help": "https://help.dydx.exchange/",
|
||||||
|
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
||||||
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
|
"stakingLearnMore": "https://help.dydx.exchange",
|
||||||
|
"keplrDashboard": "https://testnet.keplr.app/",
|
||||||
|
"accountExportLearnMore": "https://help.dydx.exchange",
|
||||||
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
|
||||||
},
|
},
|
||||||
"wallets": {
|
"wallets": {
|
||||||
"walletconnect": {
|
"walletconnect": {
|
||||||
@@ -465,6 +558,7 @@
|
|||||||
"dydxChainId": "dydx-testnet-4",
|
"dydxChainId": "dydx-testnet-4",
|
||||||
"chainName": "dYdX Chain",
|
"chainName": "dYdX Chain",
|
||||||
"chainLogo": "dydx-chain.png",
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
@@ -499,74 +593,20 @@
|
|||||||
"privacy": "https://dydx.exchange/privacy",
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
"statusPage": "https://status.v4testnet.dydx.exchange/",
|
"statusPage": "https://status.v4testnet.dydx.exchange/",
|
||||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
"documentation": "https://v4-teacher.vercel.app/",
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
"community": "https://discord.com/invite/dydx",
|
"community": "https://discord.com/invite/dydx",
|
||||||
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
||||||
"blogs": "https://www.dydx.foundation/blog"
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
},
|
"foundation": "https://www.dydx.foundation",
|
||||||
"wallets": {
|
"help": "https://help.dydx.exchange/",
|
||||||
"walletconnect": {
|
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
||||||
"client": {
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"name": "dYdX v4",
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
"description": "dYdX v4 App",
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
"iconUrl": "/logos/dydx-x.png"
|
"stakingLearnMore": "https://help.dydx.exchange",
|
||||||
},
|
"keplrDashboard": "https://testnet.keplr.app/",
|
||||||
"v2": {
|
"accountExportLearnMore": "https://help.dydx.exchange",
|
||||||
"projectId": "47559b2ec96c09aed9ff2cb54a31ab0e"
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
|
||||||
}
|
|
||||||
},
|
|
||||||
"walletSegue": {
|
|
||||||
"callbackUrl": "/walletsegue"
|
|
||||||
},
|
|
||||||
"images": "/wallets/",
|
|
||||||
"signTypedDataAction": "dYdX Chain Onboarding",
|
|
||||||
"signTypedDataDomainName": "dYdX V4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dydxprotocol-testnet-dsrv": {
|
|
||||||
"name": "v4 Public Testnet/DSRV",
|
|
||||||
"ethereumChainId": "5",
|
|
||||||
"dydxChainId": "dydx-testnet-4",
|
|
||||||
"chainName": "dYdX Chain",
|
|
||||||
"chainLogo": "dydx-chain.png",
|
|
||||||
"isMainNet": false,
|
|
||||||
"tokens": {
|
|
||||||
"chain": {
|
|
||||||
"name": "Dv4TNT",
|
|
||||||
"denom": "adv4tnt",
|
|
||||||
"decimals": 18,
|
|
||||||
"image": "/currencies/dydx.png"
|
|
||||||
},
|
|
||||||
"usdc": {
|
|
||||||
"name": "USDC",
|
|
||||||
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
|
|
||||||
"gasDenom": "uusdc",
|
|
||||||
"decimals": 6,
|
|
||||||
"image": "/currencies/usdc.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"endpoints": {
|
|
||||||
"indexers": [
|
|
||||||
{
|
|
||||||
"api": "https://dydx-testnet.imperator.co",
|
|
||||||
"socket": "wss://dydx-testnet.imperator.co"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"validators": [
|
|
||||||
"https://dydx-testnet-archive.allthatnode.com:26657/XZvMM41hESf8PJrEQiTzbCOMVyFca79R"
|
|
||||||
],
|
|
||||||
"0xsquid": "https://testnet.api.squidrouter.com",
|
|
||||||
"faucet": "https://faucet.v4testnet.dydx.exchange"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"tos": "https://dydx.exchange/v4-terms",
|
|
||||||
"privacy": "https://dydx.exchange/privacy",
|
|
||||||
"statusPage": "https://status.v4testnet.dydx.exchange/",
|
|
||||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
|
||||||
"documentation": "https://v4-teacher.vercel.app/",
|
|
||||||
"community": "https://discord.com/invite/dydx",
|
|
||||||
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
|
||||||
"blogs": "https://www.dydx.foundation/blog"
|
|
||||||
},
|
},
|
||||||
"wallets": {
|
"wallets": {
|
||||||
"walletconnect": {
|
"walletconnect": {
|
||||||
@@ -593,6 +633,7 @@
|
|||||||
"dydxChainId": "dydx-testnet-4",
|
"dydxChainId": "dydx-testnet-4",
|
||||||
"chainName": "dYdX Chain",
|
"chainName": "dYdX Chain",
|
||||||
"chainLogo": "dydx-chain.png",
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
@@ -627,10 +668,20 @@
|
|||||||
"privacy": "https://dydx.exchange/privacy",
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
"statusPage": "https://status.v4testnet.dydx.exchange/",
|
"statusPage": "https://status.v4testnet.dydx.exchange/",
|
||||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
"documentation": "https://v4-teacher.vercel.app/",
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
"community": "https://discord.com/invite/dydx",
|
"community": "https://discord.com/invite/dydx",
|
||||||
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
||||||
"blogs": "https://www.dydx.foundation/blog"
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
|
"foundation": "https://www.dydx.foundation",
|
||||||
|
"help": "https://help.dydx.exchange/",
|
||||||
|
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
||||||
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
|
"stakingLearnMore": "https://help.dydx.exchange",
|
||||||
|
"keplrDashboard": "https://testnet.keplr.app/",
|
||||||
|
"accountExportLearnMore": "https://help.dydx.exchange",
|
||||||
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
|
||||||
},
|
},
|
||||||
"wallets": {
|
"wallets": {
|
||||||
"walletconnect": {
|
"walletconnect": {
|
||||||
@@ -657,6 +708,7 @@
|
|||||||
"dydxChainId": "dydx-testnet-4",
|
"dydxChainId": "dydx-testnet-4",
|
||||||
"chainName": "dYdX Chain",
|
"chainName": "dYdX Chain",
|
||||||
"chainLogo": "dydx-chain.png",
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
@@ -691,10 +743,20 @@
|
|||||||
"privacy": "https://dydx.exchange/privacy",
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
"statusPage": "https://status.v4testnet.dydx.exchange/",
|
"statusPage": "https://status.v4testnet.dydx.exchange/",
|
||||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
"documentation": "https://v4-teacher.vercel.app/",
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
"community": "https://discord.com/invite/dydx",
|
"community": "https://discord.com/invite/dydx",
|
||||||
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
||||||
"blogs": "https://www.dydx.foundation/blog"
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
|
"foundation": "https://www.dydx.foundation",
|
||||||
|
"help": "https://help.dydx.exchange/",
|
||||||
|
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
||||||
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
|
"stakingLearnMore": "https://help.dydx.exchange",
|
||||||
|
"keplrDashboard": "https://testnet.keplr.app/",
|
||||||
|
"accountExportLearnMore": "https://help.dydx.exchange",
|
||||||
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
|
||||||
},
|
},
|
||||||
"wallets": {
|
"wallets": {
|
||||||
"walletconnect": {
|
"walletconnect": {
|
||||||
@@ -721,6 +783,7 @@
|
|||||||
"dydxChainId": "dydx-testnet-4",
|
"dydxChainId": "dydx-testnet-4",
|
||||||
"chainName": "dYdX Chain",
|
"chainName": "dYdX Chain",
|
||||||
"chainLogo": "dydx-chain.png",
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
"isMainNet": false,
|
"isMainNet": false,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"chain": {
|
"chain": {
|
||||||
@@ -755,7 +818,82 @@
|
|||||||
"privacy": "https://dydx.exchange/privacy",
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
"statusPage": "https://status.v4testnet.dydx.exchange/",
|
"statusPage": "https://status.v4testnet.dydx.exchange/",
|
||||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
"documentation": "https://v4-teacher.vercel.app/",
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
|
"community": "https://discord.com/invite/dydx",
|
||||||
|
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
||||||
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
|
"foundation": "https://www.dydx.foundation",
|
||||||
|
"help": "https://help.dydx.exchange/",
|
||||||
|
"initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
||||||
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
|
"governanceLearnMore": "https://help.dydx.exchange",
|
||||||
|
"stakingLearnMore": "https://help.dydx.exchange",
|
||||||
|
"keplrDashboard": "https://testnet.keplr.app/",
|
||||||
|
"accountExportLearnMore": "https://help.dydx.exchange",
|
||||||
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
|
||||||
|
},
|
||||||
|
"wallets": {
|
||||||
|
"walletconnect": {
|
||||||
|
"client": {
|
||||||
|
"name": "dYdX v4",
|
||||||
|
"description": "dYdX v4 App",
|
||||||
|
"iconUrl": "/logos/dydx-x.png"
|
||||||
|
},
|
||||||
|
"v2": {
|
||||||
|
"projectId": "47559b2ec96c09aed9ff2cb54a31ab0e"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"walletSegue": {
|
||||||
|
"callbackUrl": "/walletsegue"
|
||||||
|
},
|
||||||
|
"images": "/wallets/",
|
||||||
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
|
"signTypedDataDomainName": "dYdX V4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dydxprotocol-testnet-polkachu": {
|
||||||
|
"name": "v4 Public Testnet/Polkahcu",
|
||||||
|
"ethereumChainId": "5",
|
||||||
|
"dydxChainId": "dydx-testnet-4",
|
||||||
|
"chainName": "dYdX Chain",
|
||||||
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
|
"isMainNet": false,
|
||||||
|
"tokens": {
|
||||||
|
"chain": {
|
||||||
|
"name": "Dv4TNT",
|
||||||
|
"denom": "adv4tnt",
|
||||||
|
"decimals": 18,
|
||||||
|
"image": "/currencies/dydx.png"
|
||||||
|
},
|
||||||
|
"usdc": {
|
||||||
|
"name": "USDC",
|
||||||
|
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
|
||||||
|
"gasDenom": "uusdc",
|
||||||
|
"decimals": 6,
|
||||||
|
"image": "/currencies/usdc.png"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"endpoints": {
|
||||||
|
"indexers": [
|
||||||
|
{
|
||||||
|
"api": "https://dydx-testnet.imperator.co",
|
||||||
|
"socket": "wss://dydx-testnet.imperator.co"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validators": [
|
||||||
|
"https://dydx-testnet-rpc.polkachu.com/"
|
||||||
|
],
|
||||||
|
"0xsquid": "https://testnet.api.squidrouter.com",
|
||||||
|
"faucet": "https://faucet.v4testnet.dydx.exchange"
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"tos": "https://dydx.exchange/v4-terms",
|
||||||
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
|
"statusPage": "https://status.v4testnet.dydx.exchange/",
|
||||||
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
"community": "https://discord.com/invite/dydx",
|
"community": "https://discord.com/invite/dydx",
|
||||||
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
||||||
"blogs": "https://www.dydx.foundation/blog"
|
"blogs": "https://www.dydx.foundation/blog"
|
||||||
@@ -779,12 +917,88 @@
|
|||||||
"signTypedDataDomainName": "dYdX V4"
|
"signTypedDataDomainName": "dYdX V4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dydxprotocol-testnet-bware": {
|
||||||
|
"name": "v4 Public Testnet/BWare",
|
||||||
|
"ethereumChainId": "5",
|
||||||
|
"dydxChainId": "dydx-testnet-4",
|
||||||
|
"chainName": "dYdX Chain",
|
||||||
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "dYdX-api",
|
||||||
|
"isMainNet": false,
|
||||||
|
"tokens": {
|
||||||
|
"chain": {
|
||||||
|
"name": "Dv4TNT",
|
||||||
|
"denom": "adv4tnt",
|
||||||
|
"decimals": 18,
|
||||||
|
"image": "/currencies/dydx.png"
|
||||||
|
},
|
||||||
|
"usdc": {
|
||||||
|
"name": "USDC",
|
||||||
|
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
|
||||||
|
"gasDenom": "uusdc",
|
||||||
|
"decimals": 6,
|
||||||
|
"image": "/currencies/usdc.png"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"endpoints": {
|
||||||
|
"indexers": [
|
||||||
|
{
|
||||||
|
"api": "https://dydx-testnet.imperator.co",
|
||||||
|
"socket": "wss://dydx-testnet.imperator.co"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validators": [
|
||||||
|
"https://dydx-testnet-full-rpc.public.blastapi.io/"
|
||||||
|
],
|
||||||
|
"0xsquid": "https://testnet.api.squidrouter.com",
|
||||||
|
"faucet": "https://faucet.v4testnet.dydx.exchange"
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"tos": "https://dydx.exchange/v4-terms",
|
||||||
|
"privacy": "https://dydx.exchange/privacy",
|
||||||
|
"statusPage": "https://status.v4testnet.dydx.exchange/",
|
||||||
|
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||||
|
"documentation": "https://docs.dydx.exchange/",
|
||||||
|
"community": "https://discord.com/invite/dydx",
|
||||||
|
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
||||||
|
"blogs": "https://www.dydx.foundation/blog",
|
||||||
|
"foundation": "https://www.dydx.foundation",
|
||||||
|
"help": "https://help.dydx.exchange/",
|
||||||
|
"initialMarginFractionLearnmore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes",
|
||||||
|
"reduceOnlyLearnmore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
|
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||||
|
"governanceLearnmore": "https://help.dydx.exchange",
|
||||||
|
"stakingLearnmore": "https://help.dydx.exchange",
|
||||||
|
"keplrDashboard": "https://testnet.keplr.app/",
|
||||||
|
"accountExportLearnmore": "https://help.dydx.exchange",
|
||||||
|
"walletLearnmore": "https://www.dydx.academy/video/defi-wallet"
|
||||||
|
},
|
||||||
|
"wallets": {
|
||||||
|
"walletconnect": {
|
||||||
|
"client": {
|
||||||
|
"name": "dYdX v4",
|
||||||
|
"description": "dYdX v4 App",
|
||||||
|
"iconUrl": "/logos/dydx-x.png"
|
||||||
|
},
|
||||||
|
"v2": {
|
||||||
|
"projectId": "47559b2ec96c09aed9ff2cb54a31ab0e"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"walletSegue": {
|
||||||
|
"callbackUrl": "/walletsegue"
|
||||||
|
},
|
||||||
|
"images": "/wallets/",
|
||||||
|
"signTypedDataAction": "dYdX Chain Onboarding",
|
||||||
|
"signTypedDataDomainName": "dYdX V4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dydxprotocol-mainnet": {
|
"dydxprotocol-mainnet": {
|
||||||
"name": "v4",
|
"name": "v4",
|
||||||
"ethereumChainId": "1",
|
"ethereumChainId": "1",
|
||||||
"dydxChainId": "[mainnet chain id]",
|
"dydxChainId": "[mainnet chain id]",
|
||||||
"chainName": "dYdX Chain",
|
"chainName": "dYdX Chain",
|
||||||
"chainLogo": "dydx-chain.png",
|
"chainLogo": "dydx-chain.png",
|
||||||
|
"squidIntegratorId": "[mainnet squid integrator id]",
|
||||||
"isMainNet": true,
|
"isMainNet": true,
|
||||||
"tokens": {
|
"tokens": {
|
||||||
"comment": "Change according to mainnet release",
|
"comment": "Change according to mainnet release",
|
||||||
@@ -819,10 +1033,20 @@
|
|||||||
"tos": "[HTTP link to TOS]",
|
"tos": "[HTTP link to TOS]",
|
||||||
"privacy": "[HTTP link to Privacy Policy]",
|
"privacy": "[HTTP link to Privacy Policy]",
|
||||||
"mintscan": "[HTTP link to Mintscan, with {tx_hash} placeholder]",
|
"mintscan": "[HTTP link to Mintscan, with {tx_hash} placeholder]",
|
||||||
|
"mintscanBase": "[HTTP link to TOS mintsacn base url]",
|
||||||
|
"feedback": "[HTTP link to feedback form, can be null]",
|
||||||
|
"blogs": "[HTTP link to blogs, can be null]",
|
||||||
|
"foundation": "[HTTP link to foundation, can be null]",
|
||||||
|
"initialMarginFractionLearnMore": "[HTTP link to initial margin fraction learn more, can be null]",
|
||||||
|
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
|
||||||
"documentation": "[HTTP link to documentation, can be null]",
|
"documentation": "[HTTP link to documentation, can be null]",
|
||||||
"community": "[HTTP link to community, can be null]",
|
"community": "[HTTP link to community, can be null]",
|
||||||
"feedback": "[HTTP link to feedback form, can be null]",
|
"help": "[HTTP link to help page, can be null]",
|
||||||
"blogs": "[HTTP link to blogs, can be null]"
|
"governanceLearnMore": "[HTTP link to governance learn more, can be null]",
|
||||||
|
"stakingLearnMore": "[HTTP link to staking learn more, can be null]",
|
||||||
|
"keplrDashboard": "[HTTP link to keplr dashboard, can be null]",
|
||||||
|
"accountExportLearnMore": "[HTTP link to account export learn more, can be null]",
|
||||||
|
"walletLearnMore": "[HTTP link to wallet learn more, can be null]"
|
||||||
},
|
},
|
||||||
"wallets": {
|
"wallets": {
|
||||||
"walletconnect": {
|
"walletconnect": {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
"iosMinVersion": "0",
|
"iosMinVersion": "0",
|
||||||
"imageUrl": "",
|
"imageUrl": "",
|
||||||
"encoding": "=\"#%/<>?@\\^`{|}:&",
|
"encoding": "=\"#%/<>?@\\^`{|}:&",
|
||||||
|
"androidPackage": "io.metamask",
|
||||||
"connections": [
|
"connections": [
|
||||||
{
|
{
|
||||||
"type": "walletConnectV2",
|
"type": "walletConnectV2",
|
||||||
@@ -98,6 +99,7 @@
|
|||||||
"iosMinVersion": "1.8.0",
|
"iosMinVersion": "1.8.0",
|
||||||
"imageUrl": "",
|
"imageUrl": "",
|
||||||
"encoding": "=\"#%/<>?@\\^`{|}:&",
|
"encoding": "=\"#%/<>?@\\^`{|}:&",
|
||||||
|
"androidPackage": "org.toshi",
|
||||||
"connections": [
|
"connections": [
|
||||||
{
|
{
|
||||||
"type": "walletSegue",
|
"type": "walletSegue",
|
||||||
@@ -155,6 +157,7 @@
|
|||||||
"comment": "imToken",
|
"comment": "imToken",
|
||||||
"iosMinVersion": "0",
|
"iosMinVersion": "0",
|
||||||
"imageUrl": "",
|
"imageUrl": "",
|
||||||
|
"androidPackage": "im.token.app",
|
||||||
"connections": [
|
"connections": [
|
||||||
{
|
{
|
||||||
"type": "walletConnectV2",
|
"type": "walletConnectV2",
|
||||||
@@ -214,6 +217,7 @@
|
|||||||
"iosMinVersion": "0",
|
"iosMinVersion": "0",
|
||||||
"encoding": "=\"#%/<>?@\\^`{|}:&",
|
"encoding": "=\"#%/<>?@\\^`{|}:&",
|
||||||
"imageUrl": "",
|
"imageUrl": "",
|
||||||
|
"androidPackage": "com.wallet.crypto.trustapp",
|
||||||
"connections": [
|
"connections": [
|
||||||
{
|
{
|
||||||
"type": "walletConnectV2",
|
"type": "walletConnectV2",
|
||||||
@@ -271,6 +275,7 @@
|
|||||||
"iosMinVersion": "0",
|
"iosMinVersion": "0",
|
||||||
"encoding": "=\"#%/<>?@\\^`{|}:&",
|
"encoding": "=\"#%/<>?@\\^`{|}:&",
|
||||||
"imageUrl": "",
|
"imageUrl": "",
|
||||||
|
"androidPackage": "io.zerion.android",
|
||||||
"connections": [
|
"connections": [
|
||||||
{
|
{
|
||||||
"type": "walletConnectV2",
|
"type": "walletConnectV2",
|
||||||
@@ -327,6 +332,7 @@
|
|||||||
"comment": "TokenPocket",
|
"comment": "TokenPocket",
|
||||||
"iosMinVersion": "0",
|
"iosMinVersion": "0",
|
||||||
"imageUrl": "",
|
"imageUrl": "",
|
||||||
|
"androidPackage": "vip.mytokenpocket",
|
||||||
"connections": [
|
"connections": [
|
||||||
{
|
{
|
||||||
"type": "walletConnectV2",
|
"type": "walletConnectV2",
|
||||||
@@ -383,6 +389,7 @@
|
|||||||
"comment": "Rainbow",
|
"comment": "Rainbow",
|
||||||
"iosMinVersion": "0",
|
"iosMinVersion": "0",
|
||||||
"encoding": "=\"#%/<>?@\\^`{|}:&",
|
"encoding": "=\"#%/<>?@\\^`{|}:&",
|
||||||
|
"androidPackage": "me.rainbow",
|
||||||
"backlinked": true,
|
"backlinked": true,
|
||||||
"imageUrl": "",
|
"imageUrl": "",
|
||||||
"connections": [
|
"connections": [
|
||||||
@@ -442,6 +449,7 @@
|
|||||||
"comment": "1inch",
|
"comment": "1inch",
|
||||||
"iosMinVersion": "0",
|
"iosMinVersion": "0",
|
||||||
"encoding": "=\"#%/<>?@\\^`{|}:&",
|
"encoding": "=\"#%/<>?@\\^`{|}:&",
|
||||||
|
"androidPackage": "io.oneinch.android",
|
||||||
"imageUrl": "",
|
"imageUrl": "",
|
||||||
"connections": [
|
"connections": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
## App Integrations
|
||||||
|
### Amplitude
|
||||||
|
Analytics service used to collect data to help the dYdX Product team make informed product decisions.
|
||||||
|
|
||||||
|
<b>To use with dydxprotocol/v4-web:</b>
|
||||||
|
1. Amplitude account with API key.
|
||||||
|
2. Add API key in Github > Secrets and Variables > Actions as `AMPLITUDE_API_KEY`
|
||||||
|
3. In your deploy scripts add `pnpm run build:inject-amplitude` after your pnpm build / vite build command.
|
||||||
|
|
||||||
|
### Bugsnag
|
||||||
|
Error handling service used to collect handled/unhandled errors within the app. The information collected is used to help debug and alert the engineering team of crashes/unhandled errors within the app to improve stability.
|
||||||
|
|
||||||
|
<b>To use with dydxprotocol/v4-web:</b>
|
||||||
|
1. Bugsnag account with API key.
|
||||||
|
2. Add API key in Github > Secrets and Variables > Actions as `BUGSNAG_API_KEY`
|
||||||
|
3. In your deploy scripts add `pnpm run build:inject-bugsnag` after your pnpm build / vite build command.
|
||||||
|
4. If you are using with the Amplitude deployment scripts, your build command may look like the following: `pnpm build && pnpm run build:inject-amplitude && pnpm run build:inject-bugsnag`
|
||||||
|
|
||||||
|
### StatusPage
|
||||||
|
Service used to inform users of any status updates to our platform. These status updates are manually set and updated by the On Call engineers.
|
||||||
|
|
||||||
|
<b>To use with dydxprotocol/v4-web:</b>
|
||||||
|
1. StatusPage account and script URI
|
||||||
|
2. Add API key in Github > Secrets and Variables > Actions as `STATUS_PAGE_SCRIPT_URI`
|
||||||
|
3. In your deploy scripts add `pnpm run build:inject-statuspage` after your pnpm build / vite build command.
|
||||||
|
4. If you are using with the Amplitude deployment scripts, your build command may look like the following: `pnpm build && pnpm run build:inject-amplitude && pnpm run build:inject-statuspage`
|
||||||
|
|
||||||
|
### Intercom
|
||||||
|
Service used for live customer support (chat/inbox) as well as home for Help Articles.
|
||||||
|
|
||||||
|
<b>To use with dydxprotocol/v4-web:</b>
|
||||||
|
1. Create Intercom account
|
||||||
|
2. In Intercom UI
|
||||||
|
Getting started > Set up Messenger > will give you your API Key on Step 2
|
||||||
|
Customize Intercom Messenger by adding logo and brand colors
|
||||||
|
3. Add API key in Github > Secrets and Variables > Actions as `INTERCOM_APP_ID`
|
||||||
|
4. In your deploy scripts add `pnpm run build:inject-intercom` after your pnpm build / vite build command.
|
||||||
|
5. If you are using with the Amplitude deployment scripts, your build command may look like the following: `pnpm build && pnpm run build:inject-amplitude && pnpm run build:inject-intercom`
|
||||||
@@ -80,7 +80,7 @@ Styled.TriggerIcon = styled.span`
|
|||||||
width: var(--trigger-icon-width);
|
width: var(--trigger-icon-width);
|
||||||
|
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
transition: transform 0.3s var(--ease-out-expo);
|
transition: rotate 0.3s var(--ease-out-expo);
|
||||||
color: var(--trigger-icon-color);
|
color: var(--trigger-icon-color);
|
||||||
|
|
||||||
${Styled.Trigger}[data-state='open'] & {
|
${Styled.Trigger}[data-state='open'] & {
|
||||||
|
|||||||
@@ -225,6 +225,7 @@ Styled.CollapsibleContent = styled(CollapsibleContent)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.IconButton = styled(IconButton)`
|
Styled.IconButton = styled(IconButton)`
|
||||||
|
--button-icon-size: 1em;
|
||||||
${Styled.CollapsibleRoot}[data-state='closed'] & {
|
${Styled.CollapsibleRoot}[data-state='closed'] & {
|
||||||
rotate: -0.5turn;
|
rotate: -0.5turn;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ type PickDialogProps = Pick<
|
|||||||
| 'slotHeaderInner'
|
| 'slotHeaderInner'
|
||||||
| 'slotTrigger'
|
| 'slotTrigger'
|
||||||
| 'slotFooter'
|
| 'slotFooter'
|
||||||
|
| 'preventClose'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export const ComboboxDialogMenu = <
|
export const ComboboxDialogMenu = <
|
||||||
@@ -57,6 +58,7 @@ export const ComboboxDialogMenu = <
|
|||||||
children,
|
children,
|
||||||
|
|
||||||
placement = DialogPlacement.Default,
|
placement = DialogPlacement.Default,
|
||||||
|
preventClose,
|
||||||
className,
|
className,
|
||||||
}: ElementProps<MenuItemValue, MenuGroupValue> &
|
}: ElementProps<MenuItemValue, MenuGroupValue> &
|
||||||
PickComboxMenuProps<MenuItemValue, MenuGroupValue> &
|
PickComboxMenuProps<MenuItemValue, MenuGroupValue> &
|
||||||
@@ -72,6 +74,7 @@ export const ComboboxDialogMenu = <
|
|||||||
slotTrigger={slotTrigger}
|
slotTrigger={slotTrigger}
|
||||||
slotFooter={slotFooter}
|
slotFooter={slotFooter}
|
||||||
placement={placement}
|
placement={placement}
|
||||||
|
preventClose={preventClose}
|
||||||
className={className}
|
className={className}
|
||||||
>
|
>
|
||||||
<Styled.ComboboxMenu
|
<Styled.ComboboxMenu
|
||||||
|
|||||||
@@ -33,9 +33,11 @@ export const DropdownHeaderMenu = <MenuItemValue extends string>({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Root>
|
<Root>
|
||||||
<Styled.Trigger className={className}>
|
<Styled.Trigger className={className} asChild>
|
||||||
|
<div>
|
||||||
{children}
|
{children}
|
||||||
<Styled.DropdownIconButton iconName={IconName.Caret} isToggle />
|
<Styled.DropdownIconButton iconName={IconName.Caret} isToggle />
|
||||||
|
</div>
|
||||||
</Styled.Trigger>
|
</Styled.Trigger>
|
||||||
<Portal>
|
<Portal>
|
||||||
<Styled.Content
|
<Styled.Content
|
||||||
|
|||||||
+10
-1
@@ -24,9 +24,10 @@ import {
|
|||||||
CommentIcon,
|
CommentIcon,
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
CubeIcon,
|
CubeIcon,
|
||||||
|
DepositIcon,
|
||||||
|
DepthChartIcon,
|
||||||
DiscordIcon,
|
DiscordIcon,
|
||||||
EtherscanIcon,
|
EtherscanIcon,
|
||||||
DepthChartIcon,
|
|
||||||
ExportKeysIcon,
|
ExportKeysIcon,
|
||||||
FeedbackIcon,
|
FeedbackIcon,
|
||||||
FileIcon,
|
FileIcon,
|
||||||
@@ -40,6 +41,7 @@ import {
|
|||||||
LockIcon,
|
LockIcon,
|
||||||
LogoShortIcon,
|
LogoShortIcon,
|
||||||
MenuIcon,
|
MenuIcon,
|
||||||
|
MigrateIcon,
|
||||||
MintscanIcon,
|
MintscanIcon,
|
||||||
OrderbookIcon,
|
OrderbookIcon,
|
||||||
OrderCanceledIcon,
|
OrderCanceledIcon,
|
||||||
@@ -68,6 +70,7 @@ import {
|
|||||||
WarningIcon,
|
WarningIcon,
|
||||||
WebsiteIcon,
|
WebsiteIcon,
|
||||||
WhitepaperIcon,
|
WhitepaperIcon,
|
||||||
|
WithdrawIcon,
|
||||||
} from '@/icons';
|
} from '@/icons';
|
||||||
|
|
||||||
export enum IconName {
|
export enum IconName {
|
||||||
@@ -92,6 +95,7 @@ export enum IconName {
|
|||||||
Comment = 'Comment',
|
Comment = 'Comment',
|
||||||
Copy = 'Copy',
|
Copy = 'Copy',
|
||||||
Cube = 'Cube',
|
Cube = 'Cube',
|
||||||
|
Deposit = 'Deposit',
|
||||||
DepthChart = 'DepthChart',
|
DepthChart = 'DepthChart',
|
||||||
Discord = 'Discord',
|
Discord = 'Discord',
|
||||||
Etherscan = 'Etherscan',
|
Etherscan = 'Etherscan',
|
||||||
@@ -108,6 +112,7 @@ export enum IconName {
|
|||||||
Lock = 'Lock',
|
Lock = 'Lock',
|
||||||
LogoShort = 'LogoShort',
|
LogoShort = 'LogoShort',
|
||||||
Menu = 'Menu',
|
Menu = 'Menu',
|
||||||
|
Migrate = 'Migrate',
|
||||||
Mintscan = 'Mintscan',
|
Mintscan = 'Mintscan',
|
||||||
Onboarding = 'Onboarding',
|
Onboarding = 'Onboarding',
|
||||||
Orderbook = 'OrderbookIcon',
|
Orderbook = 'OrderbookIcon',
|
||||||
@@ -137,6 +142,7 @@ export enum IconName {
|
|||||||
Warning = 'Warning',
|
Warning = 'Warning',
|
||||||
Website = 'Website',
|
Website = 'Website',
|
||||||
Whitepaper = 'Whitepaper',
|
Whitepaper = 'Whitepaper',
|
||||||
|
Withdraw = 'Withdraw',
|
||||||
}
|
}
|
||||||
|
|
||||||
const icons = {
|
const icons = {
|
||||||
@@ -161,6 +167,7 @@ const icons = {
|
|||||||
[IconName.Comment]: CommentIcon,
|
[IconName.Comment]: CommentIcon,
|
||||||
[IconName.Copy]: CopyIcon,
|
[IconName.Copy]: CopyIcon,
|
||||||
[IconName.Cube]: CubeIcon,
|
[IconName.Cube]: CubeIcon,
|
||||||
|
[IconName.Deposit]: DepositIcon,
|
||||||
[IconName.DepthChart]: DepthChartIcon,
|
[IconName.DepthChart]: DepthChartIcon,
|
||||||
[IconName.Discord]: DiscordIcon,
|
[IconName.Discord]: DiscordIcon,
|
||||||
[IconName.Etherscan]: EtherscanIcon,
|
[IconName.Etherscan]: EtherscanIcon,
|
||||||
@@ -177,6 +184,7 @@ const icons = {
|
|||||||
[IconName.Lock]: LockIcon,
|
[IconName.Lock]: LockIcon,
|
||||||
[IconName.LogoShort]: LogoShortIcon,
|
[IconName.LogoShort]: LogoShortIcon,
|
||||||
[IconName.Menu]: MenuIcon,
|
[IconName.Menu]: MenuIcon,
|
||||||
|
[IconName.Migrate]: MigrateIcon,
|
||||||
[IconName.Mintscan]: MintscanIcon,
|
[IconName.Mintscan]: MintscanIcon,
|
||||||
[IconName.Orderbook]: OrderbookIcon,
|
[IconName.Orderbook]: OrderbookIcon,
|
||||||
[IconName.OrderCanceled]: OrderCanceledIcon,
|
[IconName.OrderCanceled]: OrderCanceledIcon,
|
||||||
@@ -205,6 +213,7 @@ const icons = {
|
|||||||
[IconName.Warning]: WarningIcon,
|
[IconName.Warning]: WarningIcon,
|
||||||
[IconName.Website]: WebsiteIcon,
|
[IconName.Website]: WebsiteIcon,
|
||||||
[IconName.Whitepaper]: WhitepaperIcon,
|
[IconName.Whitepaper]: WhitepaperIcon,
|
||||||
|
[IconName.Withdraw]: WithdrawIcon,
|
||||||
} as Record<IconName, ElementType>;
|
} as Record<IconName, ElementType>;
|
||||||
|
|
||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ const Styled: Record<string, AnyStyledComponent> = {};
|
|||||||
const buttonMixin = css`
|
const buttonMixin = css`
|
||||||
// Params
|
// Params
|
||||||
--button-icon-size: 1.125em;
|
--button-icon-size: 1.125em;
|
||||||
|
--button-padding: 0;
|
||||||
|
|
||||||
// Rules
|
// Rules
|
||||||
> * {
|
> * {
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ const NavItem = forwardRef(
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
{slotAfter}
|
{slotAfter}
|
||||||
{subitems?.length && <Styled.Icon iconName={IconName.Caret} />}
|
{subitems?.length && <Styled.Icon iconName={IconName.Triangle} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -525,6 +525,9 @@ Styled.NavItem = styled(NavItem)<{ orientation: 'horizontal' | 'vertical' }>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Icon = styled(Icon)`
|
Styled.Icon = styled(Icon)`
|
||||||
|
font-size: 0.375em;
|
||||||
|
transition: rotate 0.3s var(--ease-out-expo);
|
||||||
|
|
||||||
${Styled.List}[data-orientation="menu"] & {
|
${Styled.List}[data-orientation="menu"] & {
|
||||||
rotate: -0.25turn;
|
rotate: -0.25turn;
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-27
@@ -8,6 +8,7 @@ import { layoutMixins } from '@/styles/layoutMixins';
|
|||||||
type PanelProps = {
|
type PanelProps = {
|
||||||
slotHeaderContent?: string;
|
slotHeaderContent?: string;
|
||||||
slotHeader?: React.ReactNode;
|
slotHeader?: React.ReactNode;
|
||||||
|
slotRight?: React.ReactNode;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
href?: string;
|
href?: string;
|
||||||
onHeaderClick?: () => void;
|
onHeaderClick?: () => void;
|
||||||
@@ -22,6 +23,7 @@ type PanelStyleProps = {
|
|||||||
export const Panel = ({
|
export const Panel = ({
|
||||||
slotHeaderContent,
|
slotHeaderContent,
|
||||||
slotHeader,
|
slotHeader,
|
||||||
|
slotRight,
|
||||||
children,
|
children,
|
||||||
href,
|
href,
|
||||||
onHeaderClick,
|
onHeaderClick,
|
||||||
@@ -29,56 +31,80 @@ export const Panel = ({
|
|||||||
hasSeparator,
|
hasSeparator,
|
||||||
className,
|
className,
|
||||||
}: PanelProps & PanelStyleProps) => (
|
}: PanelProps & PanelStyleProps) => (
|
||||||
<Styled.Panel onClick={onClick}>
|
<Styled.Panel onClick={onClick} className={className}>
|
||||||
{href ? (
|
<Styled.Left>
|
||||||
<Link to={href}>
|
{href ? (
|
||||||
{slotHeader ? (
|
<Link to={href}>
|
||||||
slotHeader
|
{slotHeader ? (
|
||||||
) : (
|
slotHeader
|
||||||
|
) : (
|
||||||
|
<Styled.Header role="button" onClick={onHeaderClick} hasSeparator={hasSeparator}>
|
||||||
|
{slotHeaderContent}
|
||||||
|
<Styled.Icon iconName={IconName.ChevronRight} />
|
||||||
|
</Styled.Header>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
) : slotHeader ? (
|
||||||
|
slotHeader
|
||||||
|
) : (
|
||||||
|
slotHeaderContent && (
|
||||||
<Styled.Header role="button" onClick={onHeaderClick} hasSeparator={hasSeparator}>
|
<Styled.Header role="button" onClick={onHeaderClick} hasSeparator={hasSeparator}>
|
||||||
{slotHeaderContent}
|
{slotHeaderContent}
|
||||||
<Styled.Icon iconName={IconName.ChevronRight} />
|
|
||||||
</Styled.Header>
|
</Styled.Header>
|
||||||
)}
|
)
|
||||||
</Link>
|
)}
|
||||||
) : slotHeader ? (
|
<Styled.Content>{children}</Styled.Content>
|
||||||
slotHeader
|
</Styled.Left>
|
||||||
) : (
|
{slotRight}
|
||||||
slotHeaderContent && (
|
|
||||||
<Styled.Header role="button" onClick={onHeaderClick} hasSeparator={hasSeparator}>
|
|
||||||
{slotHeaderContent}
|
|
||||||
</Styled.Header>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
<Styled.Content className={className}>{children}</Styled.Content>
|
|
||||||
</Styled.Panel>
|
</Styled.Panel>
|
||||||
);
|
);
|
||||||
|
|
||||||
const Styled: Record<string, AnyStyledComponent> = {};
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
Styled.Panel = styled.section`
|
Styled.Panel = styled.section<{ onClick?: () => void }>`
|
||||||
${layoutMixins.flexColumn}
|
--panel-paddingY: 1rem;
|
||||||
|
--panel-paddingX: 1rem;
|
||||||
|
--panel-content-paddingY: var(--panel-paddingY);
|
||||||
|
--panel-content-paddingX: var(--panel-paddingX);
|
||||||
|
|
||||||
|
${layoutMixins.row}
|
||||||
|
|
||||||
background-color: var(--color-layer-3);
|
background-color: var(--color-layer-3);
|
||||||
border-radius: 0.875rem;
|
border-radius: 0.875rem;
|
||||||
|
|
||||||
|
${({ onClick }) =>
|
||||||
|
onClick &&
|
||||||
|
css`
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
button:not(:disabled) {
|
||||||
|
color: var(--button-hover-textColor);
|
||||||
|
filter: var(--button-hover-filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Left = styled.div`
|
||||||
|
${layoutMixins.flexColumn}
|
||||||
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Header = styled.header<{ hasSeparator?: boolean }>`
|
Styled.Header = styled.header<{ hasSeparator?: boolean }>`
|
||||||
${layoutMixins.spacedRow}
|
${layoutMixins.spacedRow}
|
||||||
|
padding: var(--panel-paddingY) var(--panel-paddingX);
|
||||||
padding: 0.875rem 1rem 0.625rem;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
|
|
||||||
${({ hasSeparator }) =>
|
${({ hasSeparator }) =>
|
||||||
hasSeparator &&
|
hasSeparator &&
|
||||||
css`
|
css`
|
||||||
|
padding-bottom: 0.625rem;
|
||||||
box-shadow: 0 var(--border-width) var(--border-color);
|
box-shadow: 0 var(--border-width) var(--border-color);
|
||||||
`}
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Icon = styled(Icon)`
|
Styled.Icon = styled(Icon)`
|
||||||
color: var(--color-text-0);
|
color: var(--color-text-0);
|
||||||
|
|
||||||
font-size: 0.625rem;
|
font-size: 0.625rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -86,6 +112,5 @@ Styled.Content = styled.div`
|
|||||||
${layoutMixins.scrollArea}
|
${layoutMixins.scrollArea}
|
||||||
${layoutMixins.stickyArea0}
|
${layoutMixins.stickyArea0}
|
||||||
--stickyArea0-background: transparent;
|
--stickyArea0-background: transparent;
|
||||||
|
padding: var(--panel-content-paddingY) var(--panel-content-paddingX);
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -7,13 +7,15 @@ import { ButtonShape, ButtonSize } from '@/constants/buttons';
|
|||||||
import { useBreakpoints } from '@/hooks';
|
import { useBreakpoints } from '@/hooks';
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
import { type BaseButtonProps } from '@/components/BaseButton';
|
import { type BaseButtonProps } from '@/components/BaseButton';
|
||||||
import { ToggleButton } from '@/components/ToggleButton';
|
import { ToggleButton } from '@/components/ToggleButton';
|
||||||
|
|
||||||
type ElementProps<MenuItemValue extends string> = {
|
type ElementProps<MenuItemValue extends string> = {
|
||||||
items: MenuItem<MenuItemValue>[];
|
items: MenuItem<MenuItemValue>[];
|
||||||
value: MenuItemValue;
|
value: MenuItemValue;
|
||||||
onValueChange: (value: MenuItemValue) => void;
|
onValueChange: (value: any) => void;
|
||||||
|
onInteraction?: () => void;
|
||||||
|
ensureSelected?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StyleProps = {
|
type StyleProps = {
|
||||||
@@ -25,10 +27,14 @@ export const ToggleGroup = forwardRef(
|
|||||||
{
|
{
|
||||||
items,
|
items,
|
||||||
value,
|
value,
|
||||||
|
ensureSelected = true,
|
||||||
onValueChange,
|
onValueChange,
|
||||||
|
onInteraction,
|
||||||
|
|
||||||
className,
|
className,
|
||||||
size,
|
size,
|
||||||
shape = ButtonShape.Pill,
|
shape = ButtonShape.Pill,
|
||||||
|
|
||||||
...buttonProps
|
...buttonProps
|
||||||
}: ElementProps<MenuItemValue> & StyleProps & BaseButtonProps,
|
}: ElementProps<MenuItemValue> & StyleProps & BaseButtonProps,
|
||||||
ref: Ref<HTMLDivElement>
|
ref: Ref<HTMLDivElement>
|
||||||
@@ -40,12 +46,17 @@ export const ToggleGroup = forwardRef(
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
type="single"
|
type="single"
|
||||||
value={value}
|
value={value}
|
||||||
onValueChange={onValueChange}
|
onValueChange={(newValue: MenuItemValue) => {
|
||||||
|
if ((ensureSelected && newValue) || !ensureSelected) {
|
||||||
|
onValueChange(newValue);
|
||||||
|
}
|
||||||
|
onInteraction?.();
|
||||||
|
}}
|
||||||
className={className}
|
className={className}
|
||||||
loop
|
loop
|
||||||
>
|
>
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
<Item key={item.value} value={item.value} aria-label={item.label} asChild>
|
<Item key={item.value} value={item.value} asChild>
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
size={size ? size : isTablet ? ButtonSize.Small : ButtonSize.XSmall}
|
size={size ? size : isTablet ? ButtonSize.Small : ButtonSize.XSmall}
|
||||||
shape={shape}
|
shape={shape}
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ import type { ReactNode } from 'react';
|
|||||||
import styled, { AnyStyledComponent } from 'styled-components';
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
import { Content, Portal, Provider, Root, Trigger, Arrow } from '@radix-ui/react-tooltip';
|
import { Content, Portal, Provider, Root, Trigger, Arrow } from '@radix-ui/react-tooltip';
|
||||||
|
|
||||||
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { tooltipStrings } from '@/constants/tooltips';
|
import { tooltipStrings } from '@/constants/tooltips';
|
||||||
|
|
||||||
import { useStringGetter } from '@/hooks';
|
import { useStringGetter, useURLConfigs } from '@/hooks';
|
||||||
|
|
||||||
import { Icon, IconName } from '@/components/Icon';
|
import { Icon, IconName } from '@/components/Icon';
|
||||||
|
import { Link } from '@/components/Link';
|
||||||
|
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
import { popoverMixins } from '@/styles/popoverMixins';
|
import { popoverMixins } from '@/styles/popoverMixins';
|
||||||
@@ -38,20 +40,24 @@ export const WithTooltip = ({
|
|||||||
slotTooltip,
|
slotTooltip,
|
||||||
}: ElementProps & StyleProps) => {
|
}: ElementProps & StyleProps) => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
|
const urlConfigs = useURLConfigs();
|
||||||
|
|
||||||
const getTooltipStrings = tooltip && tooltipStrings[tooltip];
|
const getTooltipStrings = tooltip && tooltipStrings[tooltip];
|
||||||
if (!getTooltipStrings && !tooltipString && !slotTooltip) return <>{children}</>;
|
if (!getTooltipStrings && !tooltipString && !slotTooltip) return <>{children}</>;
|
||||||
|
|
||||||
let tooltipTitle;
|
let tooltipTitle;
|
||||||
let tooltipBody;
|
let tooltipBody;
|
||||||
|
let tooltipLearnMore;
|
||||||
|
|
||||||
if (getTooltipStrings) {
|
if (getTooltipStrings) {
|
||||||
const { title, body } = getTooltipStrings({
|
const { title, body, learnMoreLink } = getTooltipStrings({
|
||||||
stringGetter,
|
stringGetter,
|
||||||
stringParams,
|
stringParams,
|
||||||
|
urlConfigs,
|
||||||
});
|
});
|
||||||
tooltipTitle = title;
|
tooltipTitle = title;
|
||||||
tooltipBody = body;
|
tooltipBody = body;
|
||||||
|
tooltipLearnMore = learnMoreLink;
|
||||||
} else {
|
} else {
|
||||||
tooltipBody = tooltipString;
|
tooltipBody = tooltipString;
|
||||||
}
|
}
|
||||||
@@ -72,6 +78,13 @@ export const WithTooltip = ({
|
|||||||
<dl>
|
<dl>
|
||||||
{tooltipTitle && <dt>{tooltipTitle}</dt>}
|
{tooltipTitle && <dt>{tooltipTitle}</dt>}
|
||||||
{tooltipBody && <dd>{tooltipBody}</dd>}
|
{tooltipBody && <dd>{tooltipBody}</dd>}
|
||||||
|
{tooltipLearnMore && (
|
||||||
|
<dd>
|
||||||
|
<Styled.LearnMore href={tooltipLearnMore}>
|
||||||
|
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} →
|
||||||
|
</Styled.LearnMore>
|
||||||
|
</dd>
|
||||||
|
)}
|
||||||
<Styled.Arrow />
|
<Styled.Arrow />
|
||||||
</dl>
|
</dl>
|
||||||
)}
|
)}
|
||||||
@@ -142,3 +155,7 @@ Styled.Arrow = styled(Arrow)`
|
|||||||
Styled.Icon = styled(Icon)`
|
Styled.Icon = styled(Icon)`
|
||||||
color: var(--color-text-0);
|
color: var(--color-text-0);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
Styled.LearnMore = styled(Link)`
|
||||||
|
--link-color: var(--color-accent);
|
||||||
|
`;
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import {
|
|||||||
WARNINGS_STRING_KEYS,
|
WARNINGS_STRING_KEYS,
|
||||||
} from '@dydxprotocol/v4-localization';
|
} from '@dydxprotocol/v4-localization';
|
||||||
|
|
||||||
|
import { type LinksConfigs } from '@/hooks/useURLConfigs';
|
||||||
|
|
||||||
export { TOOLTIP_STRING_KEYS } from '@dydxprotocol/v4-localization';
|
export { TOOLTIP_STRING_KEYS } from '@dydxprotocol/v4-localization';
|
||||||
|
|
||||||
export enum SupportedLocales {
|
export enum SupportedLocales {
|
||||||
@@ -79,9 +81,11 @@ export type TooltipStrings = {
|
|||||||
[key: string]: ({
|
[key: string]: ({
|
||||||
stringGetter,
|
stringGetter,
|
||||||
stringParams,
|
stringParams,
|
||||||
|
urlConfigs,
|
||||||
}: {
|
}: {
|
||||||
stringGetter: StringGetterFunction;
|
stringGetter: StringGetterFunction;
|
||||||
stringParams?: any;
|
stringParams?: any;
|
||||||
|
urlConfigs?: LinksConfigs;
|
||||||
}) => {
|
}) => {
|
||||||
title: string;
|
title: string;
|
||||||
body: string;
|
body: string;
|
||||||
|
|||||||
@@ -37,7 +37,3 @@ export const HISTORY_ROUTE = `${AppRoute.Portfolio}/${PortfolioRoute.History}/:s
|
|||||||
export const DEFAULT_TRADE_ROUTE = `${AppRoute.Trade}/${DEFAULT_MARKETID}`;
|
export const DEFAULT_TRADE_ROUTE = `${AppRoute.Trade}/${DEFAULT_MARKETID}`;
|
||||||
export const SETTINGS_ROUTE = `${AppRoute.Settings}/*`;
|
export const SETTINGS_ROUTE = `${AppRoute.Settings}/*`;
|
||||||
export const DEFAULT_DOCUMENT_TITLE = 'dYdX';
|
export const DEFAULT_DOCUMENT_TITLE = 'dYdX';
|
||||||
|
|
||||||
export enum ExternalLink {
|
|
||||||
Foundation = 'https://dydx.foundation',
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -57,10 +57,10 @@ export const tradeTooltips: TooltipStrings = {
|
|||||||
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INDEX_PRICE_TITLE }),
|
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INDEX_PRICE_TITLE }),
|
||||||
body: stringGetter({ key: TOOLTIP_STRING_KEYS.INDEX_PRICE_BODY }),
|
body: stringGetter({ key: TOOLTIP_STRING_KEYS.INDEX_PRICE_BODY }),
|
||||||
}),
|
}),
|
||||||
'initial-margin-fraction': ({ stringGetter }) => ({
|
'initial-margin-fraction': ({ stringGetter, urlConfigs }) => ({
|
||||||
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_MARGIN_FRACTION_TITLE }),
|
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_MARGIN_FRACTION_TITLE }),
|
||||||
body: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_MARGIN_FRACTION_BODY }),
|
body: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_MARGIN_FRACTION_BODY }),
|
||||||
learnMoreLink: 'https://help.dydx.exchange/articles/5232637-maximum-position-sizes',
|
learnMoreLink: urlConfigs?.initialMarginFractionLearnMore,
|
||||||
}),
|
}),
|
||||||
'initial-stop': ({ stringGetter }) => ({
|
'initial-stop': ({ stringGetter }) => ({
|
||||||
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_STOP_TITLE }),
|
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_STOP_TITLE }),
|
||||||
@@ -146,10 +146,10 @@ export const tradeTooltips: TooltipStrings = {
|
|||||||
title: stringGetter({ key: TOOLTIP_STRING_KEYS.REALIZED_PNL_TITLE }),
|
title: stringGetter({ key: TOOLTIP_STRING_KEYS.REALIZED_PNL_TITLE }),
|
||||||
body: stringGetter({ key: TOOLTIP_STRING_KEYS.REALIZED_PNL_BODY }),
|
body: stringGetter({ key: TOOLTIP_STRING_KEYS.REALIZED_PNL_BODY }),
|
||||||
}),
|
}),
|
||||||
'reduce-only': ({ stringGetter }) => ({
|
'reduce-only': ({ stringGetter, urlConfigs }) => ({
|
||||||
title: stringGetter({ key: TOOLTIP_STRING_KEYS.REDUCE_ONLY_TITLE }),
|
title: stringGetter({ key: TOOLTIP_STRING_KEYS.REDUCE_ONLY_TITLE }),
|
||||||
body: stringGetter({ key: TOOLTIP_STRING_KEYS.REDUCE_ONLY_BODY }),
|
body: stringGetter({ key: TOOLTIP_STRING_KEYS.REDUCE_ONLY_BODY }),
|
||||||
learnMoreLink: 'https://help.dydx.exchange/articles/6345793-reduce-only-orders',
|
learnMoreLink: urlConfigs?.reduceOnlyLearnMore,
|
||||||
}),
|
}),
|
||||||
spread: () => ({
|
spread: () => ({
|
||||||
title: 'Spread',
|
title: 'Spread',
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { useShouldShowFooter } from './useShouldShowFooter';
|
|||||||
import { useSelectedNetwork } from './useSelectedNetwork';
|
import { useSelectedNetwork } from './useSelectedNetwork';
|
||||||
import { useStringGetter } from './useStringGetter';
|
import { useStringGetter } from './useStringGetter';
|
||||||
import { useSubaccount } from './useSubaccount';
|
import { useSubaccount } from './useSubaccount';
|
||||||
|
import { useURLConfigs } from './useURLConfigs';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
useApiState,
|
useApiState,
|
||||||
@@ -48,4 +49,5 @@ export {
|
|||||||
useSelectedNetwork,
|
useSelectedNetwork,
|
||||||
useStringGetter,
|
useStringGetter,
|
||||||
useSubaccount,
|
useSubaccount,
|
||||||
|
useURLConfigs,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import { MarketFilters, MARKET_FILTER_LABELS, type MarketData } from '@/constant
|
|||||||
import { getAssets } from '@/state/assetsSelectors';
|
import { getAssets } from '@/state/assetsSelectors';
|
||||||
import { getPerpetualMarkets } from '@/state/perpetualsSelectors';
|
import { getPerpetualMarkets } from '@/state/perpetualsSelectors';
|
||||||
|
|
||||||
|
import { isTruthy } from '@/lib/isTruthy';
|
||||||
|
|
||||||
const filterFunctions = {
|
const filterFunctions = {
|
||||||
[MarketFilters.ALL]: (market: MarketData) => true,
|
[MarketFilters.ALL]: () => true,
|
||||||
[MarketFilters.LAYER_1]: (market: MarketData) => {
|
[MarketFilters.LAYER_1]: (market: MarketData) => {
|
||||||
return market.asset.tags?.toArray().includes('Layer 1');
|
return market.asset.tags?.toArray().includes('Layer 1');
|
||||||
},
|
},
|
||||||
@@ -28,13 +30,15 @@ export const useMarketsData = (
|
|||||||
const allAssets = useSelector(getAssets, shallowEqual) || {};
|
const allAssets = useSelector(getAssets, shallowEqual) || {};
|
||||||
|
|
||||||
const markets = useMemo(() => {
|
const markets = useMemo(() => {
|
||||||
return Object.values(allPerpetualMarkets).map((marketData) => ({
|
return Object.values(allPerpetualMarkets)
|
||||||
asset: allAssets[marketData.assetId],
|
.filter(isTruthy)
|
||||||
tickSizeDecimals: marketData.configs?.tickSizeDecimals,
|
.map((marketData) => ({
|
||||||
...marketData,
|
asset: allAssets[marketData.assetId],
|
||||||
...marketData.perpetual,
|
tickSizeDecimals: marketData.configs?.tickSizeDecimals,
|
||||||
...marketData.configs,
|
...marketData,
|
||||||
})) as MarketData[];
|
...marketData.perpetual,
|
||||||
|
...marketData.configs,
|
||||||
|
})) as MarketData[];
|
||||||
}, [allPerpetualMarkets, allAssets]);
|
}, [allPerpetualMarkets, allAssets]);
|
||||||
|
|
||||||
const filteredMarkets = useMemo(() => {
|
const filteredMarkets = useMemo(() => {
|
||||||
|
|||||||
@@ -22,7 +22,11 @@ const useSquidContext = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const squid = useMemo(
|
const squid = useMemo(
|
||||||
() => new Squid({ baseUrl: ENVIRONMENT_CONFIG_MAP[selectedNetwork]?.endpoints['0xsquid'] }),
|
() =>
|
||||||
|
new Squid({
|
||||||
|
baseUrl: ENVIRONMENT_CONFIG_MAP[selectedNetwork]?.endpoints['0xsquid'],
|
||||||
|
integratorId: ENVIRONMENT_CONFIG_MAP[selectedNetwork]?.squidIntegratorId,
|
||||||
|
}),
|
||||||
[selectedNetwork]
|
[selectedNetwork]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
+91
-54
@@ -48,7 +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 { usdcDenom, usdcDecimals } = useTokenConfigs();
|
||||||
const { compositeClient, faucetClient } = useDydxClient();
|
const { compositeClient, faucetClient } = useDydxClient();
|
||||||
|
|
||||||
const { getFaucetFunds } = useMemo(
|
const { getFaucetFunds } = useMemo(
|
||||||
@@ -79,16 +79,34 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
subaccountClient: SubaccountClient;
|
subaccountClient: SubaccountClient;
|
||||||
assetId?: number;
|
assetId?: number;
|
||||||
amount: number;
|
amount: number;
|
||||||
}) => await compositeClient?.depositToSubaccount(subaccountClient, amount.toString()),
|
}) => {
|
||||||
|
try {
|
||||||
|
return await compositeClient?.depositToSubaccount(
|
||||||
|
subaccountClient,
|
||||||
|
amount.toFixed(usdcDecimals)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
log('useSubaccount/depositToSubaccount', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
withdrawFromSubaccount: async ({
|
withdrawFromSubaccount: async ({
|
||||||
subaccountClient,
|
subaccountClient,
|
||||||
amount,
|
amount,
|
||||||
}: {
|
}: {
|
||||||
subaccountClient: SubaccountClient;
|
subaccountClient: SubaccountClient;
|
||||||
amount: number;
|
amount: number;
|
||||||
}) => await compositeClient?.withdrawFromSubaccount(subaccountClient, amount.toString()),
|
}) => {
|
||||||
|
try {
|
||||||
|
return await compositeClient?.withdrawFromSubaccount(
|
||||||
|
subaccountClient,
|
||||||
|
amount.toFixed(usdcDecimals)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
log('useSubaccount/withdrawFromSubaccount', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
transferFromSubaccountToAddress: async ({
|
transferFromSubaccountToAddress: async ({
|
||||||
subaccountClient,
|
subaccountClient,
|
||||||
assetId = 0,
|
assetId = 0,
|
||||||
@@ -99,27 +117,33 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
assetId?: number;
|
assetId?: number;
|
||||||
amount: number;
|
amount: number;
|
||||||
recipient: string;
|
recipient: string;
|
||||||
}) =>
|
}) => {
|
||||||
await compositeClient?.validatorClient.post.send(
|
try {
|
||||||
subaccountClient?.wallet,
|
return await compositeClient?.validatorClient.post.send(
|
||||||
() =>
|
subaccountClient?.wallet,
|
||||||
new Promise((resolve) => {
|
() =>
|
||||||
const msg =
|
new Promise((resolve) => {
|
||||||
compositeClient?.validatorClient.post.composer.composeMsgWithdrawFromSubaccount(
|
const msg =
|
||||||
subaccountClient.address,
|
compositeClient?.validatorClient.post.composer.composeMsgWithdrawFromSubaccount(
|
||||||
subaccountClient.subaccountNumber,
|
subaccountClient.address,
|
||||||
assetId,
|
subaccountClient.subaccountNumber,
|
||||||
Long.fromNumber(amount * QUANTUM_MULTIPLIER),
|
assetId,
|
||||||
recipient
|
Long.fromNumber(amount * QUANTUM_MULTIPLIER),
|
||||||
);
|
recipient
|
||||||
|
);
|
||||||
|
|
||||||
resolve([msg]);
|
resolve([msg]);
|
||||||
}),
|
}),
|
||||||
false,
|
false,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
Method.BroadcastTxCommit
|
Method.BroadcastTxCommit
|
||||||
),
|
);
|
||||||
|
} catch (error) {
|
||||||
|
log('useSubaccount/transferFromSubaccountToAddress', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
transferNativeToken: async ({
|
transferNativeToken: async ({
|
||||||
subaccountClient,
|
subaccountClient,
|
||||||
@@ -129,24 +153,30 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
subaccountClient: SubaccountClient;
|
subaccountClient: SubaccountClient;
|
||||||
amount: number;
|
amount: number;
|
||||||
recipient: string;
|
recipient: string;
|
||||||
}) =>
|
}) => {
|
||||||
await compositeClient?.validatorClient.post.send(
|
try {
|
||||||
subaccountClient.wallet,
|
return await compositeClient?.validatorClient.post.send(
|
||||||
() =>
|
subaccountClient.wallet,
|
||||||
new Promise((resolve) => {
|
() =>
|
||||||
const msg = compositeClient?.sendTokenMessage(
|
new Promise((resolve) => {
|
||||||
subaccountClient.wallet,
|
const msg = compositeClient?.sendTokenMessage(
|
||||||
amount.toString(),
|
subaccountClient.wallet,
|
||||||
recipient,
|
amount.toString(),
|
||||||
);
|
recipient
|
||||||
|
);
|
||||||
|
|
||||||
resolve([msg]);
|
resolve([msg]);
|
||||||
}),
|
}),
|
||||||
false,
|
false,
|
||||||
compositeClient?.validatorClient?.post.defaultDydxGasPrice,
|
compositeClient?.validatorClient?.post.defaultDydxGasPrice,
|
||||||
undefined,
|
undefined,
|
||||||
Method.BroadcastTxCommit
|
Method.BroadcastTxCommit
|
||||||
),
|
);
|
||||||
|
} catch (error) {
|
||||||
|
log('useSubaccount/transferNativeToken', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
sendSquidWithdrawFromSubaccount: async ({
|
sendSquidWithdrawFromSubaccount: async ({
|
||||||
subaccountClient,
|
subaccountClient,
|
||||||
@@ -158,20 +188,27 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
|||||||
payload: string;
|
payload: string;
|
||||||
}) => {
|
}) => {
|
||||||
if (!compositeClient) throw new Error('client not initialized');
|
if (!compositeClient) throw new Error('client not initialized');
|
||||||
|
try {
|
||||||
|
const transaction = JSON.parse(payload);
|
||||||
|
|
||||||
const transaction = JSON.parse(payload);
|
const msg = compositeClient.withdrawFromSubaccountMessage(
|
||||||
|
subaccountClient,
|
||||||
|
amount.toFixed(usdcDecimals)
|
||||||
|
);
|
||||||
|
const ibcMsg: EncodeObject = {
|
||||||
|
typeUrl: transaction.msgTypeUrl,
|
||||||
|
value: transaction.msg,
|
||||||
|
};
|
||||||
|
|
||||||
const msg = compositeClient.withdrawFromSubaccountMessage(subaccountClient, amount.toString());
|
return await compositeClient.send(
|
||||||
const ibcMsg: EncodeObject = {
|
subaccountClient.wallet,
|
||||||
typeUrl: transaction.msgTypeUrl,
|
() => Promise.resolve([msg, ibcMsg]),
|
||||||
value: transaction.msg,
|
false
|
||||||
};
|
);
|
||||||
|
} catch (error) {
|
||||||
return await compositeClient.send(
|
log('useSubaccount/sendSquidWithdrawFromSubaccount', error);
|
||||||
subaccountClient.wallet,
|
throw error;
|
||||||
() => Promise.resolve([msg, ibcMsg]),
|
}
|
||||||
false
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[compositeClient]
|
[compositeClient]
|
||||||
|
|||||||
@@ -19,8 +19,10 @@ export const useTokenConfigs = (): {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
usdcDenom: string;
|
usdcDenom: string;
|
||||||
|
usdcDecimals: number;
|
||||||
usdcLabel: string;
|
usdcLabel: string;
|
||||||
chainTokenDenom: string;
|
chainTokenDenom: string;
|
||||||
|
chainTokenDecimals: number;
|
||||||
chainTokenLabel: string;
|
chainTokenLabel: string;
|
||||||
} => {
|
} => {
|
||||||
const { selectedNetwork } = useSelectedNetwork();
|
const { selectedNetwork } = useSelectedNetwork();
|
||||||
@@ -29,8 +31,10 @@ export const useTokenConfigs = (): {
|
|||||||
return {
|
return {
|
||||||
tokensConfigs,
|
tokensConfigs,
|
||||||
usdcDenom: tokensConfigs[DydxChainAsset.USDC].denom,
|
usdcDenom: tokensConfigs[DydxChainAsset.USDC].denom,
|
||||||
|
usdcDecimals: tokensConfigs[DydxChainAsset.USDC].decimals,
|
||||||
usdcLabel: tokensConfigs[DydxChainAsset.USDC].name,
|
usdcLabel: tokensConfigs[DydxChainAsset.USDC].name,
|
||||||
chainTokenDenom: tokensConfigs[DydxChainAsset.CHAINTOKEN].denom,
|
chainTokenDenom: tokensConfigs[DydxChainAsset.CHAINTOKEN].denom,
|
||||||
|
chainTokenDecimals: tokensConfigs[DydxChainAsset.CHAINTOKEN].decimals,
|
||||||
chainTokenLabel: tokensConfigs[DydxChainAsset.CHAINTOKEN].name,
|
chainTokenLabel: tokensConfigs[DydxChainAsset.CHAINTOKEN].name,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||||
|
|
||||||
|
import { useSelectedNetwork } from '@/hooks';
|
||||||
|
|
||||||
|
const FALLBACK_URL = 'https://help.dydx.exchange/';
|
||||||
|
|
||||||
|
export interface LinksConfigs {
|
||||||
|
tos: string,
|
||||||
|
privacy: string,
|
||||||
|
mintscan: string,
|
||||||
|
mintscanBase: string,
|
||||||
|
feedback?: string,
|
||||||
|
help?: string,
|
||||||
|
blogs?: string,
|
||||||
|
foundation?: string,
|
||||||
|
initialMarginFractionLearnMore?: string,
|
||||||
|
reduceOnlyLearnMore?: string,
|
||||||
|
documentation?: string,
|
||||||
|
community?: string,
|
||||||
|
governanceLearnMore?: string,
|
||||||
|
stakingLearnMore?: string,
|
||||||
|
keplrDashboard?: string,
|
||||||
|
accountExportLearnMore?: string,
|
||||||
|
walletLearnMore?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useURLConfigs = (): LinksConfigs => {
|
||||||
|
const { selectedNetwork } = useSelectedNetwork();
|
||||||
|
const linksConfigs = ENVIRONMENT_CONFIG_MAP[selectedNetwork].links as LinksConfigs;
|
||||||
|
|
||||||
|
return {
|
||||||
|
tos: linksConfigs.tos,
|
||||||
|
privacy: linksConfigs.privacy,
|
||||||
|
mintscan: linksConfigs.mintscan,
|
||||||
|
mintscanBase: linksConfigs.mintscanBase,
|
||||||
|
feedback: linksConfigs.feedback || FALLBACK_URL,
|
||||||
|
help: linksConfigs.help || FALLBACK_URL,
|
||||||
|
blogs: linksConfigs.blogs || FALLBACK_URL,
|
||||||
|
foundation: linksConfigs.foundation || FALLBACK_URL,
|
||||||
|
initialMarginFractionLearnMore: linksConfigs.initialMarginFractionLearnMore || FALLBACK_URL,
|
||||||
|
reduceOnlyLearnMore: linksConfigs.reduceOnlyLearnMore || FALLBACK_URL,
|
||||||
|
documentation: linksConfigs.documentation || FALLBACK_URL,
|
||||||
|
community: linksConfigs.community || FALLBACK_URL,
|
||||||
|
governanceLearnMore: linksConfigs.governanceLearnMore || FALLBACK_URL,
|
||||||
|
stakingLearnMore: linksConfigs.stakingLearnMore || FALLBACK_URL,
|
||||||
|
keplrDashboard: linksConfigs.keplrDashboard || FALLBACK_URL,
|
||||||
|
accountExportLearnMore: linksConfigs.accountExportLearnMore || FALLBACK_URL,
|
||||||
|
walletLearnMore: linksConfigs.walletLearnMore || FALLBACK_URL,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none">
|
||||||
|
<g clip-path="url(#clip0_18204_36775)">
|
||||||
|
<path d="M13.2426 6.25736C14.0817 7.09647 14.6531 8.16557 14.8846 9.32946C15.1162 10.4933 14.9973 11.6997 14.5432 12.7961C14.0891 13.8925 13.32 14.8295 12.3334 15.4888C11.3467 16.1481 10.1866 16.5 8.99993 16.5C7.81324 16.5 6.6532 16.1481 5.66651 15.4888C4.67981 14.8295 3.91078 13.8925 3.45665 12.7961C3.00253 11.6997 2.88371 10.4933 3.11522 9.32946C3.34673 8.16557 3.91817 7.09647 4.75729 6.25736" stroke="#C8C7D8" stroke-width="1.35" stroke-linecap="round"/>
|
||||||
|
<path d="M11.25 9L9 11.25M9 11.25L6.75 9M9 11.25V1.6875" stroke="#C8C7D8" stroke-width="1.35" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_18204_36775">
|
||||||
|
<rect width="18" height="18" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 886 B |
@@ -19,6 +19,7 @@ export { default as CoinsIcon } from './coins.svg';
|
|||||||
export { default as CommentIcon } from './comment.svg';
|
export { default as CommentIcon } from './comment.svg';
|
||||||
export { default as CopyIcon } from './copy.svg';
|
export { default as CopyIcon } from './copy.svg';
|
||||||
export { default as CubeIcon } from './cube.svg';
|
export { default as CubeIcon } from './cube.svg';
|
||||||
|
export { default as DepositIcon } from './deposit.svg';
|
||||||
export { default as DepthChartIcon } from './depth-chart.svg';
|
export { default as DepthChartIcon } from './depth-chart.svg';
|
||||||
export { default as DiscordIcon } from './discord.svg';
|
export { default as DiscordIcon } from './discord.svg';
|
||||||
export { default as ExportKeysIcon } from './export-keys.svg';
|
export { default as ExportKeysIcon } from './export-keys.svg';
|
||||||
@@ -35,6 +36,7 @@ export { default as LockIcon } from './lock.svg';
|
|||||||
export { default as LogoShortIcon } from './logo-short';
|
export { default as LogoShortIcon } from './logo-short';
|
||||||
export { default as MarketsIcon } from './markets.svg';
|
export { default as MarketsIcon } from './markets.svg';
|
||||||
export { default as MenuIcon } from './menu.svg';
|
export { default as MenuIcon } from './menu.svg';
|
||||||
|
export { default as MigrateIcon } from './migrate.svg';
|
||||||
export { default as MintscanIcon } from './logos/mintscan.svg';
|
export { default as MintscanIcon } from './logos/mintscan.svg';
|
||||||
export { default as OrderbookIcon } from './orderbook.svg';
|
export { default as OrderbookIcon } from './orderbook.svg';
|
||||||
export { default as OverviewIcon } from './overview.svg';
|
export { default as OverviewIcon } from './overview.svg';
|
||||||
@@ -58,6 +60,7 @@ export { default as TransferIcon } from './transfer.svg';
|
|||||||
export { default as TriangleIcon } from './triangle.svg';
|
export { default as TriangleIcon } from './triangle.svg';
|
||||||
export { default as TryAgainIcon } from './try-again.svg';
|
export { default as TryAgainIcon } from './try-again.svg';
|
||||||
export { default as WarningIcon } from './warning.svg';
|
export { default as WarningIcon } from './warning.svg';
|
||||||
|
export { default as WithdrawIcon } from './withdraw.svg';
|
||||||
|
|
||||||
// Wallets
|
// Wallets
|
||||||
export { default as BitkeepIcon } from './wallets/bitkeep.svg';
|
export { default as BitkeepIcon } from './wallets/bitkeep.svg';
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 694 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none">
|
||||||
|
<path d="M13.2426 6.2573C14.0817 7.09641 14.6531 8.16551 14.8846 9.3294C15.1162 10.4933 14.9973 11.6997 14.5432 12.796C14.0891 13.8924 13.32 14.8295 12.3334 15.4888C11.3467 16.148 10.1866 16.4999 8.99993 16.4999C7.81324 16.4999 6.6532 16.148 5.66651 15.4888C4.67981 14.8295 3.91078 13.8924 3.45665 12.796C3.00253 11.6997 2.88371 10.4933 3.11522 9.3294C3.34673 8.16551 3.91817 7.09641 4.75729 6.2573" stroke="#C8C7D8" stroke-width="1.35" stroke-linecap="round"/>
|
||||||
|
<path d="M11.25 2.9375L9 0.6875M9 0.6875L6.75 2.9375M9 0.6875V10.25" stroke="#C8C7D8" stroke-width="1.35" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 723 B |
@@ -8,7 +8,7 @@ import { STRING_KEYS } from '@/constants/localization';
|
|||||||
import { AppRoute } from '@/constants/routes';
|
import { AppRoute } from '@/constants/routes';
|
||||||
import { LogoShortIcon, BellStrokeIcon } from '@/icons';
|
import { LogoShortIcon, BellStrokeIcon } from '@/icons';
|
||||||
|
|
||||||
import { useTokenConfigs, useStringGetter } from '@/hooks';
|
import { useTokenConfigs, useStringGetter, useURLConfigs } from '@/hooks';
|
||||||
|
|
||||||
import { Icon, IconName } from '@/components/Icon';
|
import { Icon, IconName } from '@/components/Icon';
|
||||||
import { IconButton } from '@/components/IconButton';
|
import { IconButton } from '@/components/IconButton';
|
||||||
@@ -24,9 +24,11 @@ import { openDialog } from '@/state/dialogs';
|
|||||||
|
|
||||||
import { headerMixins } from '@/styles/headerMixins';
|
import { headerMixins } from '@/styles/headerMixins';
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
import breakpoints from '@/styles/breakpoints';
|
||||||
|
|
||||||
export const HeaderDesktop = () => {
|
export const HeaderDesktop = () => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
|
const { documentation, community, mintscanBase } = useURLConfigs();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { chainTokenLabel } = useTokenConfigs();
|
const { chainTokenLabel } = useTokenConfigs();
|
||||||
|
|
||||||
@@ -34,26 +36,26 @@ export const HeaderDesktop = () => {
|
|||||||
{
|
{
|
||||||
group: 'navigation',
|
group: 'navigation',
|
||||||
items: [
|
items: [
|
||||||
{
|
|
||||||
value: 'MARKET',
|
|
||||||
label: stringGetter({ key: STRING_KEYS.MARKET }),
|
|
||||||
href: AppRoute.Markets,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
value: 'TRADE',
|
value: 'TRADE',
|
||||||
label: stringGetter({ key: STRING_KEYS.TRADE }),
|
label: stringGetter({ key: STRING_KEYS.TRADE }),
|
||||||
href: AppRoute.Trade,
|
href: AppRoute.Trade,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
value: chainTokenLabel,
|
|
||||||
label: chainTokenLabel,
|
|
||||||
href: `/${chainTokenLabel}`,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
value: 'PORTFOLIO',
|
value: 'PORTFOLIO',
|
||||||
label: stringGetter({ key: STRING_KEYS.PORTFOLIO }),
|
label: stringGetter({ key: STRING_KEYS.PORTFOLIO }),
|
||||||
href: AppRoute.Portfolio,
|
href: AppRoute.Portfolio,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value: 'MARKETS',
|
||||||
|
label: stringGetter({ key: STRING_KEYS.MARKETS }),
|
||||||
|
href: AppRoute.Markets,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: chainTokenLabel,
|
||||||
|
label: chainTokenLabel,
|
||||||
|
href: `/${chainTokenLabel}`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: 'MORE',
|
value: 'MORE',
|
||||||
label: stringGetter({ key: STRING_KEYS.MORE }),
|
label: stringGetter({ key: STRING_KEYS.MORE }),
|
||||||
@@ -62,19 +64,19 @@ export const HeaderDesktop = () => {
|
|||||||
value: 'DOCUMENTATION',
|
value: 'DOCUMENTATION',
|
||||||
slotBefore: <Icon iconName={IconName.Terminal} />,
|
slotBefore: <Icon iconName={IconName.Terminal} />,
|
||||||
label: stringGetter({ key: STRING_KEYS.DOCUMENTATION }),
|
label: stringGetter({ key: STRING_KEYS.DOCUMENTATION }),
|
||||||
href: 'https://v4-teacher.vercel.app/',
|
href: documentation,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'MINTSCAN',
|
value: 'MINTSCAN',
|
||||||
slotBefore: <Icon iconName={IconName.Mintscan} />,
|
slotBefore: <Icon iconName={IconName.Mintscan} />,
|
||||||
label: stringGetter({ key: STRING_KEYS.MINTSCAN }),
|
label: stringGetter({ key: STRING_KEYS.MINTSCAN }),
|
||||||
href: 'https://testnet.mintscan.io/dydx-testnet',
|
href: mintscanBase,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'COMMUNITY',
|
value: 'COMMUNITY',
|
||||||
slotBefore: <Icon iconName={IconName.Discord} />,
|
slotBefore: <Icon iconName={IconName.Discord} />,
|
||||||
label: stringGetter({ key: STRING_KEYS.COMMUNITY }),
|
label: stringGetter({ key: STRING_KEYS.COMMUNITY }),
|
||||||
href: 'https://discord.gg/dydx',
|
href: community,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'TERMS_OF_USE',
|
value: 'TERMS_OF_USE',
|
||||||
@@ -150,6 +152,7 @@ const Styled: Record<string, AnyStyledComponent> = {};
|
|||||||
|
|
||||||
Styled.Header = styled.header`
|
Styled.Header = styled.header`
|
||||||
--header-horizontal-padding-mobile: 0.5rem;
|
--header-horizontal-padding-mobile: 0.5rem;
|
||||||
|
--trigger-height: 2.25rem;
|
||||||
--logo-width: 3.5rem;
|
--logo-width: 3.5rem;
|
||||||
|
|
||||||
${layoutMixins.container}
|
${layoutMixins.container}
|
||||||
@@ -157,6 +160,8 @@ Styled.Header = styled.header`
|
|||||||
${layoutMixins.scrollSnapItem}
|
${layoutMixins.scrollSnapItem}
|
||||||
backdrop-filter: none;
|
backdrop-filter: none;
|
||||||
|
|
||||||
|
height: var(--page-currentHeaderHeight);
|
||||||
|
|
||||||
grid-area: Header;
|
grid-area: Header;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -169,6 +174,14 @@ Styled.Header = styled.header`
|
|||||||
)
|
)
|
||||||
var(--border-width) 1fr var(--border-width) auto;
|
var(--border-width) 1fr var(--border-width) auto;
|
||||||
|
|
||||||
|
@media ${breakpoints.tablet} {
|
||||||
|
--trigger-height: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media ${breakpoints.mobile} {
|
||||||
|
--navBefore-width: 7rem;
|
||||||
|
}
|
||||||
|
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
|
|
||||||
:before {
|
:before {
|
||||||
@@ -179,6 +192,7 @@ Styled.Header = styled.header`
|
|||||||
Styled.NavigationMenu = styled(NavigationMenu)`
|
Styled.NavigationMenu = styled(NavigationMenu)`
|
||||||
& {
|
& {
|
||||||
--navigationMenu-height: var(--stickyArea-topHeight);
|
--navigationMenu-height: var(--stickyArea-topHeight);
|
||||||
|
--navigationMenu-item-height: var(--trigger-height);
|
||||||
}
|
}
|
||||||
|
|
||||||
${layoutMixins.scrollArea}
|
${layoutMixins.scrollArea}
|
||||||
|
|||||||
+16
-8
@@ -46,6 +46,8 @@ import {
|
|||||||
WALLET_CONNECT_EXPLORER_RECOMMENDED_IDS,
|
WALLET_CONNECT_EXPLORER_RECOMMENDED_IDS,
|
||||||
} from '@/constants/wallets';
|
} from '@/constants/wallets';
|
||||||
|
|
||||||
|
import { isTruthy } from './isTruthy';
|
||||||
|
|
||||||
// Config
|
// Config
|
||||||
|
|
||||||
export const WAGMI_SUPPORTED_CHAINS: Chain[] = [
|
export const WAGMI_SUPPORTED_CHAINS: Chain[] = [
|
||||||
@@ -78,13 +80,17 @@ export const WAGMI_SUPPORTED_CHAINS: Chain[] = [
|
|||||||
celoAlfajores,
|
celoAlfajores,
|
||||||
];
|
];
|
||||||
|
|
||||||
const { chains, publicClient, webSocketPublicClient } = configureChains(WAGMI_SUPPORTED_CHAINS, [
|
const { chains, publicClient, webSocketPublicClient } = configureChains(
|
||||||
// alchemyProvider({ apiKey: import.meta.env.VITE_ALCHEMY_API_KEY }),
|
WAGMI_SUPPORTED_CHAINS,
|
||||||
jsonRpcProvider({
|
[
|
||||||
rpc: (chain) => ({ http: chain.rpcUrls.default.http[0] }),
|
import.meta.env.VITE_ALCHEMY_API_KEY &&
|
||||||
}),
|
alchemyProvider({ apiKey: import.meta.env.VITE_ALCHEMY_API_KEY }),
|
||||||
publicProvider(),
|
jsonRpcProvider({
|
||||||
]);
|
rpc: (chain) => ({ http: chain.rpcUrls.default.http[0] }),
|
||||||
|
}),
|
||||||
|
publicProvider(),
|
||||||
|
].filter(isTruthy)
|
||||||
|
);
|
||||||
|
|
||||||
const injectedConnectorOptions = {
|
const injectedConnectorOptions = {
|
||||||
chains,
|
chains,
|
||||||
@@ -202,5 +208,7 @@ export const resolveWagmiConnector = ({
|
|||||||
? createInjectedConnectorWithProvider(walletConnection.provider)
|
? createInjectedConnectorWithProvider(walletConnection.provider)
|
||||||
: walletConnection.type === WalletConnectionType.WalletConnect2 && walletConfig.walletconnect2Id
|
: walletConnection.type === WalletConnectionType.WalletConnect2 && walletConfig.walletconnect2Id
|
||||||
? createWalletConnect2ConnectorWithId(walletConfig.walletconnect2Id, walletConnectConfig)
|
? createWalletConnect2ConnectorWithId(walletConfig.walletconnect2Id, walletConnectConfig)
|
||||||
: getConnectors(walletConnectConfig).find(({ id }: { id: string }) => id === walletConnectionConfig.wagmiConnectorId);
|
: getConnectors(walletConnectConfig).find(
|
||||||
|
({ id }: { id: string }) => id === walletConnectionConfig.wagmiConnectorId
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+21
-13
@@ -17,7 +17,7 @@ import { DialogTypes } from '@/constants/dialogs';
|
|||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { AppRoute, PortfolioRoute, HistoryRoute } from '@/constants/routes';
|
import { AppRoute, PortfolioRoute, HistoryRoute } from '@/constants/routes';
|
||||||
import { wallets, WalletType } from '@/constants/wallets';
|
import { wallets, WalletType } from '@/constants/wallets';
|
||||||
import { useAccounts, useStringGetter } from '@/hooks';
|
import { useAccounts, useStringGetter, useTokenConfigs } from '@/hooks';
|
||||||
|
|
||||||
import { getOnboardingState } from '@/state/accountSelectors';
|
import { getOnboardingState } from '@/state/accountSelectors';
|
||||||
import { openDialog } from '@/state/dialogs';
|
import { openDialog } from '@/state/dialogs';
|
||||||
@@ -37,6 +37,7 @@ const Profile = () => {
|
|||||||
const isConnected = onboardingState !== OnboardingState.Disconnected;
|
const isConnected = onboardingState !== OnboardingState.Disconnected;
|
||||||
|
|
||||||
const { evmAddress, dydxAddress, walletType } = useAccounts();
|
const { evmAddress, dydxAddress, walletType } = useAccounts();
|
||||||
|
const { chainTokenLabel } = useTokenConfigs();
|
||||||
|
|
||||||
const { data: ensName } = useEnsName({
|
const { data: ensName } = useEnsName({
|
||||||
address: evmAddress,
|
address: evmAddress,
|
||||||
@@ -137,7 +138,11 @@ const Profile = () => {
|
|||||||
layout="grid"
|
layout="grid"
|
||||||
/>
|
/>
|
||||||
</Panel>
|
</Panel>
|
||||||
<Styled.RewardsPanel header={stringGetter({ key: STRING_KEYS.REWARDS })} hasSeparator>
|
<Styled.RewardsPanel
|
||||||
|
slotHeaderContent={stringGetter({ key: STRING_KEYS.REWARDS })}
|
||||||
|
href={`/${chainTokenLabel}`}
|
||||||
|
hasSeparator
|
||||||
|
>
|
||||||
<Styled.Details
|
<Styled.Details
|
||||||
items={[
|
items={[
|
||||||
{ key: 'maker', label: stringGetter({ key: STRING_KEYS.YOU_WILL_EARN }), value: '-' },
|
{ key: 'maker', label: stringGetter({ key: STRING_KEYS.YOU_WILL_EARN }), value: '-' },
|
||||||
@@ -149,8 +154,8 @@ const Profile = () => {
|
|||||||
</Styled.EqualGrid>
|
</Styled.EqualGrid>
|
||||||
|
|
||||||
<Styled.TablePanel
|
<Styled.TablePanel
|
||||||
header={stringGetter({ key: STRING_KEYS.HISTORY })}
|
slotHeaderContent={stringGetter({ key: STRING_KEYS.HISTORY })}
|
||||||
linkto={`${AppRoute.Portfolio}/${PortfolioRoute.History}/${HistoryRoute.Trades}`}
|
href={`${AppRoute.Portfolio}/${PortfolioRoute.History}/${HistoryRoute.Trades}`}
|
||||||
hasSeparator
|
hasSeparator
|
||||||
>
|
>
|
||||||
<FillsTable
|
<FillsTable
|
||||||
@@ -175,7 +180,7 @@ Styled.MobileProfileLayout = styled.div`
|
|||||||
${layoutMixins.contentContainerPage}
|
${layoutMixins.contentContainerPage}
|
||||||
|
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 1rem;
|
padding: 1.25rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Header = styled.header`
|
Styled.Header = styled.header`
|
||||||
@@ -273,22 +278,25 @@ Styled.RewardsPanel = styled(Panel)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.TablePanel = styled(Panel)`
|
Styled.TablePanel = styled(Panel)`
|
||||||
padding: 0;
|
--panel-content-paddingY: 0;
|
||||||
max-width: calc(100vw - 2rem);
|
--panel-content-paddingX: 0;
|
||||||
max-height: 10rem;
|
|
||||||
|
> div > div {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
--scrollArea-height: 10rem;
|
||||||
|
border-radius: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
|
max-height: 10rem;
|
||||||
--tableCell-padding: 0.25rem 1rem;
|
--tableCell-padding: 0.25rem 1rem;
|
||||||
|
--tableRow-backgroundColor: var(--color-layer-3);
|
||||||
background-color: transparent;
|
background-color: var(--color-layer-3);
|
||||||
|
|
||||||
thead {
|
thead {
|
||||||
color: var(--color-text-0);
|
color: var(--color-text-0);
|
||||||
}
|
}
|
||||||
|
|
||||||
tbody {
|
tbody {
|
||||||
background-color: transparent;
|
|
||||||
|
|
||||||
tr {
|
tr {
|
||||||
td:nth-child(2),
|
td:nth-child(2),
|
||||||
td:nth-child(3) {
|
td:nth-child(3) {
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ export const AccountDetailsAndHistory = () => {
|
|||||||
key: 'BuyingPower',
|
key: 'BuyingPower',
|
||||||
labelKey: STRING_KEYS.BUYING_POWER,
|
labelKey: STRING_KEYS.BUYING_POWER,
|
||||||
type: OutputType.Fiat,
|
type: OutputType.Fiat,
|
||||||
value: buyingPower?.current,
|
value: MustBigNumber(buyingPower?.current).lt(0) ? undefined : buyingPower?.current, // show '-' when buying power is negative
|
||||||
},
|
},
|
||||||
].filter(isTruthy);
|
].filter(isTruthy);
|
||||||
|
|
||||||
|
|||||||
+131
-106
@@ -1,12 +1,12 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { Nullable } from '@dydxprotocol/v4-abacus';
|
import { Nullable } from '@dydxprotocol/v4-abacus';
|
||||||
import styled, { AnyStyledComponent } from 'styled-components';
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
import { shallowEqual, useSelector } from 'react-redux';
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { FeeTier } from '@/constants/abacus';
|
import { FeeTier } from '@/constants/abacus';
|
||||||
import { FEE_DECIMALS, QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
import { FEE_DECIMALS } from '@/constants/numbers';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { useAccounts, useBreakpoints, useStringGetter } from '@/hooks';
|
import { useBreakpoints, useStringGetter } from '@/hooks';
|
||||||
import { breakpoints } from '@/styles';
|
import { breakpoints } from '@/styles';
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
import { tableMixins } from '@/styles/tableMixins';
|
import { tableMixins } from '@/styles/tableMixins';
|
||||||
@@ -29,9 +29,8 @@ const EQUALITY_SYMBOL_MAP = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const Fees = () => {
|
export const Fees = () => {
|
||||||
const { dydxAddress } = useAccounts();
|
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const { isNotTablet } = useBreakpoints();
|
const { isTablet, isNotTablet } = useBreakpoints();
|
||||||
const userFeeTier = useSelector(getUserFeeTier, shallowEqual);
|
const userFeeTier = useSelector(getUserFeeTier, shallowEqual);
|
||||||
const userStats = useSelector(getUserStats, shallowEqual);
|
const userStats = useSelector(getUserStats, shallowEqual);
|
||||||
const feeTiers = useSelector(getFeeTiers, shallowEqual);
|
const feeTiers = useSelector(getFeeTiers, shallowEqual);
|
||||||
@@ -56,28 +55,28 @@ export const Fees = () => {
|
|||||||
<Styled.AdditionalConditions>
|
<Styled.AdditionalConditions>
|
||||||
{!isAdditional && !totalShare && !makerShare && <Output type={OutputType.Text} />}
|
{!isAdditional && !totalShare && !makerShare && <Output type={OutputType.Text} />}
|
||||||
{!!totalShare && (
|
{!!totalShare && (
|
||||||
<Styled.TextRow>
|
<Styled.AdditionalConditionsText>
|
||||||
{isAdditional && <span>{stringGetter({ key: STRING_KEYS.AND })}</span>}
|
{isAdditional && stringGetter({ key: STRING_KEYS.AND })}{' '}
|
||||||
<span>{stringGetter({ key: STRING_KEYS.EXCHANGE_MARKET_SHARE })}</span>
|
{stringGetter({ key: STRING_KEYS.EXCHANGE_MARKET_SHARE })}{' '}
|
||||||
<Styled.Highlighted>{'>'}</Styled.Highlighted>
|
<Styled.Highlighted>{'>'}</Styled.Highlighted>{' '}
|
||||||
<Styled.HighlightOutput
|
<Styled.HighlightOutput
|
||||||
type={OutputType.Percent}
|
type={OutputType.Percent}
|
||||||
value={totalShare}
|
value={totalShare}
|
||||||
fractionDigits={0}
|
fractionDigits={0}
|
||||||
/>
|
/>
|
||||||
</Styled.TextRow>
|
</Styled.AdditionalConditionsText>
|
||||||
)}
|
)}
|
||||||
{!!makerShare && (
|
{!!makerShare && (
|
||||||
<Styled.TextRow>
|
<Styled.AdditionalConditionsText>
|
||||||
{isAdditional && <span>{stringGetter({ key: STRING_KEYS.AND })}</span>}
|
{isAdditional && stringGetter({ key: STRING_KEYS.AND })}{' '}
|
||||||
<span>{stringGetter({ key: STRING_KEYS.MAKER_MARKET_SHARE })}</span>
|
{stringGetter({ key: STRING_KEYS.MAKER_MARKET_SHARE })}{' '}
|
||||||
<Styled.Highlighted>{'>'}</Styled.Highlighted>
|
<Styled.Highlighted>{'>'}</Styled.Highlighted>{' '}
|
||||||
<Styled.HighlightOutput
|
<Styled.HighlightOutput
|
||||||
type={OutputType.Percent}
|
type={OutputType.Percent}
|
||||||
value={makerShare}
|
value={makerShare}
|
||||||
fractionDigits={0}
|
fractionDigits={0}
|
||||||
/>
|
/>
|
||||||
</Styled.TextRow>
|
</Styled.AdditionalConditionsText>
|
||||||
)}
|
)}
|
||||||
</Styled.AdditionalConditions>
|
</Styled.AdditionalConditions>
|
||||||
),
|
),
|
||||||
@@ -103,91 +102,90 @@ export const Fees = () => {
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<div>
|
|
||||||
<Styled.FeeTable
|
<Styled.FeeTable
|
||||||
label="Fee Tiers"
|
label="Fee Tiers"
|
||||||
data={feeTiers || []}
|
data={feeTiers || []}
|
||||||
getRowKey={(row: FeeTier) => row.tier}
|
getRowKey={(row: FeeTier) => row.tier}
|
||||||
getRowAttributes={(row: FeeTier) => ({
|
getRowAttributes={(row: FeeTier) => ({
|
||||||
'data-yours': row.tier === userFeeTier,
|
'data-yours': row.tier === userFeeTier,
|
||||||
})}
|
})}
|
||||||
columns={(
|
columns={(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
columnKey: 'tier',
|
columnKey: 'tier',
|
||||||
getCellValue: (row) => row.tier,
|
getCellValue: (row) => row.tier,
|
||||||
label: stringGetter({ key: STRING_KEYS.TIER }),
|
label: stringGetter({ key: STRING_KEYS.TIER }),
|
||||||
allowsSorting: false,
|
allowsSorting: false,
|
||||||
renderCell: ({ tier }) => (
|
renderCell: ({ tier }) => (
|
||||||
<Styled.Tier>
|
<Styled.Tier>
|
||||||
<Styled.Output type={OutputType.Text} value={tier} />
|
<Styled.Output type={OutputType.Text} value={tier} />
|
||||||
{tier === userFeeTier && (
|
{tier === userFeeTier && (
|
||||||
<Styled.YouTag size={TagSize.Medium}>
|
<Styled.YouTag size={TagSize.Medium}>
|
||||||
{stringGetter({ key: STRING_KEYS.YOU })}
|
{stringGetter({ key: STRING_KEYS.YOU })}
|
||||||
</Styled.YouTag>
|
</Styled.YouTag>
|
||||||
)}
|
)}
|
||||||
</Styled.Tier>
|
</Styled.Tier>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
columnKey: 'volume',
|
columnKey: 'volume',
|
||||||
getCellValue: (row) => row.volume,
|
getCellValue: (row) => row.volume,
|
||||||
label: stringGetter({ key: STRING_KEYS.VOLUME_30D }),
|
label: stringGetter({ key: STRING_KEYS.VOLUME_30D }),
|
||||||
allowsSorting: false,
|
allowsSorting: false,
|
||||||
renderCell: ({ symbol, volume, makerShare, totalShare }) => (
|
renderCell: ({ symbol, volume, makerShare, totalShare }) => (
|
||||||
<>
|
<>
|
||||||
<span>{`${
|
<span>{`${
|
||||||
symbol in EQUALITY_SYMBOL_MAP
|
symbol in EQUALITY_SYMBOL_MAP
|
||||||
? EQUALITY_SYMBOL_MAP[symbol as keyof typeof EQUALITY_SYMBOL_MAP]
|
? EQUALITY_SYMBOL_MAP[symbol as keyof typeof EQUALITY_SYMBOL_MAP]
|
||||||
: symbol
|
: symbol
|
||||||
} `}</span>
|
} `}</span>
|
||||||
<Styled.HighlightOutput type={OutputType.CompactFiat} value={volume} />
|
<Styled.HighlightOutput type={OutputType.CompactFiat} value={volume} />
|
||||||
{!isNotTablet &&
|
{isTablet &&
|
||||||
AdditionalConditions({ totalShare, makerShare, isAdditional: true })}
|
AdditionalConditions({ totalShare, makerShare, isAdditional: true })}
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
isNotTablet && {
|
isNotTablet && {
|
||||||
columnKey: 'condition',
|
columnKey: 'condition',
|
||||||
getCellValue: (row) => row.volume,
|
getCellValue: (row) => row.volume,
|
||||||
label: stringGetter({ key: STRING_KEYS.ADDITIONAL_CONDITION }),
|
label: stringGetter({ key: STRING_KEYS.ADDITIONAL_CONDITION }),
|
||||||
allowsSorting: false,
|
allowsSorting: false,
|
||||||
renderCell: ({ totalShare, makerShare }) =>
|
renderCell: ({ totalShare, makerShare }) =>
|
||||||
AdditionalConditions({ totalShare, makerShare }),
|
AdditionalConditions({ totalShare, makerShare }),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
columnKey: 'maker',
|
columnKey: 'maker',
|
||||||
getCellValue: (row) => row.maker,
|
getCellValue: (row) => row.maker,
|
||||||
label: stringGetter({ key: STRING_KEYS.MAKER }),
|
label: stringGetter({ key: STRING_KEYS.MAKER }),
|
||||||
allowsSorting: false,
|
allowsSorting: false,
|
||||||
renderCell: ({ maker }) => (
|
renderCell: ({ maker }) => (
|
||||||
<Styled.HighlightOutput
|
<Styled.HighlightOutput
|
||||||
type={OutputType.SmallPercent}
|
type={OutputType.SmallPercent}
|
||||||
value={maker}
|
value={maker}
|
||||||
fractionDigits={FEE_DECIMALS}
|
fractionDigits={FEE_DECIMALS}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
columnKey: 'taker',
|
columnKey: 'taker',
|
||||||
getCellValue: (row) => row.taker,
|
getCellValue: (row) => row.taker,
|
||||||
label: stringGetter({ key: STRING_KEYS.TAKER }),
|
label: stringGetter({ key: STRING_KEYS.TAKER }),
|
||||||
allowsSorting: false,
|
allowsSorting: false,
|
||||||
renderCell: ({ taker }) => (
|
renderCell: ({ taker }) => (
|
||||||
<Styled.HighlightOutput
|
<Styled.HighlightOutput
|
||||||
type={OutputType.SmallPercent}
|
type={OutputType.SmallPercent}
|
||||||
value={taker}
|
value={taker}
|
||||||
fractionDigits={FEE_DECIMALS}
|
fractionDigits={FEE_DECIMALS}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
] as ColumnDef<FeeTier>[]
|
] as ColumnDef<FeeTier>[]
|
||||||
).filter(isTruthy)}
|
).filter(isTruthy)}
|
||||||
selectionBehavior="replace"
|
selectionBehavior="replace"
|
||||||
withOuterBorder={isNotTablet}
|
withOuterBorder={isNotTablet}
|
||||||
withInnerBorders
|
withInnerBorders
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</Styled.ContentWrapper>
|
</Styled.ContentWrapper>
|
||||||
</AttachedExpandingSection>
|
</AttachedExpandingSection>
|
||||||
);
|
);
|
||||||
@@ -198,21 +196,43 @@ const Styled: Record<string, AnyStyledComponent> = {};
|
|||||||
Styled.ContentWrapper = styled.div`
|
Styled.ContentWrapper = styled.div`
|
||||||
${layoutMixins.flexColumn}
|
${layoutMixins.flexColumn}
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
|
max-width: 100vw;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.AdditionalConditions = styled.div`
|
Styled.AdditionalConditions = styled.div`
|
||||||
${tableMixins.cellContentColumn}
|
${tableMixins.cellContentColumn}
|
||||||
|
justify-content: end;
|
||||||
|
|
||||||
color: var(--color-text-0);
|
color: var(--color-text-0);
|
||||||
|
font: var(--font-small-book);
|
||||||
|
|
||||||
> :nth-child(2) {
|
> :nth-child(2) {
|
||||||
font: var(--font-base-book);
|
font: var(--font-small-book);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.AdditionalConditionsText = styled.span`
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5ch;
|
||||||
|
|
||||||
|
@media ${breakpoints.mobile} {
|
||||||
|
display: inline;
|
||||||
|
max-width: 8rem;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
output {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.FeesDetails = styled(Details)`
|
Styled.FeesDetails = styled(Details)`
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
|
||||||
|
@media ${breakpoints.notTablet} {
|
||||||
|
margin: 0 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
@media ${breakpoints.tablet} {
|
@media ${breakpoints.tablet} {
|
||||||
padding: 1rem 1rem 0 1rem;
|
padding: 1rem 1rem 0 1rem;
|
||||||
--details-grid-numColumns: 1;
|
--details-grid-numColumns: 1;
|
||||||
@@ -237,11 +257,7 @@ Styled.FeesDetails = styled(Details)`
|
|||||||
}
|
}
|
||||||
|
|
||||||
output {
|
output {
|
||||||
font: var(--font-medium-book);
|
font: var(--font-base-book);
|
||||||
|
|
||||||
@media ${breakpoints.tablet} {
|
|
||||||
font: var(--font-base-book);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -271,6 +287,11 @@ Styled.FeeTable = styled(Table)`
|
|||||||
|
|
||||||
font: var(--font-base-book);
|
font: var(--font-base-book);
|
||||||
|
|
||||||
|
@media ${breakpoints.mobile} {
|
||||||
|
--tableCell-padding: 1rem 1.25rem;
|
||||||
|
font: var(--font-small-book);
|
||||||
|
}
|
||||||
|
|
||||||
tbody tr {
|
tbody tr {
|
||||||
&[data-yours='true'] {
|
&[data-yours='true'] {
|
||||||
background-color: var(--color-layer-3);
|
background-color: var(--color-layer-3);
|
||||||
@@ -283,6 +304,10 @@ Styled.FeeTable = styled(Table)`
|
|||||||
|
|
||||||
@media ${breakpoints.notTablet} {
|
@media ${breakpoints.notTablet} {
|
||||||
--tableHeader-backgroundColor: var(--color-layer-1);
|
--tableHeader-backgroundColor: var(--color-layer-1);
|
||||||
|
|
||||||
|
thead tr {
|
||||||
|
--border-width: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ export const DYDXBalancePanel = () => {
|
|||||||
const { chainTokenLabel } = useTokenConfigs();
|
const { chainTokenLabel } = useTokenConfigs();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Panel
|
<Styled.Panel
|
||||||
slotHeader={
|
slotHeader={
|
||||||
<Styled.Header>
|
<Styled.Header>
|
||||||
<Styled.Title>
|
<Styled.Title>
|
||||||
{/* <AssetIcon symbol="DYDX" /> */}
|
<AssetIcon symbol={chainTokenLabel} />
|
||||||
{chainTokenLabel}
|
{chainTokenLabel}
|
||||||
</Styled.Title>
|
</Styled.Title>
|
||||||
<Styled.ReceiveAndTransferButtons>
|
<Styled.ReceiveAndTransferButtons>
|
||||||
@@ -117,14 +117,19 @@ export const DYDXBalancePanel = () => {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Styled.Content>
|
</Styled.Content>
|
||||||
</Panel>
|
</Styled.Panel>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Styled: Record<string, AnyStyledComponent> = {};
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
|
Styled.Panel = styled(Panel)`
|
||||||
|
--panel-paddingX: 1.5rem;
|
||||||
|
`;
|
||||||
|
|
||||||
Styled.Header = styled.div`
|
Styled.Header = styled.div`
|
||||||
${layoutMixins.spacedRow}
|
${layoutMixins.spacedRow}
|
||||||
|
gap: 1rem;
|
||||||
padding: 1rem 1.5rem 0;
|
padding: 1rem 1.5rem 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -177,7 +182,7 @@ Styled.WalletAndStakedBalance = styled(Details)`
|
|||||||
--details-item-backgroundColor: var(--color-layer-6);
|
--details-item-backgroundColor: var(--color-layer-6);
|
||||||
|
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
gap: 0.5rem;
|
gap: 1rem;
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
|||||||
@@ -0,0 +1,224 @@
|
|||||||
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||||
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
|
import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons';
|
||||||
|
|
||||||
|
import { useAccountBalance, useBreakpoints, useStringGetter } from '@/hooks';
|
||||||
|
|
||||||
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
|
import { Details } from '@/components/Details';
|
||||||
|
import { Panel } from '@/components/Panel';
|
||||||
|
import { Button } from '@/components/Button';
|
||||||
|
import { Link } from '@/components/Link';
|
||||||
|
import { IconName, Icon } from '@/components/Icon';
|
||||||
|
import { Output, OutputType } from '@/components/Output';
|
||||||
|
import { VerticalSeparator } from '@/components/Separator';
|
||||||
|
import { Tag } from '@/components/Tag';
|
||||||
|
import { WithReceipt } from '@/components/WithReceipt';
|
||||||
|
|
||||||
|
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||||
|
|
||||||
|
import { MustBigNumber } from '@/lib/numbers';
|
||||||
|
|
||||||
|
const TOKEN_MIGRATION_LEARN_MORE_LINK =
|
||||||
|
'https://www.dydx.foundation/blog/update-on-exploring-the-future-of-dydx';
|
||||||
|
|
||||||
|
export const MigratePanel = () => {
|
||||||
|
const { isNotTablet } = useBreakpoints();
|
||||||
|
const stringGetter = useStringGetter();
|
||||||
|
|
||||||
|
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||||
|
|
||||||
|
const chainId = Number(ENVIRONMENT_CONFIG_MAP[selectedNetwork].ethereumChainId);
|
||||||
|
|
||||||
|
// v3 token is only on mainnet
|
||||||
|
const { balance: tokenBalance } = useAccountBalance({
|
||||||
|
addressOrDenom: chainId === 1 ? import.meta.env.VITE_V3_TOKEN_ADDRESS : undefined,
|
||||||
|
chainId: 1,
|
||||||
|
isCosmosChain: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return isNotTablet ? (
|
||||||
|
<Styled.MigratePanel
|
||||||
|
slotHeader={<Styled.Title>{stringGetter({ key: STRING_KEYS.MIGRATE })}</Styled.Title>}
|
||||||
|
slotRight={
|
||||||
|
<Styled.MigrateAction>
|
||||||
|
<div>
|
||||||
|
<div>{stringGetter({ key: STRING_KEYS.AVAILABLE_TO_MIGRATE })}</div>
|
||||||
|
<Styled.Token type={OutputType.Asset} value={tokenBalance} />
|
||||||
|
</div>
|
||||||
|
{import.meta.env.VITE_TOKEN_MIGRATION_URI && (
|
||||||
|
<Button
|
||||||
|
action={MustBigNumber(tokenBalance).gt(0) ? ButtonAction.Primary : ButtonAction.Base}
|
||||||
|
type={ButtonType.Link}
|
||||||
|
href={import.meta.env.VITE_TOKEN_MIGRATION_URI}
|
||||||
|
slotRight={<Icon iconName={IconName.LinkOut} />}
|
||||||
|
>
|
||||||
|
{stringGetter({ key: STRING_KEYS.MIGRATE_NOW })}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Styled.MigrateAction>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Styled.Description>
|
||||||
|
{stringGetter({ key: STRING_KEYS.MIGRATE_DESCRIPTION })}
|
||||||
|
<Link href={TOKEN_MIGRATION_LEARN_MORE_LINK}>
|
||||||
|
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} →
|
||||||
|
</Link>
|
||||||
|
</Styled.Description>
|
||||||
|
</Styled.MigratePanel>
|
||||||
|
) : (
|
||||||
|
<Styled.MigratePanel
|
||||||
|
slotHeader={
|
||||||
|
<Styled.MobileMigrateHeader>
|
||||||
|
<h3>
|
||||||
|
<Icon iconName={IconName.Migrate} />
|
||||||
|
{stringGetter({ key: STRING_KEYS.MIGRATE })}
|
||||||
|
</h3>
|
||||||
|
<Styled.VerticalSeparator />
|
||||||
|
<span>
|
||||||
|
{stringGetter({
|
||||||
|
key: STRING_KEYS.FROM_TO,
|
||||||
|
params: { FROM: <b>Ethereum</b>, TO: <b>dYdX Chain</b> },
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</Styled.MobileMigrateHeader>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Styled.Column>
|
||||||
|
<Styled.WithReceipt
|
||||||
|
slotReceipt={
|
||||||
|
<Styled.Details
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
key: 'available-to-migrate',
|
||||||
|
label: (
|
||||||
|
<Styled.InlineRow>
|
||||||
|
{stringGetter({ key: STRING_KEYS.AVAILABLE_TO_MIGRATE })}
|
||||||
|
<Tag>DYDX</Tag>
|
||||||
|
</Styled.InlineRow>
|
||||||
|
),
|
||||||
|
value: <Output type={OutputType.Asset} value={tokenBalance} />,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{import.meta.env.VITE_TOKEN_MIGRATION_URI && (
|
||||||
|
<Button
|
||||||
|
action={tokenBalance ? ButtonAction.Primary : ButtonAction.Base}
|
||||||
|
size={ButtonSize.Medium}
|
||||||
|
slotRight={<Icon iconName={IconName.LinkOut} />}
|
||||||
|
href={import.meta.env.VITE_TOKEN_MIGRATION_URI}
|
||||||
|
>
|
||||||
|
{stringGetter({ key: STRING_KEYS.MIGRATE_NOW })}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Styled.WithReceipt>
|
||||||
|
<Styled.InlineRow>
|
||||||
|
{stringGetter({ key: STRING_KEYS.WANT_TO_LEARN })}
|
||||||
|
<Link href={TOKEN_MIGRATION_LEARN_MORE_LINK} withIcon>
|
||||||
|
{stringGetter({ key: STRING_KEYS.CLICK_HERE })}
|
||||||
|
</Link>
|
||||||
|
</Styled.InlineRow>
|
||||||
|
</Styled.Column>
|
||||||
|
</Styled.MigratePanel>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
|
Styled.MigratePanel = styled(Panel)`
|
||||||
|
--panel-paddingX: 1.5rem;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Title = styled.h3`
|
||||||
|
font: var(--font-medium-book);
|
||||||
|
color: var(--color-text-2);
|
||||||
|
|
||||||
|
padding: 1rem 1.5rem 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.MigrateAction = styled.div`
|
||||||
|
${layoutMixins.flexEqualColumns}
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 1rem;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
background-color: var(--color-layer-2);
|
||||||
|
border: solid var(--border-width) var(--color-border);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Token = styled(Output)`
|
||||||
|
font: var(--font-large-book);
|
||||||
|
color: var(--color-text-2);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Description = styled.div`
|
||||||
|
color: var(--color-text-0);
|
||||||
|
--link-color: var(--color-text-1);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Column = styled.div`
|
||||||
|
${layoutMixins.flexColumn}
|
||||||
|
gap: 1rem;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.MobileMigrateHeader = styled.div`
|
||||||
|
${layoutMixins.inlineRow}
|
||||||
|
gap: 1ch;
|
||||||
|
|
||||||
|
font: var(--font-small-book);
|
||||||
|
color: var(--color-text-0);
|
||||||
|
|
||||||
|
padding: 1rem 1.5rem 0;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
${layoutMixins.inlineRow}
|
||||||
|
font: var(--font-large-book);
|
||||||
|
color: var(--color-text-2);
|
||||||
|
|
||||||
|
svg {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-top: 0.2rem;
|
||||||
|
|
||||||
|
b {
|
||||||
|
font-weight: var(--fontWeight-book);
|
||||||
|
color: var(--color-text-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.VerticalSeparator = styled(VerticalSeparator)`
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
&& {
|
||||||
|
height: 1.5rem;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Details = styled(Details)`
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.WithReceipt = styled(WithReceipt)`
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.InlineRow = styled.div`
|
||||||
|
${layoutMixins.inlineRow}
|
||||||
|
color: var(--color-text-0);
|
||||||
|
--link-color: var(--color-text-1);
|
||||||
|
`;
|
||||||
@@ -1,186 +1,74 @@
|
|||||||
import styled, { AnyStyledComponent } from 'styled-components';
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { ButtonAction, ButtonSize, ButtonState, ButtonType } from '@/constants/buttons';
|
import { ButtonAction, ButtonSize } from '@/constants/buttons';
|
||||||
import { DialogTypes } from '@/constants/dialogs';
|
import { DialogTypes } from '@/constants/dialogs';
|
||||||
|
|
||||||
import { useAccountBalance, useBreakpoints, useStringGetter } from '@/hooks';
|
import { useBreakpoints, useStringGetter, useURLConfigs } from '@/hooks';
|
||||||
|
|
||||||
import { breakpoints } from '@/styles';
|
import { breakpoints } from '@/styles';
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
import { Details } from '@/components/Details';
|
|
||||||
import { Panel } from '@/components/Panel';
|
import { Panel } from '@/components/Panel';
|
||||||
import { IconName } from '@/components/Icon';
|
import { IconName } from '@/components/Icon';
|
||||||
import { Button } from '@/components/Button';
|
|
||||||
import { IconButton } from '@/components/IconButton';
|
import { IconButton } from '@/components/IconButton';
|
||||||
import { Link } from '@/components/Link';
|
import { Link } from '@/components/Link';
|
||||||
import { Output, OutputType } from '@/components/Output';
|
|
||||||
import { VerticalSeparator } from '@/components/Separator';
|
|
||||||
import { WithReceipt } from '@/components/WithReceipt';
|
|
||||||
|
|
||||||
import { openDialog } from '@/state/dialogs';
|
import { openDialog } from '@/state/dialogs';
|
||||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
|
||||||
|
|
||||||
import { DYDXBalancePanel } from './DYDXBalancePanel';
|
import { DYDXBalancePanel } from './DYDXBalancePanel';
|
||||||
|
import { MigratePanel } from './MigratePanel';
|
||||||
// TODO: replace placeholder URL with real URLs when avaialble
|
|
||||||
const GOVERNANCE_HELP_URL = 'https://help.dydx.exchange/';
|
|
||||||
const STAKING_HELP_URL = 'https://help.dydx.exchange/';
|
|
||||||
|
|
||||||
export const RewardsPage = () => {
|
export const RewardsPage = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
|
const { governanceLearnMore, stakingLearnMore } = useURLConfigs();
|
||||||
const { isTablet, isNotTablet } = useBreakpoints();
|
const { isTablet, isNotTablet } = useBreakpoints();
|
||||||
|
|
||||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
const panelArrow = (
|
||||||
|
<Styled.Arrow>
|
||||||
// const chainId = Number(ENVIRONMENT_CONFIG_MAP[selectedNetwork].ethereumChainId);
|
<Styled.IconButton
|
||||||
|
action={ButtonAction.Base}
|
||||||
// const { balance } = useAccountBalance({
|
iconName={IconName.Arrow}
|
||||||
// addressOrDenom: import.meta.env.VITE_V3_TOKEN_ADDRESS,
|
size={ButtonSize.Small}
|
||||||
// assetSymbol: 'DYDX',
|
/>
|
||||||
// chainId,
|
</Styled.Arrow>
|
||||||
// isCosmosChain: false,
|
);
|
||||||
// });
|
|
||||||
|
|
||||||
// const tokenBalance = import.meta.env.VITE_V3_TOKEN_ADDRESS ? balance : 0;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Styled.Page>
|
<Styled.Page>
|
||||||
{/* {isNotTablet ? (
|
{import.meta.env.VITE_V3_TOKEN_ADDRESS && <MigratePanel />}
|
||||||
<Styled.Migrate>
|
|
||||||
<Styled.TwoItemRow>
|
|
||||||
<div>
|
|
||||||
<Styled.MigrateTitle>
|
|
||||||
{stringGetter({ key: STRING_KEYS.MIGRATE })}
|
|
||||||
</Styled.MigrateTitle>
|
|
||||||
<Styled.Description>
|
|
||||||
{stringGetter({ key: STRING_KEYS.MIGRATE_DESCRIPTION })}
|
|
||||||
<Link href={MIGRATE_HELP_URL}>
|
|
||||||
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} →
|
|
||||||
</Link>
|
|
||||||
</Styled.Description>
|
|
||||||
</div>
|
|
||||||
<Styled.MigrateAction>
|
|
||||||
<div>
|
|
||||||
<div>{stringGetter({ key: STRING_KEYS.AVAILABLE_TO_MIGRATE })}</div>
|
|
||||||
<div>
|
|
||||||
<Styled.Token type={OutputType.Asset} value={tokenBalance} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
action={tokenBalance ? ButtonAction.Primary : ButtonAction.Base}
|
|
||||||
// type={ButtonType.Link}
|
|
||||||
// href={BRIDGE_URL}
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
{tokenBalance
|
|
||||||
? `${stringGetter({ key: STRING_KEYS.MIGRATE_NOW })} →`
|
|
||||||
: stringGetter({ key: STRING_KEYS.NO_TOKENS_TO_MIGRATE })}
|
|
||||||
</Button>
|
|
||||||
</Styled.MigrateAction>
|
|
||||||
</Styled.TwoItemRow>
|
|
||||||
</Styled.Migrate>
|
|
||||||
) : (
|
|
||||||
<Styled.MobileMigrateCard
|
|
||||||
slotHeader={
|
|
||||||
<Styled.MobileMigrateHeader>
|
|
||||||
<h3>{stringGetter({ key: STRING_KEYS.MIGRATE })}</h3>
|
|
||||||
<VerticalSeparator />
|
|
||||||
<span>
|
|
||||||
{stringGetter({
|
|
||||||
key: STRING_KEYS.FROM_TO,
|
|
||||||
params: { FROM: <strong>Ethereum</strong>, TO: <strong>dYdX Chain</strong> },
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
</Styled.MobileMigrateHeader>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Styled.WithReceipt
|
|
||||||
slotReceipt={
|
|
||||||
<Styled.Details
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
key: 'available-to-migrate',
|
|
||||||
label: stringGetter({ key: STRING_KEYS.AVAILABLE_TO_MIGRATE }),
|
|
||||||
value: <Output type={OutputType.Asset} value={tokenBalance} />,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
action={tokenBalance ? ButtonAction.Primary : ButtonAction.Base}
|
|
||||||
size={ButtonSize.Medium}
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
{tokenBalance
|
|
||||||
? `${stringGetter({ key: STRING_KEYS.MIGRATE_NOW })} →`
|
|
||||||
: stringGetter({ key: STRING_KEYS.NO_TOKENS_TO_MIGRATE })}
|
|
||||||
</Button>
|
|
||||||
</Styled.WithReceipt>
|
|
||||||
<Styled.LearnMore>
|
|
||||||
{stringGetter({ key: STRING_KEYS.WANT_TO_LEARN })}
|
|
||||||
<Link href={MIGRATE_HELP_URL}>{stringGetter({ key: STRING_KEYS.CLICK_HERE })}</Link>
|
|
||||||
</Styled.LearnMore>
|
|
||||||
</Styled.MobileMigrateCard>
|
|
||||||
)} */}
|
|
||||||
|
|
||||||
<Styled.PanelRow>
|
<Styled.PanelRow>
|
||||||
{isTablet && (
|
{isTablet && <DYDXBalancePanel />}
|
||||||
<Styled.BalancePanelContainer>
|
|
||||||
<DYDXBalancePanel />
|
|
||||||
</Styled.BalancePanelContainer>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Styled.Panel
|
<Styled.Panel
|
||||||
slotHeader={<Styled.Title>{stringGetter({ key: STRING_KEYS.GOVERNANCE })}</Styled.Title>}
|
slotHeader={<Styled.Title>{stringGetter({ key: STRING_KEYS.GOVERNANCE })}</Styled.Title>}
|
||||||
|
slotRight={panelArrow}
|
||||||
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
|
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
|
||||||
>
|
>
|
||||||
<Styled.Row>
|
<Styled.Description>
|
||||||
<Styled.Description>
|
{stringGetter({ key: STRING_KEYS.GOVERNANCE_DESCRIPTION })}
|
||||||
{stringGetter({ key: STRING_KEYS.GOVERNANCE_DESCRIPTION })}
|
<Link href={governanceLearnMore} onClick={(e) => e.stopPropagation()}>
|
||||||
<Link href={GOVERNANCE_HELP_URL} onClick={(e) => e.stopPropagation()}>
|
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} →
|
||||||
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} →
|
</Link>
|
||||||
</Link>
|
</Styled.Description>
|
||||||
</Styled.Description>
|
|
||||||
{/* TODO: vertically center based on Panel height */}
|
|
||||||
<Styled.IconButton
|
|
||||||
action={ButtonAction.Base}
|
|
||||||
iconName={IconName.Arrow}
|
|
||||||
size={ButtonSize.Small}
|
|
||||||
/>
|
|
||||||
</Styled.Row>
|
|
||||||
</Styled.Panel>
|
</Styled.Panel>
|
||||||
|
|
||||||
<Styled.Panel
|
<Styled.Panel
|
||||||
slotHeader={<Styled.Title>{stringGetter({ key: STRING_KEYS.STAKING })}</Styled.Title>}
|
slotHeader={<Styled.Title>{stringGetter({ key: STRING_KEYS.STAKING })}</Styled.Title>}
|
||||||
|
slotRight={panelArrow}
|
||||||
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
|
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
|
||||||
>
|
>
|
||||||
<Styled.Row>
|
<Styled.Description>
|
||||||
<Styled.Description>
|
{stringGetter({ key: STRING_KEYS.STAKING_DESCRIPTION })}
|
||||||
{stringGetter({ key: STRING_KEYS.STAKING_DESCRIPTION })}
|
<Link href={stakingLearnMore} onClick={(e) => e.stopPropagation()}>
|
||||||
<Link href={STAKING_HELP_URL} onClick={(e) => e.stopPropagation()}>
|
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} →
|
||||||
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} →
|
</Link>
|
||||||
</Link>
|
</Styled.Description>
|
||||||
</Styled.Description>
|
|
||||||
{/* TODO: vertically center based on Panel height */}
|
|
||||||
<Styled.IconButton
|
|
||||||
action={ButtonAction.Base}
|
|
||||||
iconName={IconName.Arrow}
|
|
||||||
size={ButtonSize.Small}
|
|
||||||
/>
|
|
||||||
</Styled.Row>
|
|
||||||
</Styled.Panel>
|
</Styled.Panel>
|
||||||
|
|
||||||
{isNotTablet && (
|
{isNotTablet && <DYDXBalancePanel />}
|
||||||
<Styled.BalancePanelContainer>
|
|
||||||
<DYDXBalancePanel />
|
|
||||||
</Styled.BalancePanelContainer>
|
|
||||||
)}
|
|
||||||
</Styled.PanelRow>
|
</Styled.PanelRow>
|
||||||
</Styled.Page>
|
</Styled.Page>
|
||||||
);
|
);
|
||||||
@@ -191,143 +79,56 @@ const Styled: Record<string, AnyStyledComponent> = {};
|
|||||||
Styled.Page = styled.div`
|
Styled.Page = styled.div`
|
||||||
${layoutMixins.contentContainerPage}
|
${layoutMixins.contentContainerPage}
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
|
padding: 2rem;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
--content-max-width: 70rem;
|
||||||
|
max-width: min(calc(100vw - 4rem), var(--content-max-width));
|
||||||
|
}
|
||||||
|
|
||||||
@media ${breakpoints.tablet} {
|
@media ${breakpoints.tablet} {
|
||||||
padding: 1rem;
|
padding: 1.25rem;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
max-width: calc(100vw - 2.5rem);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Panel = styled(Panel)`
|
Styled.Panel = styled(Panel)`
|
||||||
padding: 0 1.5rem 1rem;
|
--panel-paddingX: 1.5rem;
|
||||||
|
|
||||||
@media ${breakpoints.tablet} {
|
|
||||||
max-width: calc(100vw - 2rem);
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Row = styled.div`
|
Styled.Title = styled.h3`
|
||||||
${layoutMixins.spacedRow}
|
font: var(--font-medium-book);
|
||||||
gap: 1rem;
|
color: var(--color-text-2);
|
||||||
|
padding: 1rem 1.5rem 0;
|
||||||
align-items: center;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Description = styled.div`
|
Styled.Description = styled.div`
|
||||||
color: var(--color-text-0);
|
color: var(--color-text-0);
|
||||||
|
--link-color: var(--color-text-1);
|
||||||
a {
|
|
||||||
color: var(--color-text-1);
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.Migrate = styled.section`
|
Styled.PanelRow = styled.div`
|
||||||
max-width: min(100vw, var(--content-max-width));
|
${layoutMixins.gridEqualColumns}
|
||||||
|
|
||||||
padding: 1.5rem;
|
|
||||||
|
|
||||||
background-color: var(--color-layer-3);
|
|
||||||
border-radius: 0.875rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.TwoItemRow = styled(Styled.Row)`
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.MigrateAction = styled(Styled.TwoItemRow)`
|
|
||||||
padding: 1rem;
|
|
||||||
|
|
||||||
background-color: var(--color-layer-2);
|
|
||||||
border: solid var(--border-width) var(--color-border);
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Token = styled(Output)`
|
|
||||||
font: var(--font-large-book);
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.PanelRow = styled(Styled.Row)`
|
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
max-width: min(100vw, var(--content-max-width));
|
|
||||||
align-items: flex-start;
|
|
||||||
|
|
||||||
> section {
|
align-items: flex-start;
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media ${breakpoints.tablet} {
|
@media ${breakpoints.tablet} {
|
||||||
grid-auto-flow: row;
|
grid-auto-flow: row;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
max-width: auto;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Styled.BalancePanelContainer = styled.div`
|
|
||||||
width: 21.25rem;
|
|
||||||
|
|
||||||
@media ${breakpoints.tablet} {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Title = styled.h3`
|
|
||||||
${layoutMixins.inlineRow}
|
|
||||||
padding: 1.25rem 1.5rem 0.5rem;
|
|
||||||
|
|
||||||
font: var(--font-medium-book);
|
|
||||||
color: var(--color-text-2);
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.MigrateTitle = styled(Styled.Title)`
|
|
||||||
padding: 0 0 0.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.MobileMigrateCard = styled(Styled.Panel)`
|
|
||||||
${layoutMixins.flexColumn}
|
|
||||||
gap: 1rem;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.MobileMigrateHeader = styled(Styled.Title)`
|
|
||||||
${layoutMixins.inlineRow}
|
|
||||||
gap: 1ch;
|
|
||||||
padding-bottom: 1rem;
|
|
||||||
|
|
||||||
font: var(--font-small-book);
|
|
||||||
color: var(--color-text-0);
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
${layoutMixins.inlineRow}
|
|
||||||
font: var(--font-large-book);
|
|
||||||
color: var(--color-text-2);
|
|
||||||
|
|
||||||
svg {
|
|
||||||
font-size: 1.75rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
margin-top: 0.2rem;
|
|
||||||
b {
|
|
||||||
font-weight: var(--fontWeight-book);
|
|
||||||
color: var(--color-text-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Details = styled(Details)`
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.WithReceipt = styled(WithReceipt)`
|
|
||||||
width: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.LearnMore = styled(Styled.Description)`
|
|
||||||
${layoutMixins.row}
|
|
||||||
gap: 1ch;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.IconButton = styled(IconButton)`
|
Styled.IconButton = styled(IconButton)`
|
||||||
color: var(--color-text-0);
|
color: var(--color-text-0);
|
||||||
|
--color-border: var(--color-layer-6);
|
||||||
|
`;
|
||||||
|
|
||||||
|
Styled.Arrow = styled.div`
|
||||||
|
padding: 1rem;
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -227,8 +227,8 @@ export const HorizontalPanel = ({ isOpen = true, setIsOpen }: ElementProps) => {
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
value={view}
|
value={view}
|
||||||
onValueChange={(newView: string) => {
|
onValueChange={setView}
|
||||||
setView((newView || view) as PanelView);
|
onInteraction={() => {
|
||||||
setIsOpen?.(true);
|
setIsOpen?.(true);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { MustBigNumber } from '@/lib/numbers';
|
|||||||
import { MidMarketPrice } from '@/views/MidMarketPrice';
|
import { MidMarketPrice } from '@/views/MidMarketPrice';
|
||||||
|
|
||||||
export const TradeHeaderMobile = () => {
|
export const TradeHeaderMobile = () => {
|
||||||
const { name, symbol } = useSelector(getCurrentMarketAssetData, shallowEqual) ?? {};
|
const { name, id } = useSelector(getCurrentMarketAssetData, shallowEqual) ?? {};
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { market, priceChange24H, priceChange24HPercent } =
|
const { market, priceChange24H, priceChange24HPercent } =
|
||||||
@@ -27,7 +27,7 @@ export const TradeHeaderMobile = () => {
|
|||||||
<Styled.Header>
|
<Styled.Header>
|
||||||
<BackButton onClick={() => navigate(AppRoute.Markets)} />
|
<BackButton onClick={() => navigate(AppRoute.Markets)} />
|
||||||
<Styled.MarketName>
|
<Styled.MarketName>
|
||||||
<Styled.AssetIcon symbol={symbol} />
|
<Styled.AssetIcon symbol={id} />
|
||||||
<Styled.Name>
|
<Styled.Name>
|
||||||
<h3>{name}</h3>
|
<h3>{name}</h3>
|
||||||
<span>{market}</span>
|
<span>{market}</span>
|
||||||
|
|||||||
@@ -151,7 +151,10 @@ export const AccountInfoConnectedState = () => {
|
|||||||
),
|
),
|
||||||
label: stringGetter({ key: STRING_KEYS.BUYING_POWER }),
|
label: stringGetter({ key: STRING_KEYS.BUYING_POWER }),
|
||||||
type: OutputType.Fiat,
|
type: OutputType.Fiat,
|
||||||
value: buyingPower,
|
value:
|
||||||
|
MustBigNumber(buyingPower?.current).lt(0) && buyingPower?.postOrder === null
|
||||||
|
? undefined
|
||||||
|
: buyingPower,
|
||||||
},
|
},
|
||||||
].map(
|
].map(
|
||||||
({
|
({
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const MarketFilter = ({
|
|||||||
<>
|
<>
|
||||||
{!isSearch && (
|
{!isSearch && (
|
||||||
<ToggleGroup
|
<ToggleGroup
|
||||||
items={Object.entries(filters).map(([key, value]) => ({
|
items={Object.values(filters).map((value) => ({
|
||||||
label: stringGetter({ key: MARKET_FILTER_LABELS[value] }),
|
label: stringGetter({ key: MARKET_FILTER_LABELS[value] }),
|
||||||
value,
|
value,
|
||||||
}))}
|
}))}
|
||||||
|
|||||||
@@ -198,8 +198,6 @@ Styled.Details = styled(Details)`
|
|||||||
@media ${breakpoints.tablet} {
|
@media ${breakpoints.tablet} {
|
||||||
${layoutMixins.withOuterAndInnerBorders}
|
${layoutMixins.withOuterAndInnerBorders}
|
||||||
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
|
|
||||||
font: var(--font-small-book);
|
font: var(--font-small-book);
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ Styled.TriggerIcon = styled.span`
|
|||||||
width: 0.75em;
|
width: 0.75em;
|
||||||
|
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
transition: transform 0.3s var(--ease-out-expo);
|
transition: rotate 0.3s var(--ease-out-expo);
|
||||||
|
|
||||||
${Styled.Trigger}[data-state='open'] & {
|
${Styled.Trigger}[data-state='open'] & {
|
||||||
rotate: -0.5turn;
|
rotate: -0.5turn;
|
||||||
|
|||||||
@@ -246,9 +246,7 @@ export const FundingChart = ({ selectedLocale }: ElementProps) => {
|
|||||||
}[rate] || '',
|
}[rate] || '',
|
||||||
}))}
|
}))}
|
||||||
value={fundingRateView}
|
value={fundingRateView}
|
||||||
onValueChange={(newRate: FundingRateResolution) => {
|
onValueChange={setFundingRateView}
|
||||||
if (newRate) setFundingRateView(newRate);
|
|
||||||
}}
|
|
||||||
size={ButtonSize.XSmall}
|
size={ButtonSize.XSmall}
|
||||||
/>
|
/>
|
||||||
</Styled.FundingRateToggle>
|
</Styled.FundingRateToggle>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import styled, { type AnyStyledComponent } from 'styled-components';
|
|||||||
|
|
||||||
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 { useBreakpoints, useStringGetter } from '@/hooks';
|
import { useBreakpoints, useStringGetter, useURLConfigs } from '@/hooks';
|
||||||
|
|
||||||
import { Button } from '@/components/Button';
|
import { Button } from '@/components/Button';
|
||||||
import { Dialog, DialogPlacement } from '@/components/Dialog';
|
import { Dialog, DialogPlacement } from '@/components/Dialog';
|
||||||
@@ -15,12 +15,10 @@ type ElementProps = {
|
|||||||
setIsOpen: (open: boolean) => void;
|
setIsOpen: (open: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: replace placeholder URL with real URLs when avaialble
|
|
||||||
const KEPLR_DASHBOARD_URL = 'https://testnet.keplr.app/';
|
|
||||||
const HELP_URL = 'https://help.dydx.exchange/en/articles/2921366-how-do-i-create-an-account-or-sign-up';
|
|
||||||
|
|
||||||
export const ExternalNavKeplrDialog = ({ setIsOpen }: ElementProps) => {
|
export const ExternalNavKeplrDialog = ({ setIsOpen }: ElementProps) => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
|
const { keplrDashboard, accountExportLearnMore } = useURLConfigs();
|
||||||
|
|
||||||
const { isTablet } = useBreakpoints();
|
const { isTablet } = useBreakpoints();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -31,7 +29,7 @@ export const ExternalNavKeplrDialog = ({ setIsOpen }: ElementProps) => {
|
|||||||
placement={isTablet ? DialogPlacement.FullScreen : DialogPlacement.Default}
|
placement={isTablet ? DialogPlacement.FullScreen : DialogPlacement.Default}
|
||||||
>
|
>
|
||||||
<Styled.Content>
|
<Styled.Content>
|
||||||
<Styled.Button type={ButtonType.Link} size={ButtonSize.XLarge} href={KEPLR_DASHBOARD_URL}>
|
<Styled.Button type={ButtonType.Link} size={ButtonSize.XLarge} href={keplrDashboard}>
|
||||||
<span>
|
<span>
|
||||||
{stringGetter({
|
{stringGetter({
|
||||||
key: STRING_KEYS.NAVIGATE_TO_KEPLR,
|
key: STRING_KEYS.NAVIGATE_TO_KEPLR,
|
||||||
@@ -48,7 +46,7 @@ export const ExternalNavKeplrDialog = ({ setIsOpen }: ElementProps) => {
|
|||||||
/>
|
/>
|
||||||
</Styled.Button>
|
</Styled.Button>
|
||||||
|
|
||||||
<Styled.Button type={ButtonType.Link} size={ButtonSize.XLarge} href={HELP_URL}>
|
<Styled.Button type={ButtonType.Link} size={ButtonSize.XLarge} href={accountExportLearnMore}>
|
||||||
<span>
|
<span>
|
||||||
{stringGetter({
|
{stringGetter({
|
||||||
key: STRING_KEYS.LEARN_TO_EXPORT,
|
key: STRING_KEYS.LEARN_TO_EXPORT,
|
||||||
@@ -104,4 +102,5 @@ Styled.Button = styled(Button)`
|
|||||||
|
|
||||||
Styled.IconButton = styled(IconButton)`
|
Styled.IconButton = styled(IconButton)`
|
||||||
color: var(--color-text-0);
|
color: var(--color-text-0);
|
||||||
|
--color-border: var(--color-layer-6);
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import { useMemo } from 'react';
|
|||||||
import styled, { AnyStyledComponent } from 'styled-components';
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
|
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { useStringGetter } from '@/hooks';
|
import { useStringGetter, useURLConfigs } from '@/hooks';
|
||||||
import { ChatIcon, FeedbackIcon, FileIcon, TerminalIcon } from '@/icons';
|
|
||||||
|
|
||||||
import { ComboboxDialogMenu } from '@/components/ComboboxDialogMenu';
|
import { ComboboxDialogMenu } from '@/components/ComboboxDialogMenu';
|
||||||
|
import { Icon, IconName } from '@/components/Icon';
|
||||||
|
|
||||||
import { isTruthy } from '@/lib/isTruthy';
|
import { isTruthy } from '@/lib/isTruthy';
|
||||||
|
|
||||||
@@ -13,39 +13,24 @@ type ElementProps = {
|
|||||||
setIsOpen: (open: boolean) => void;
|
setIsOpen: (open: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const HELP_LINKS = {
|
|
||||||
apiDocumentation: 'https://v4-teacher.vercel.app/',
|
|
||||||
helpCenter: null,
|
|
||||||
feedback: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const HelpDialog = ({ setIsOpen }: ElementProps) => {
|
export const HelpDialog = ({ setIsOpen }: ElementProps) => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
|
const { help: helpCenter, community } = useURLConfigs();
|
||||||
|
|
||||||
const HELP_ITEMS = useMemo(
|
const HELP_ITEMS = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
group: 'help-items',
|
group: 'help-items',
|
||||||
items: [
|
items: [
|
||||||
HELP_LINKS.helpCenter && {
|
helpCenter && {
|
||||||
value: 'help-center',
|
value: 'help-center',
|
||||||
label: stringGetter({ key: STRING_KEYS.HELP_CENTER }),
|
label: stringGetter({ key: STRING_KEYS.HELP_CENTER }),
|
||||||
description: stringGetter({ key: STRING_KEYS.HELP_CENTER_DESCRIPTION }),
|
description: stringGetter({ key: STRING_KEYS.HELP_CENTER_DESCRIPTION }),
|
||||||
onSelect: () => {
|
onSelect: () => {
|
||||||
HELP_LINKS.helpCenter && globalThis.open(HELP_LINKS.helpCenter, '_blank');
|
helpCenter && globalThis.open(helpCenter, '_blank');
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
},
|
},
|
||||||
slotBefore: <FileIcon />,
|
slotBefore: <Icon iconName={IconName.File} />,
|
||||||
},
|
|
||||||
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 && {
|
globalThis?.Intercom && {
|
||||||
value: 'live-chat',
|
value: 'live-chat',
|
||||||
@@ -55,22 +40,22 @@ export const HelpDialog = ({ setIsOpen }: ElementProps) => {
|
|||||||
globalThis.Intercom('show');
|
globalThis.Intercom('show');
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
},
|
},
|
||||||
slotBefore: <ChatIcon />,
|
slotBefore: <Icon iconName={IconName.Chat} />,
|
||||||
},
|
},
|
||||||
HELP_LINKS.feedback && {
|
community && {
|
||||||
value: 'feedback',
|
value: 'community',
|
||||||
label: stringGetter({ key: STRING_KEYS.PROVIDE_FEEDBACK }),
|
label: stringGetter({ key: STRING_KEYS.COMMUNITY }),
|
||||||
description: stringGetter({ key: STRING_KEYS.PROVIDE_FEEDBACK_DESCRIPTION }),
|
description: stringGetter({ key: STRING_KEYS.COMMUNITY_DESCRIPTION }),
|
||||||
onSelect: () => {
|
onSelect: () => {
|
||||||
HELP_LINKS.feedback && globalThis.open(HELP_LINKS.feedback, '_blank');
|
community && globalThis.open(community, '_blank');
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
},
|
},
|
||||||
slotBefore: <FeedbackIcon />,
|
slotBefore: <Icon iconName={IconName.Discord} />,
|
||||||
},
|
},
|
||||||
].filter(isTruthy),
|
].filter(isTruthy),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[stringGetter]
|
[stringGetter, helpCenter, community]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -13,16 +13,15 @@ import { Button } from '@/components/Button';
|
|||||||
import { Icon } from '@/components/Icon';
|
import { Icon } from '@/components/Icon';
|
||||||
import { Link } from '@/components/Link';
|
import { Link } from '@/components/Link';
|
||||||
|
|
||||||
import { useAccounts, useStringGetter } from '@/hooks';
|
import { useAccounts, useStringGetter, useURLConfigs } from '@/hooks';
|
||||||
import { useDisplayedWallets } from '@/hooks/useDisplayedWallets';
|
import { useDisplayedWallets } from '@/hooks/useDisplayedWallets';
|
||||||
|
|
||||||
import { breakpoints } from '@/styles';
|
import { breakpoints } from '@/styles';
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
|
||||||
const aboutWalletsLink = `https://www.dydx.academy/video/defi-wallet`;
|
|
||||||
|
|
||||||
export const ChooseWallet = () => {
|
export const ChooseWallet = () => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
|
const { walletLearnMore } = useURLConfigs();
|
||||||
|
|
||||||
const displayedWallets = useDisplayedWallets();
|
const displayedWallets = useDisplayedWallets();
|
||||||
|
|
||||||
@@ -63,7 +62,7 @@ export const ChooseWallet = () => {
|
|||||||
</Styled.Wallets>
|
</Styled.Wallets>
|
||||||
|
|
||||||
<Styled.Footer>
|
<Styled.Footer>
|
||||||
<Link href={aboutWalletsLink} withIcon>
|
<Link href={walletLearnMore} withIcon>
|
||||||
{stringGetter({ key: STRING_KEYS.ABOUT_WALLETS })}
|
{stringGetter({ key: STRING_KEYS.ABOUT_WALLETS })}
|
||||||
</Link>
|
</Link>
|
||||||
</Styled.Footer>
|
</Styled.Footer>
|
||||||
|
|||||||
@@ -130,12 +130,14 @@ export const GenerateKeys = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
setStatus(EvmDerivedAccountStatus.NotDerived);
|
||||||
const { message } = parseWalletError({ error, stringGetter });
|
const { message } = parseWalletError({ error, stringGetter });
|
||||||
|
|
||||||
if (message) {
|
if (message) {
|
||||||
track(AnalyticsEvent.OnboardingWalletIsNonDeterministic);
|
track(AnalyticsEvent.OnboardingWalletIsNonDeterministic);
|
||||||
setError(message);
|
setError(message);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await setWalletFromEvmSignature(signature);
|
await setWalletFromEvmSignature(signature);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export const TradeDialog = ({ isOpen, setIsOpen, slotTrigger }: ElementProps) =>
|
|||||||
const selectedTradeType = getSelectedTradeType(type);
|
const selectedTradeType = getSelectedTradeType(type);
|
||||||
const { typeOptions } = useSelector(getInputTradeOptions, shallowEqual) ?? {};
|
const { typeOptions } = useSelector(getInputTradeOptions, shallowEqual) ?? {};
|
||||||
|
|
||||||
const allTradeTypeItems = typeOptions?.toArray()?.map(({ type, stringKey }) => ({
|
const allTradeTypeItems = (typeOptions?.toArray() ?? []).map(({ type, stringKey }) => ({
|
||||||
value: type,
|
value: type,
|
||||||
label: stringGetter({
|
label: stringGetter({
|
||||||
key: stringKey as StringKey,
|
key: stringKey as StringKey,
|
||||||
@@ -73,9 +73,7 @@ export const TradeDialog = ({ isOpen, setIsOpen, slotTrigger }: ElementProps) =>
|
|||||||
<Styled.ToggleGroup
|
<Styled.ToggleGroup
|
||||||
items={allTradeTypeItems}
|
items={allTradeTypeItems}
|
||||||
value={selectedTradeType}
|
value={selectedTradeType}
|
||||||
onValueChange={(tradeType: TradeTypes) =>
|
onValueChange={onTradeTypeChange}
|
||||||
onTradeTypeChange(tradeType || selectedTradeType)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { type Dispatch, type SetStateAction, useState, type ReactNode } from 'react';
|
import { type Dispatch, type SetStateAction, useState, type ReactNode } from 'react';
|
||||||
import styled, { type AnyStyledComponent, } from 'styled-components';
|
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||||
import { shallowEqual, useSelector } from 'react-redux';
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
import type { RouteData } from '@0xsquid/sdk';
|
import type { RouteData } from '@0xsquid/sdk';
|
||||||
|
|
||||||
@@ -32,6 +32,8 @@ import { WithReceipt } from '@/components/WithReceipt';
|
|||||||
import { getSubaccountBuyingPower, getSubaccountEquity } from '@/state/accountSelectors';
|
import { getSubaccountBuyingPower, getSubaccountEquity } from '@/state/accountSelectors';
|
||||||
import { getTransferInputs } from '@/state/inputsSelectors';
|
import { getTransferInputs } from '@/state/inputsSelectors';
|
||||||
|
|
||||||
|
import { MustBigNumber } from '@/lib/numbers';
|
||||||
|
|
||||||
import { SlippageEditor } from '../SlippageEditor';
|
import { SlippageEditor } from '../SlippageEditor';
|
||||||
|
|
||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
@@ -131,7 +133,7 @@ export const DepositButtonAndReceipt = ({
|
|||||||
value: (
|
value: (
|
||||||
<DiffOutput
|
<DiffOutput
|
||||||
type={OutputType.Fiat}
|
type={OutputType.Fiat}
|
||||||
value={buyingPower}
|
value={MustBigNumber(buyingPower).lt(0) ? undefined : buyingPower}
|
||||||
newValue={newBuyingPower}
|
newValue={newBuyingPower}
|
||||||
sign={NumberSign.Positive}
|
sign={NumberSign.Positive}
|
||||||
withDiff={Boolean(newBuyingPower) && buyingPower !== newBuyingPower}
|
withDiff={Boolean(newBuyingPower) && buyingPower !== newBuyingPower}
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ export const ClosePositionForm = ({
|
|||||||
value: value.toString(),
|
value: value.toString(),
|
||||||
}))}
|
}))}
|
||||||
value={percent?.toString() ?? ''}
|
value={percent?.toString() ?? ''}
|
||||||
onValueChange={(value: any) => onSelectPercentage((value || percent?.toString()) ?? '')}
|
onValueChange={onSelectPercentage}
|
||||||
shape={ButtonShape.Rectangle}
|
shape={ButtonShape.Rectangle}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -322,7 +322,6 @@ export const TradeForm = ({
|
|||||||
summary={summary ?? undefined}
|
summary={summary ?? undefined}
|
||||||
currentStep={currentStep}
|
currentStep={currentStep}
|
||||||
showDeposit={inputAlert?.errorAction === TradeInputErrorAction.DEPOSIT}
|
showDeposit={inputAlert?.errorAction === TradeInputErrorAction.DEPOSIT}
|
||||||
showConnectWallet={inputAlert?.errorAction === TradeInputErrorAction.CONNECT_WALLET}
|
|
||||||
/>
|
/>
|
||||||
</Styled.Footer>
|
</Styled.Footer>
|
||||||
</Styled.TradeForm>
|
</Styled.TradeForm>
|
||||||
|
|||||||
@@ -153,9 +153,7 @@ export const MarketLeverageInput = ({
|
|||||||
value: MustBigNumber(leverageAmount).toFixed(LEVERAGE_DECIMALS),
|
value: MustBigNumber(leverageAmount).toFixed(LEVERAGE_DECIMALS),
|
||||||
}))}
|
}))}
|
||||||
value={MustBigNumber(formattedLeverageValue).abs().toFixed(LEVERAGE_DECIMALS)} // sign agnostic
|
value={MustBigNumber(formattedLeverageValue).abs().toFixed(LEVERAGE_DECIMALS)} // sign agnostic
|
||||||
onValueChange={(option?: number) =>
|
onValueChange={updateLeverage}
|
||||||
updateLeverage(option === undefined ? formattedLeverageValue : option)
|
|
||||||
}
|
|
||||||
shape={ButtonShape.Rectangle}
|
shape={ButtonShape.Rectangle}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -7,9 +7,8 @@ import { DialogTypes } from '@/constants/dialogs';
|
|||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { TRADE_TYPE_STRINGS, MobilePlaceOrderSteps } from '@/constants/trade';
|
import { TRADE_TYPE_STRINGS, MobilePlaceOrderSteps } from '@/constants/trade';
|
||||||
|
|
||||||
import { useStringGetter } from '@/hooks';
|
import { useStringGetter, useTokenConfigs } from '@/hooks';
|
||||||
|
|
||||||
import { AssetIcon } from '@/components/AssetIcon';
|
|
||||||
import { Button } from '@/components/Button';
|
import { Button } from '@/components/Button';
|
||||||
import { Output, OutputType, ShowSign } from '@/components/Output';
|
import { Output, OutputType, ShowSign } from '@/components/Output';
|
||||||
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
|
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
|
||||||
@@ -47,6 +46,7 @@ export const PlaceOrderButtonAndReceipt = ({
|
|||||||
}: ElementProps) => {
|
}: ElementProps) => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const { chainTokenLabel } = useTokenConfigs();
|
||||||
|
|
||||||
const canAccountTrade = useSelector(calculateCanAccountTrade);
|
const canAccountTrade = useSelector(calculateCanAccountTrade);
|
||||||
const subaccountNumber = useSelector(getSubaccountId);
|
const subaccountNumber = useSelector(getSubaccountId);
|
||||||
@@ -88,7 +88,14 @@ export const PlaceOrderButtonAndReceipt = ({
|
|||||||
{/* <AssetIcon symbol="DYDX" /> */}
|
{/* <AssetIcon symbol="DYDX" /> */}
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
value: <Output type={OutputType.Asset} value={reward} useGrouping tag={reward ? "Dv4TNT" : ''} />,
|
value: (
|
||||||
|
<Output
|
||||||
|
type={OutputType.Asset}
|
||||||
|
value={reward}
|
||||||
|
useGrouping
|
||||||
|
tag={reward ? chainTokenLabel : ''}
|
||||||
|
/>
|
||||||
|
),
|
||||||
tooltip: 'max-reward',
|
tooltip: 'max-reward',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -111,7 +118,7 @@ export const PlaceOrderButtonAndReceipt = ({
|
|||||||
? actionStringKey
|
? actionStringKey
|
||||||
: STRING_KEYS.UNAVAILABLE,
|
: STRING_KEYS.UNAVAILABLE,
|
||||||
buttonAction: ButtonAction.Primary,
|
buttonAction: ButtonAction.Primary,
|
||||||
buttonState: { isDisabled: !shouldEnableTrade },
|
buttonState: { isDisabled: !shouldEnableTrade, isLoading: hasMissingData },
|
||||||
},
|
},
|
||||||
|
|
||||||
[MobilePlaceOrderSteps.PreviewOrder]: {
|
[MobilePlaceOrderSteps.PreviewOrder]: {
|
||||||
@@ -148,7 +155,10 @@ export const PlaceOrderButtonAndReceipt = ({
|
|||||||
|
|
||||||
const buttonState = currentStep
|
const buttonState = currentStep
|
||||||
? buttonStatesPerStep[currentStep].buttonState
|
? buttonStatesPerStep[currentStep].buttonState
|
||||||
: { isDisabled: !shouldEnableTrade || isLoading, isLoading };
|
: {
|
||||||
|
isDisabled: !shouldEnableTrade || isLoading,
|
||||||
|
isLoading: isLoading || hasMissingData,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WithDetailsReceipt detailItems={items}>
|
<WithDetailsReceipt detailItems={items}>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
useTokenConfigs,
|
useTokenConfigs,
|
||||||
useStringGetter,
|
useStringGetter,
|
||||||
useAccountBalance,
|
useAccountBalance,
|
||||||
|
useURLConfigs,
|
||||||
} from '@/hooks';
|
} from '@/hooks';
|
||||||
|
|
||||||
import { OnboardingTriggerButton } from '@/views/dialogs/OnboardingTriggerButton';
|
import { OnboardingTriggerButton } from '@/views/dialogs/OnboardingTriggerButton';
|
||||||
@@ -35,11 +36,11 @@ import { truncateAddress } from '@/lib/wallet';
|
|||||||
|
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
import { headerMixins } from '@/styles/headerMixins';
|
import { headerMixins } from '@/styles/headerMixins';
|
||||||
|
import { MustBigNumber } from '@/lib/numbers';
|
||||||
const explorerBaseUri = 'https://testnet.mintscan.io/dydx-testnet';
|
|
||||||
|
|
||||||
export const AccountMenu = () => {
|
export const AccountMenu = () => {
|
||||||
const stringGetter = useStringGetter();
|
const stringGetter = useStringGetter();
|
||||||
|
const { mintscanBase } = useURLConfigs();
|
||||||
const { isTablet } = useBreakpoints();
|
const { isTablet } = useBreakpoints();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const onboardingState = useSelector(getOnboardingState);
|
const onboardingState = useSelector(getOnboardingState);
|
||||||
@@ -49,6 +50,8 @@ export const AccountMenu = () => {
|
|||||||
|
|
||||||
const { evmAddress, walletType, dydxAddress, hdKey } = useAccounts();
|
const { evmAddress, walletType, dydxAddress, hdKey } = useAccounts();
|
||||||
|
|
||||||
|
const usdcBalance = freeCollateral?.current || 0;
|
||||||
|
|
||||||
const onRecoverKeys = () => {
|
const onRecoverKeys = () => {
|
||||||
dispatch(openDialog({ type: DialogTypes.Onboarding }));
|
dispatch(openDialog({ type: DialogTypes.Onboarding }));
|
||||||
};
|
};
|
||||||
@@ -92,7 +95,7 @@ export const AccountMenu = () => {
|
|||||||
/>
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
action={ButtonAction.Base}
|
action={ButtonAction.Base}
|
||||||
href={`${explorerBaseUri}/account/${dydxAddress}`}
|
href={`${mintscanBase}/account/${dydxAddress}`}
|
||||||
iconName={IconName.LinkOut}
|
iconName={IconName.LinkOut}
|
||||||
shape={ButtonShape.Square}
|
shape={ButtonShape.Square}
|
||||||
type={ButtonType.Link}
|
type={ButtonType.Link}
|
||||||
@@ -122,7 +125,11 @@ export const AccountMenu = () => {
|
|||||||
</Styled.label>
|
</Styled.label>
|
||||||
<Styled.BalanceOutput type={OutputType.Asset} value={nativeTokenBalance} />
|
<Styled.BalanceOutput type={OutputType.Asset} value={nativeTokenBalance} />
|
||||||
</div>
|
</div>
|
||||||
<AssetActions asset={DydxChainAsset.CHAINTOKEN} dispatch={dispatch} />
|
<AssetActions
|
||||||
|
asset={DydxChainAsset.CHAINTOKEN}
|
||||||
|
dispatch={dispatch}
|
||||||
|
hasBalance={nativeTokenBalance.gt(0)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
@@ -135,11 +142,16 @@ export const AccountMenu = () => {
|
|||||||
</Styled.label>
|
</Styled.label>
|
||||||
<Styled.BalanceOutput
|
<Styled.BalanceOutput
|
||||||
type={OutputType.Asset}
|
type={OutputType.Asset}
|
||||||
value={freeCollateral?.current || 0}
|
value={usdcBalance}
|
||||||
fractionDigits={2}
|
fractionDigits={2}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<AssetActions asset={DydxChainAsset.USDC} dispatch={dispatch} />
|
<AssetActions
|
||||||
|
asset={DydxChainAsset.USDC}
|
||||||
|
dispatch={dispatch}
|
||||||
|
hasBalance={MustBigNumber(usdcBalance).gt(0)}
|
||||||
|
withOnboarding
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Styled.Balances>
|
</Styled.Balances>
|
||||||
</Styled.AccountInfo>
|
</Styled.AccountInfo>
|
||||||
@@ -167,7 +179,7 @@ export const AccountMenu = () => {
|
|||||||
// value: 'ViewInExplorer',
|
// value: 'ViewInExplorer',
|
||||||
// icon: <Icon iconName={IconName.Etherscan} />,
|
// icon: <Icon iconName={IconName.Etherscan} />,
|
||||||
// label: stringGetter({ key: STRING_KEYS.OPEN_IN_ETHERSCAN }),
|
// label: stringGetter({ key: STRING_KEYS.OPEN_IN_ETHERSCAN }),
|
||||||
// onSelect: () => globalThis.open(`${explorerBaseUri}/address/${address}`),
|
// onSelect: () => globalThis.open(`${mintscanBase}/address/${address}`),
|
||||||
// separator: true,
|
// separator: true,
|
||||||
// },
|
// },
|
||||||
...(onboardingState === OnboardingState.AccountConnected && hdKey
|
...(onboardingState === OnboardingState.AccountConnected && hdKey
|
||||||
@@ -212,28 +224,48 @@ export const AccountMenu = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const AssetActions = memo(({ asset, dispatch }: { asset: DydxChainAsset; dispatch: Dispatch }) => (
|
const AssetActions = memo(
|
||||||
<Styled.InlineRow>
|
({
|
||||||
{[
|
asset,
|
||||||
// TODO(@rosepuppy): Add withdraw action for USDC
|
dispatch,
|
||||||
{
|
withOnboarding,
|
||||||
dialogType: DialogTypes.Receive,
|
hasBalance,
|
||||||
iconName: IconName.Qr,
|
}: {
|
||||||
},
|
asset: DydxChainAsset;
|
||||||
{ dialogType: DialogTypes.Transfer, iconName: IconName.Send },
|
dispatch: Dispatch;
|
||||||
].map(({ iconName, dialogType }) => (
|
withOnboarding?: boolean;
|
||||||
<IconButton
|
hasBalance?: boolean;
|
||||||
key={dialogType}
|
}) => (
|
||||||
action={ButtonAction.Base}
|
<Styled.InlineRow>
|
||||||
shape={ButtonShape.Square}
|
{[
|
||||||
iconName={iconName}
|
withOnboarding &&
|
||||||
onClick={() =>
|
hasBalance && {
|
||||||
dispatch(openDialog({ type: dialogType, dialogProps: { selectedAsset: asset } }))
|
dialogType: DialogTypes.Withdraw,
|
||||||
}
|
iconName: IconName.Withdraw,
|
||||||
/>
|
},
|
||||||
))}
|
withOnboarding && {
|
||||||
</Styled.InlineRow>
|
dialogType: DialogTypes.Deposit,
|
||||||
));
|
iconName: IconName.Deposit,
|
||||||
|
},
|
||||||
|
hasBalance && {
|
||||||
|
dialogType: DialogTypes.Transfer,
|
||||||
|
dialogProps: { selectedAsset: asset },
|
||||||
|
iconName: IconName.Send,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.filter(isTruthy)
|
||||||
|
.map(({ iconName, dialogType, dialogProps }) => (
|
||||||
|
<Styled.IconButton
|
||||||
|
key={dialogType}
|
||||||
|
action={ButtonAction.Base}
|
||||||
|
shape={ButtonShape.Square}
|
||||||
|
iconName={iconName}
|
||||||
|
onClick={() => dispatch(openDialog({ type: dialogType, dialogProps }))}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Styled.InlineRow>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
const Styled: Record<string, AnyStyledComponent> = {};
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
@@ -351,3 +383,7 @@ Styled.ConnectToChain = styled(Styled.Column)`
|
|||||||
font: var(--font-small-book);
|
font: var(--font-small-book);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
Styled.IconButton = styled(IconButton)`
|
||||||
|
--button-padding: 0 0.25rem;
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
import { groupBy } from 'lodash';
|
import { groupBy } from 'lodash';
|
||||||
|
|
||||||
import { type Notification, NotificationStatus } from '@/constants/notifications';
|
import { type Notification, NotificationStatus } from '@/constants/notifications';
|
||||||
|
|
||||||
|
import { useBreakpoints } from '@/hooks';
|
||||||
import { useNotifications } from '@/hooks/useNotifications';
|
import { useNotifications } from '@/hooks/useNotifications';
|
||||||
|
import { CloseIcon } from '@/icons';
|
||||||
|
|
||||||
import { Button } from '@/components/Button';
|
import { Button } from '@/components/Button';
|
||||||
import { ButtonAction, ButtonSize } from '@/constants/buttons';
|
import { ButtonAction, ButtonSize } from '@/constants/buttons';
|
||||||
@@ -13,10 +16,6 @@ import { DialogPlacement } from '@/components/Dialog';
|
|||||||
import { Output, OutputType } from '@/components/Output';
|
import { Output, OutputType } from '@/components/Output';
|
||||||
import { IconButton } from '@/components/IconButton';
|
import { IconButton } from '@/components/IconButton';
|
||||||
import { Toolbar } from '@/components/Toolbar';
|
import { Toolbar } from '@/components/Toolbar';
|
||||||
import { CloseIcon } from '@/icons';
|
|
||||||
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
|
||||||
|
|
||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
slotTrigger?: React.ReactNode;
|
slotTrigger?: React.ReactNode;
|
||||||
@@ -27,6 +26,7 @@ export const NotificationsMenu = ({
|
|||||||
slotTrigger,
|
slotTrigger,
|
||||||
placement = DialogPlacement.Sidebar,
|
placement = DialogPlacement.Sidebar,
|
||||||
}: ElementProps) => {
|
}: ElementProps) => {
|
||||||
|
const { isTablet } = useBreakpoints();
|
||||||
const {
|
const {
|
||||||
notifications,
|
notifications,
|
||||||
getDisplayData,
|
getDisplayData,
|
||||||
@@ -173,6 +173,7 @@ export const NotificationsMenu = ({
|
|||||||
</$FooterToolbar>
|
</$FooterToolbar>
|
||||||
}
|
}
|
||||||
placement={placement}
|
placement={placement}
|
||||||
|
preventClose={isTablet}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ const getOrdersTableColumnDef = ({
|
|||||||
key: STRING_KEYS.FILL,
|
key: STRING_KEYS.FILL,
|
||||||
})}`,
|
})}`,
|
||||||
renderCell: ({
|
renderCell: ({
|
||||||
asset: { symbol: assetSymbol },
|
asset,
|
||||||
createdAtMilliseconds,
|
createdAtMilliseconds,
|
||||||
size,
|
size,
|
||||||
status,
|
status,
|
||||||
@@ -254,7 +254,7 @@ const getOrdersTableColumnDef = ({
|
|||||||
value={createdAtMilliseconds}
|
value={createdAtMilliseconds}
|
||||||
/>
|
/>
|
||||||
<Styled.AssetIconWithStatus>
|
<Styled.AssetIconWithStatus>
|
||||||
<Styled.AssetIcon symbol={assetSymbol} />
|
<Styled.AssetIcon symbol={asset?.id} />
|
||||||
<Styled.StatusDot color={statusIconColor} />
|
<Styled.StatusDot color={statusIconColor} />
|
||||||
</Styled.AssetIconWithStatus>
|
</Styled.AssetIconWithStatus>
|
||||||
</>
|
</>
|
||||||
@@ -276,7 +276,7 @@ const getOrdersTableColumnDef = ({
|
|||||||
type={OutputType.Asset}
|
type={OutputType.Asset}
|
||||||
value={size}
|
value={size}
|
||||||
fractionDigits={TOKEN_DECIMALS}
|
fractionDigits={TOKEN_DECIMALS}
|
||||||
tag={assetSymbol}
|
tag={asset?.id}
|
||||||
/>
|
/>
|
||||||
</Styled.InlineRow>
|
</Styled.InlineRow>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
Reference in New Issue
Block a user