Compare commits

..
Author SHA1 Message Date
Bill He f1f10357c4 Abort key derivation if second signature fails 2023-10-27 10:22:41 -07:00
34 changed files with 467 additions and 808 deletions
+1 -2
View File
@@ -6,5 +6,4 @@ VITE_PK_ENCRYPTION_KEY=
VITE_WALLETCONNECT2_PROJECT_ID=
VITE_V3_TOKEN_ADDRESS=
VITE_TOKEN_MIGRATION_URI=
VITE_V3_TOKEN_ADDRESS=
+4 -21
View File
@@ -26,7 +26,7 @@ Alternatively, follow the [IPFS Kubo installation guide](https://docs.ipfs.tech
## Part 1: Setting up your local environment
### 1. Clone the repo
### Step 1: Clone the repo
Clone the repository and navigate to its directory:
@@ -35,7 +35,7 @@ git clone https://github.com/dydxprotocol/v4-web.git
cd v4-web
```
### 2. Install pnpm and dependencies
### Step 2: Install pnpm and dependencies
Install pnpm and the project dependencies:
@@ -69,9 +69,7 @@ You'll need to provide a Wallet Connect project id to enable onboarding and wall
- 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)
# Deployments
## Deploying with Vercel
## Part 4: Deploying with Vercel
### Step 1: Connect your repository to Vercel
@@ -88,7 +86,7 @@ If you wish to incorporate analytics via Amplitude and Bugsnag, you can use our
For more details, check out Vercel's [official documentation](https://vercel.com/docs).
## Deploying to IPFS
## Part 5: Deploying to IPFS
### web3.storage: deploy to IPFS via web3.storage using the provided script
@@ -120,18 +118,3 @@ 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`.
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
+2 -2
View File
@@ -40,8 +40,8 @@
"@cosmjs/stargate": "^0.31.0",
"@cosmjs/tendermint-rpc": "^0.31.0",
"@dydxprotocol/v4-abacus": "^1.0.3",
"@dydxprotocol/v4-client-js": "^1.0.0",
"@dydxprotocol/v4-localization": "^1.0.0",
"@dydxprotocol/v4-client-js": "^0.40.3",
"@dydxprotocol/v4-localization": "^0.1.32",
"@ethersproject/providers": "^5.7.2",
"@js-joda/core": "^5.5.3",
"@radix-ui/react-collapsible": "^1.0.3",
+12 -12
View File
@@ -1,5 +1,9 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
'@0xsquid/sdk':
specifier: ^1.10.0
@@ -26,11 +30,11 @@ dependencies:
specifier: ^1.0.3
version: 1.0.3
'@dydxprotocol/v4-client-js':
specifier: ^1.0.0
version: 1.0.0
specifier: ^0.40.3
version: 0.40.3
'@dydxprotocol/v4-localization':
specifier: ^1.0.0
version: 1.0.0
specifier: ^0.1.32
version: 0.1.32
'@ethersproject/providers':
specifier: ^5.7.2
version: 5.7.2
@@ -979,8 +983,8 @@ packages:
resolution: {integrity: sha512-GuX37/DMMNSke8ZFcw52II7IVJfUgVGHqoi1Uw2cUb+hgIjjSG3OtbyRWedm5r6nqWq8BNLOexI0VVFB6OMVYg==}
dev: false
/@dydxprotocol/v4-client-js@1.0.0:
resolution: {integrity: sha512-ehfHO+zQy795TcJRwtiawadFHZyh4HnpJNP26hCGsIjLE5q6LLHweQHpK/1N/sXU1PBOuQwc7iaJnFop6gYauQ==}
/@dydxprotocol/v4-client-js@0.40.3:
resolution: {integrity: sha512-nMQd6tYisKDKIbfx0BGJSYEOSt+I+t5SsaBSmlgTdso+w2rCRO9vyxS+u6MF9h4w5FsVRfhHo3e6uTWX48WpGQ==}
dependencies:
'@cosmjs/amino': 0.30.1
'@cosmjs/encoding': 0.31.1
@@ -1007,8 +1011,8 @@ packages:
- utf-8-validate
dev: false
/@dydxprotocol/v4-localization@1.0.0:
resolution: {integrity: sha512-U7QjOlzpfSAVEchkNDB3xYRx7okzdeYi83XsnHwI+EHa2quFm/2Y2dhrBkT5fqpZmhcwxb/vG8AZmFSToOf9hA==}
/@dydxprotocol/v4-localization@0.1.32:
resolution: {integrity: sha512-ZtXScxgFLjUt0Ag52RyFnQe9aEl1Aky5fp+vMGOBduVkFiCEMRMkSsSgg6grMdyw/x0AbnxOTRkhYoX2MsK9Ow==}
dev: false
/@dydxprotocol/v4-proto@0.4.1:
@@ -14096,7 +14100,3 @@ packages:
/zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
dev: true
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
+87 -226
View File
@@ -22,11 +22,11 @@
"dydxprotocol-staging-west",
"dydxprotocol-testnet",
"dydxprotocol-testnet-dydx",
"dydxprotocol-testnet-dsrv",
"dydxprotocol-testnet-nodefleet",
"dydxprotocol-testnet-kingnodes",
"dydxprotocol-testnet-liquify",
"dydxprotocol-testnet-polkachu",
"dydxprotocol-testnet-bware"
"dydxprotocol-testnet-polkachu"
],
"default": "dydxprotocol-testnet"
}
@@ -71,19 +71,7 @@
"tos": "https://dydx.exchange/v4-terms",
"privacy": "https://dydx.exchange/privacy",
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
"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"
"blogs": "https://www.dydx.foundation/blog"
},
"wallets": {
"walletconnect": {
@@ -142,19 +130,7 @@
"tos": "https://dydx.exchange/v4-terms",
"privacy": "https://dydx.exchange/privacy",
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
"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"
"blogs": "https://www.dydx.foundation/blog"
},
"wallets": {
"walletconnect": {
@@ -213,19 +189,7 @@
"tos": "https://dydx.exchange/v4-terms",
"privacy": "https://dydx.exchange/privacy",
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
"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"
"blogs": "https://www.dydx.foundation/blog"
},
"wallets": {
"walletconnect": {
@@ -284,19 +248,7 @@
"tos": "https://dydx.exchange/v4-terms",
"privacy": "https://dydx.exchange/privacy",
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
"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"
"blogs": "https://www.dydx.foundation/blog"
},
"wallets": {
"walletconnect": {
@@ -356,20 +308,10 @@
"tos": "https://dydx.exchange/v4-terms",
"privacy": "https://dydx.exchange/privacy",
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
"documentation": "https://docs.dydx.exchange/",
"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",
"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"
"blogs": "https://www.dydx.foundation/blog"
},
"wallets": {
"walletconnect": {
@@ -429,20 +371,10 @@
"tos": "https://dydx.exchange/v4-terms",
"privacy": "https://dydx.exchange/privacy",
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
"documentation": "https://docs.dydx.exchange/",
"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",
"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"
"blogs": "https://www.dydx.foundation/blog"
},
"wallets": {
"walletconnect": {
@@ -493,7 +425,6 @@
}
],
"validators": [
"https://dydx-testnet-full-rpc.public.blastapi.io/",
"https://dydx-testnet-rpc.polkachu.com/",
"https://dydx-testnet.nodefleet.org",
"https://test-dydx.kingnodes.com",
@@ -506,20 +437,10 @@
"tos": "https://dydx.exchange/v4-terms",
"privacy": "https://dydx.exchange/privacy",
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
"documentation": "https://docs.dydx.exchange/",
"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",
"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"
"blogs": "https://www.dydx.foundation/blog"
},
"wallets": {
"walletconnect": {
@@ -580,20 +501,74 @@
"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/",
"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",
"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"
"blogs": "https://www.dydx.foundation/blog"
},
"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-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": {
"walletconnect": {
@@ -654,20 +629,10 @@
"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/",
"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",
"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"
"blogs": "https://www.dydx.foundation/blog"
},
"wallets": {
"walletconnect": {
@@ -728,20 +693,10 @@
"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/",
"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",
"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"
"blogs": "https://www.dydx.foundation/blog"
},
"wallets": {
"walletconnect": {
@@ -802,20 +757,10 @@
"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/",
"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",
"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"
"blogs": "https://www.dydx.foundation/blog"
},
"wallets": {
"walletconnect": {
@@ -876,7 +821,7 @@
"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/",
"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"
@@ -900,80 +845,6 @@
"signTypedDataDomainName": "dYdX V4"
}
},
"dydxprotocol-testnet-bware": {
"name": "v4 Public Testnet/BWare",
"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-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": {
"name": "v4",
"ethereumChainId": "1",
@@ -1014,20 +885,10 @@
"tos": "[HTTP link to TOS]",
"privacy": "[HTTP link to Privacy Policy]",
"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]",
"community": "[HTTP link to community, can be null]",
"help": "[HTTP link to help page, 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]"
"feedback": "[HTTP link to feedback form, can be null]",
"blogs": "[HTTP link to blogs, can be null]"
},
"wallets": {
"walletconnect": {
-8
View File
@@ -40,7 +40,6 @@
"iosMinVersion": "0",
"imageUrl": "",
"encoding": "=\"#%/<>?@\\^`{|}:&",
"androidPackage": "io.metamask",
"connections": [
{
"type": "walletConnectV2",
@@ -99,7 +98,6 @@
"iosMinVersion": "1.8.0",
"imageUrl": "",
"encoding": "=\"#%/<>?@\\^`{|}:&",
"androidPackage": "org.toshi",
"connections": [
{
"type": "walletSegue",
@@ -157,7 +155,6 @@
"comment": "imToken",
"iosMinVersion": "0",
"imageUrl": "",
"androidPackage": "im.token.app",
"connections": [
{
"type": "walletConnectV2",
@@ -217,7 +214,6 @@
"iosMinVersion": "0",
"encoding": "=\"#%/<>?@\\^`{|}:&",
"imageUrl": "",
"androidPackage": "com.wallet.crypto.trustapp",
"connections": [
{
"type": "walletConnectV2",
@@ -275,7 +271,6 @@
"iosMinVersion": "0",
"encoding": "=\"#%/<>?@\\^`{|}:&",
"imageUrl": "",
"androidPackage": "io.zerion.android",
"connections": [
{
"type": "walletConnectV2",
@@ -332,7 +327,6 @@
"comment": "TokenPocket",
"iosMinVersion": "0",
"imageUrl": "",
"androidPackage": "vip.mytokenpocket",
"connections": [
{
"type": "walletConnectV2",
@@ -389,7 +383,6 @@
"comment": "Rainbow",
"iosMinVersion": "0",
"encoding": "=\"#%/<>?@\\^`{|}:&",
"androidPackage": "me.rainbow",
"backlinked": true,
"imageUrl": "",
"connections": [
@@ -449,7 +442,6 @@
"comment": "1inch",
"iosMinVersion": "0",
"encoding": "=\"#%/<>?@\\^`{|}:&",
"androidPackage": "io.oneinch.android",
"imageUrl": "",
"connections": [
{
-38
View File
@@ -1,38 +0,0 @@
## 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`
+1 -1
View File
@@ -80,7 +80,7 @@ Styled.TriggerIcon = styled.span`
width: var(--trigger-icon-width);
display: inline-flex;
transition: rotate 0.3s var(--ease-out-expo);
transition: transform 0.3s var(--ease-out-expo);
color: var(--trigger-icon-color);
${Styled.Trigger}[data-state='open'] & {
-3
View File
@@ -40,7 +40,6 @@ import {
LockIcon,
LogoShortIcon,
MenuIcon,
MigrateIcon,
MintscanIcon,
OrderbookIcon,
OrderCanceledIcon,
@@ -109,7 +108,6 @@ export enum IconName {
Lock = 'Lock',
LogoShort = 'LogoShort',
Menu = 'Menu',
Migrate = 'Migrate',
Mintscan = 'Mintscan',
Onboarding = 'Onboarding',
Orderbook = 'OrderbookIcon',
@@ -179,7 +177,6 @@ const icons = {
[IconName.Lock]: LockIcon,
[IconName.LogoShort]: LogoShortIcon,
[IconName.Menu]: MenuIcon,
[IconName.Migrate]: MigrateIcon,
[IconName.Mintscan]: MintscanIcon,
[IconName.Orderbook]: OrderbookIcon,
[IconName.OrderCanceled]: OrderCanceledIcon,
-3
View File
@@ -525,9 +525,6 @@ Styled.NavItem = styled(NavItem)<{ orientation: 'horizontal' | 'vertical' }>`
`;
Styled.Icon = styled(Icon)`
height: 0.75em;
transition: rotate 0.3s var(--ease-out-expo);
${Styled.List}[data-orientation="menu"] & {
rotate: -0.25turn;
}
+25 -32
View File
@@ -8,7 +8,6 @@ import { layoutMixins } from '@/styles/layoutMixins';
type PanelProps = {
slotHeaderContent?: string;
slotHeader?: React.ReactNode;
slotRight?: React.ReactNode;
children?: React.ReactNode;
href?: string;
onHeaderClick?: () => void;
@@ -23,7 +22,6 @@ type PanelStyleProps = {
export const Panel = ({
slotHeaderContent,
slotHeader,
slotRight,
children,
href,
onHeaderClick,
@@ -32,61 +30,55 @@ export const Panel = ({
className,
}: PanelProps & PanelStyleProps) => (
<Styled.Panel onClick={onClick}>
<Styled.Left>
{href ? (
<Link to={href}>
{slotHeader ? (
slotHeader
) : (
<Styled.Header role="button" onClick={onHeaderClick} hasSeparator={hasSeparator}>
{slotHeaderContent}
<Styled.Icon iconName={IconName.ChevronRight} />
</Styled.Header>
)}
</Link>
) : slotHeader ? (
slotHeader
) : (
slotHeaderContent && (
{href ? (
<Link to={href}>
{slotHeader ? (
slotHeader
) : (
<Styled.Header role="button" onClick={onHeaderClick} hasSeparator={hasSeparator}>
{slotHeaderContent}
<Styled.Icon iconName={IconName.ChevronRight} />
</Styled.Header>
)
)}
<Styled.Content className={className}>{children}</Styled.Content>
</Styled.Left>
{slotRight}
)}
</Link>
) : slotHeader ? (
slotHeader
) : (
slotHeaderContent && (
<Styled.Header role="button" onClick={onHeaderClick} hasSeparator={hasSeparator}>
{slotHeaderContent}
</Styled.Header>
)
)}
<Styled.Content className={className}>{children}</Styled.Content>
</Styled.Panel>
);
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Panel = styled.section`
${layoutMixins.row}
${layoutMixins.flexColumn}
background-color: var(--color-layer-3);
border-radius: 0.875rem;
`;
Styled.Left = styled.div`
${layoutMixins.flexColumn}
width: 100%;
`;
Styled.Header = styled.header<{ hasSeparator?: boolean }>`
${layoutMixins.spacedRow}
padding: 1rem 1rem;
padding: 0.875rem 1rem 0.625rem;
font-size: 0.875rem;
${({ hasSeparator }) =>
hasSeparator &&
css`
padding-bottom: 0.625rem;
box-shadow: 0 var(--border-width) var(--border-color);
`}
`;
Styled.Icon = styled(Icon)`
color: var(--color-text-0);
font-size: 0.625rem;
`;
@@ -94,5 +86,6 @@ Styled.Content = styled.div`
${layoutMixins.scrollArea}
${layoutMixins.stickyArea0}
--stickyArea0-background: transparent;
padding: 1rem 1rem;
padding: 0.5rem 1rem;
`;
+2 -19
View File
@@ -2,13 +2,11 @@ import type { ReactNode } from 'react';
import styled, { AnyStyledComponent } from 'styled-components';
import { Content, Portal, Provider, Root, Trigger, Arrow } from '@radix-ui/react-tooltip';
import { STRING_KEYS } from '@/constants/localization';
import { tooltipStrings } from '@/constants/tooltips';
import { useStringGetter, useURLConfigs } from '@/hooks';
import { useStringGetter } from '@/hooks';
import { Icon, IconName } from '@/components/Icon';
import { Link } from '@/components/Link';
import { layoutMixins } from '@/styles/layoutMixins';
import { popoverMixins } from '@/styles/popoverMixins';
@@ -40,24 +38,20 @@ export const WithTooltip = ({
slotTooltip,
}: ElementProps & StyleProps) => {
const stringGetter = useStringGetter();
const urlConfigs = useURLConfigs();
const getTooltipStrings = tooltip && tooltipStrings[tooltip];
if (!getTooltipStrings && !tooltipString && !slotTooltip) return <>{children}</>;
let tooltipTitle;
let tooltipBody;
let tooltipLearnMore;
if (getTooltipStrings) {
const { title, body, learnMoreLink } = getTooltipStrings({
const { title, body } = getTooltipStrings({
stringGetter,
stringParams,
urlConfigs,
});
tooltipTitle = title;
tooltipBody = body;
tooltipLearnMore = learnMoreLink;
} else {
tooltipBody = tooltipString;
}
@@ -78,13 +72,6 @@ export const WithTooltip = ({
<dl>
{tooltipTitle && <dt>{tooltipTitle}</dt>}
{tooltipBody && <dd>{tooltipBody}</dd>}
{tooltipLearnMore && (
<dd>
<Styled.LearnMore href={tooltipLearnMore}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Styled.LearnMore>
</dd>
)}
<Styled.Arrow />
</dl>
)}
@@ -155,7 +142,3 @@ Styled.Arrow = styled(Arrow)`
Styled.Icon = styled(Icon)`
color: var(--color-text-0);
`;
Styled.LearnMore = styled(Link)`
--link-color: var(--color-accent);
`;
-4
View File
@@ -8,8 +8,6 @@ import {
WARNINGS_STRING_KEYS,
} from '@dydxprotocol/v4-localization';
import { type LinksConfigs } from '@/hooks/useURLConfigs';
export { TOOLTIP_STRING_KEYS } from '@dydxprotocol/v4-localization';
export enum SupportedLocales {
@@ -81,11 +79,9 @@ export type TooltipStrings = {
[key: string]: ({
stringGetter,
stringParams,
urlConfigs,
}: {
stringGetter: StringGetterFunction;
stringParams?: any;
urlConfigs?: LinksConfigs;
}) => {
title: string;
body: string;
+4
View File
@@ -37,3 +37,7 @@ export const HISTORY_ROUTE = `${AppRoute.Portfolio}/${PortfolioRoute.History}/:s
export const DEFAULT_TRADE_ROUTE = `${AppRoute.Trade}/${DEFAULT_MARKETID}`;
export const SETTINGS_ROUTE = `${AppRoute.Settings}/*`;
export const DEFAULT_DOCUMENT_TITLE = 'dYdX';
export enum ExternalLink {
Foundation = 'https://dydx.foundation',
}
+4 -4
View File
@@ -57,10 +57,10 @@ export const tradeTooltips: TooltipStrings = {
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INDEX_PRICE_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.INDEX_PRICE_BODY }),
}),
'initial-margin-fraction': ({ stringGetter, urlConfigs }) => ({
'initial-margin-fraction': ({ stringGetter }) => ({
title: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_MARGIN_FRACTION_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_MARGIN_FRACTION_BODY }),
learnMoreLink: urlConfigs?.initialMarginFractionLearnMore,
learnMoreLink: 'https://help.dydx.exchange/articles/5232637-maximum-position-sizes',
}),
'initial-stop': ({ stringGetter }) => ({
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 }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.REALIZED_PNL_BODY }),
}),
'reduce-only': ({ stringGetter, urlConfigs }) => ({
'reduce-only': ({ stringGetter }) => ({
title: stringGetter({ key: TOOLTIP_STRING_KEYS.REDUCE_ONLY_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.REDUCE_ONLY_BODY }),
learnMoreLink: urlConfigs?.reduceOnlyLearnMore,
learnMoreLink: 'https://help.dydx.exchange/articles/6345793-reduce-only-orders',
}),
spread: () => ({
title: 'Spread',
-2
View File
@@ -22,7 +22,6 @@ import { useShouldShowFooter } from './useShouldShowFooter';
import { useSelectedNetwork } from './useSelectedNetwork';
import { useStringGetter } from './useStringGetter';
import { useSubaccount } from './useSubaccount';
import { useURLConfigs } from './useURLConfigs';
export {
useApiState,
@@ -49,5 +48,4 @@ export {
useSelectedNetwork,
useStringGetter,
useSubaccount,
useURLConfigs,
};
-50
View File
@@ -1,50 +0,0 @@
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,
};
};
-1
View File
@@ -35,7 +35,6 @@ export { default as LockIcon } from './lock.svg';
export { default as LogoShortIcon } from './logo-short';
export { default as MarketsIcon } from './markets.svg';
export { default as MenuIcon } from './menu.svg';
export { default as MigrateIcon } from './migrate.svg';
export { default as MintscanIcon } from './logos/mintscan.svg';
export { default as OrderbookIcon } from './orderbook.svg';
export { default as OverviewIcon } from './overview.svg';
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 694 KiB

+14 -28
View File
@@ -8,7 +8,7 @@ import { STRING_KEYS } from '@/constants/localization';
import { AppRoute } from '@/constants/routes';
import { LogoShortIcon, BellStrokeIcon } from '@/icons';
import { useTokenConfigs, useStringGetter, useURLConfigs } from '@/hooks';
import { useTokenConfigs, useStringGetter } from '@/hooks';
import { Icon, IconName } from '@/components/Icon';
import { IconButton } from '@/components/IconButton';
@@ -24,11 +24,9 @@ import { openDialog } from '@/state/dialogs';
import { headerMixins } from '@/styles/headerMixins';
import { layoutMixins } from '@/styles/layoutMixins';
import breakpoints from '@/styles/breakpoints';
export const HeaderDesktop = () => {
const stringGetter = useStringGetter();
const { documentation, community, mintscanBase } = useURLConfigs();
const dispatch = useDispatch();
const { chainTokenLabel } = useTokenConfigs();
@@ -36,26 +34,26 @@ export const HeaderDesktop = () => {
{
group: 'navigation',
items: [
{
value: 'MARKET',
label: stringGetter({ key: STRING_KEYS.MARKET }),
href: AppRoute.Markets,
},
{
value: 'TRADE',
label: stringGetter({ key: STRING_KEYS.TRADE }),
href: AppRoute.Trade,
},
{
value: 'PORTFOLIO',
label: stringGetter({ key: STRING_KEYS.PORTFOLIO }),
href: AppRoute.Portfolio,
},
{
value: 'MARKETS',
label: stringGetter({ key: STRING_KEYS.MARKETS }),
href: AppRoute.Markets,
},
{
value: chainTokenLabel,
label: chainTokenLabel,
href: `/${chainTokenLabel}`,
},
{
value: 'PORTFOLIO',
label: stringGetter({ key: STRING_KEYS.PORTFOLIO }),
href: AppRoute.Portfolio,
},
{
value: 'MORE',
label: stringGetter({ key: STRING_KEYS.MORE }),
@@ -64,19 +62,19 @@ export const HeaderDesktop = () => {
value: 'DOCUMENTATION',
slotBefore: <Icon iconName={IconName.Terminal} />,
label: stringGetter({ key: STRING_KEYS.DOCUMENTATION }),
href: documentation,
href: 'https://v4-teacher.vercel.app/',
},
{
value: 'MINTSCAN',
slotBefore: <Icon iconName={IconName.Mintscan} />,
label: stringGetter({ key: STRING_KEYS.MINTSCAN }),
href: mintscanBase,
href: 'https://testnet.mintscan.io/dydx-testnet',
},
{
value: 'COMMUNITY',
slotBefore: <Icon iconName={IconName.Discord} />,
label: stringGetter({ key: STRING_KEYS.COMMUNITY }),
href: community,
href: 'https://discord.gg/dydx',
},
{
value: 'TERMS_OF_USE',
@@ -152,7 +150,6 @@ const Styled: Record<string, AnyStyledComponent> = {};
Styled.Header = styled.header`
--header-horizontal-padding-mobile: 0.5rem;
--trigger-height: 2.25rem;
--logo-width: 3.5rem;
${layoutMixins.container}
@@ -160,8 +157,6 @@ Styled.Header = styled.header`
${layoutMixins.scrollSnapItem}
backdrop-filter: none;
height: var(--page-currentHeaderHeight);
grid-area: Header;
display: grid;
@@ -174,14 +169,6 @@ Styled.Header = styled.header`
)
var(--border-width) 1fr var(--border-width) auto;
@media ${breakpoints.tablet} {
--trigger-height: 3rem;
}
@media ${breakpoints.mobile} {
--navBefore-width: 7rem;
}
font-size: 0.9375rem;
:before {
@@ -192,7 +179,6 @@ Styled.Header = styled.header`
Styled.NavigationMenu = styled(NavigationMenu)`
& {
--navigationMenu-height: var(--stickyArea-topHeight);
--navigationMenu-item-height: var(--trigger-height);
}
${layoutMixins.scrollArea}
+8 -16
View File
@@ -46,8 +46,6 @@ import {
WALLET_CONNECT_EXPLORER_RECOMMENDED_IDS,
} from '@/constants/wallets';
import { isTruthy } from './isTruthy';
// Config
export const WAGMI_SUPPORTED_CHAINS: Chain[] = [
@@ -80,17 +78,13 @@ export const WAGMI_SUPPORTED_CHAINS: Chain[] = [
celoAlfajores,
];
const { chains, publicClient, webSocketPublicClient } = configureChains(
WAGMI_SUPPORTED_CHAINS,
[
import.meta.env.VITE_ALCHEMY_API_KEY &&
alchemyProvider({ apiKey: import.meta.env.VITE_ALCHEMY_API_KEY }),
jsonRpcProvider({
rpc: (chain) => ({ http: chain.rpcUrls.default.http[0] }),
}),
publicProvider(),
].filter(isTruthy)
);
const { chains, publicClient, webSocketPublicClient } = configureChains(WAGMI_SUPPORTED_CHAINS, [
// alchemyProvider({ apiKey: import.meta.env.VITE_ALCHEMY_API_KEY }),
jsonRpcProvider({
rpc: (chain) => ({ http: chain.rpcUrls.default.http[0] }),
}),
publicProvider(),
]);
const injectedConnectorOptions = {
chains,
@@ -208,7 +202,5 @@ export const resolveWagmiConnector = ({
? createInjectedConnectorWithProvider(walletConnection.provider)
: walletConnection.type === WalletConnectionType.WalletConnect2 && walletConfig.walletconnect2Id
? createWalletConnect2ConnectorWithId(walletConfig.walletconnect2Id, walletConnectConfig)
: getConnectors(walletConnectConfig).find(
({ id }: { id: string }) => id === walletConnectionConfig.wagmiConnectorId
);
: getConnectors(walletConnectConfig).find(({ id }: { id: string }) => id === walletConnectionConfig.wagmiConnectorId);
};
+10 -14
View File
@@ -17,7 +17,7 @@ import { DialogTypes } from '@/constants/dialogs';
import { STRING_KEYS } from '@/constants/localization';
import { AppRoute, PortfolioRoute, HistoryRoute } from '@/constants/routes';
import { wallets, WalletType } from '@/constants/wallets';
import { useAccounts, useStringGetter, useTokenConfigs } from '@/hooks';
import { useAccounts, useStringGetter } from '@/hooks';
import { getOnboardingState } from '@/state/accountSelectors';
import { openDialog } from '@/state/dialogs';
@@ -37,7 +37,6 @@ const Profile = () => {
const isConnected = onboardingState !== OnboardingState.Disconnected;
const { evmAddress, dydxAddress, walletType } = useAccounts();
const { chainTokenLabel } = useTokenConfigs();
const { data: ensName } = useEnsName({
address: evmAddress,
@@ -138,11 +137,7 @@ const Profile = () => {
layout="grid"
/>
</Panel>
<Styled.RewardsPanel
slotHeaderContent={stringGetter({ key: STRING_KEYS.REWARDS })}
href={`/${chainTokenLabel}`}
hasSeparator
>
<Styled.RewardsPanel header={stringGetter({ key: STRING_KEYS.REWARDS })} hasSeparator>
<Styled.Details
items={[
{ key: 'maker', label: stringGetter({ key: STRING_KEYS.YOU_WILL_EARN }), value: '-' },
@@ -154,8 +149,8 @@ const Profile = () => {
</Styled.EqualGrid>
<Styled.TablePanel
slotHeaderContent={stringGetter({ key: STRING_KEYS.HISTORY })}
href={`${AppRoute.Portfolio}/${PortfolioRoute.History}/${HistoryRoute.Trades}`}
header={stringGetter({ key: STRING_KEYS.HISTORY })}
linkto={`${AppRoute.Portfolio}/${PortfolioRoute.History}/${HistoryRoute.Trades}`}
hasSeparator
>
<FillsTable
@@ -278,21 +273,22 @@ Styled.RewardsPanel = styled(Panel)`
`;
Styled.TablePanel = styled(Panel)`
padding: 0;
max-width: calc(100vw - 2rem);
max-height: 10rem;
margin-top: 0.5rem;
padding: 0;
border-radius: 0.875rem;
table {
--tableCell-padding: 0.25rem 1rem;
--tableRow-backgroundColor: var(--color-layer-3);
background-color: var(--color-layer-3);
background-color: transparent;
thead {
color: var(--color-text-0);
}
tbody {
background-color: transparent;
tr {
td:nth-child(2),
td:nth-child(3) {
-222
View File
@@ -1,222 +0,0 @@
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.MobileMigratePanel
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.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.MobileMigratePanel>
);
};
const Styled: Record<string, AnyStyledComponent> = {};
Styled.MigratePanel = styled(Panel)`
padding: 1rem 1.5rem;
`;
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.MobileMigratePanel = styled(Panel)`
${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);
`;
+236 -42
View File
@@ -1,44 +1,134 @@
import styled, { AnyStyledComponent } from 'styled-components';
import { useDispatch } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { STRING_KEYS } from '@/constants/localization';
import { ButtonAction, ButtonSize } from '@/constants/buttons';
import { ButtonAction, ButtonSize, ButtonState, ButtonType } from '@/constants/buttons';
import { DialogTypes } from '@/constants/dialogs';
import { useBreakpoints, useStringGetter, useURLConfigs } from '@/hooks';
import { useAccountBalance, useBreakpoints, useStringGetter } from '@/hooks';
import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins';
import { Details } from '@/components/Details';
import { Panel } from '@/components/Panel';
import { IconName } from '@/components/Icon';
import { Button } from '@/components/Button';
import { IconButton } from '@/components/IconButton';
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 { getSelectedNetwork } from '@/state/appSelectors';
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 = () => {
const dispatch = useDispatch();
const stringGetter = useStringGetter();
const { governanceLearnMore, stakingLearnMore } = useURLConfigs();
const { isTablet, isNotTablet } = useBreakpoints();
const panelArrow = (
<Styled.Arrow>
<Styled.IconButton
action={ButtonAction.Base}
iconName={IconName.Arrow}
size={ButtonSize.Small}
/>
</Styled.Arrow>
);
const selectedNetwork = useSelector(getSelectedNetwork);
// const chainId = Number(ENVIRONMENT_CONFIG_MAP[selectedNetwork].ethereumChainId);
// const { balance } = useAccountBalance({
// addressOrDenom: import.meta.env.VITE_V3_TOKEN_ADDRESS,
// assetSymbol: 'DYDX',
// chainId,
// isCosmosChain: false,
// });
// const tokenBalance = import.meta.env.VITE_V3_TOKEN_ADDRESS ? balance : 0;
return (
<Styled.Page>
{import.meta.env.VITE_V3_TOKEN_ADDRESS && <MigratePanel />}
{/* {isNotTablet ? (
<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>
{isTablet && (
<Styled.BalancePanelContainer>
@@ -48,28 +138,42 @@ export const RewardsPage = () => {
<Styled.Panel
slotHeader={<Styled.Title>{stringGetter({ key: STRING_KEYS.GOVERNANCE })}</Styled.Title>}
slotRight={panelArrow}
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.GOVERNANCE_DESCRIPTION })}
<Link href={governanceLearnMore} onClick={(e) => e.stopPropagation()}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
</Styled.Description>
<Styled.Row>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.GOVERNANCE_DESCRIPTION })}
<Link href={GOVERNANCE_HELP_URL} onClick={(e) => e.stopPropagation()}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
</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
slotHeader={<Styled.Title>{stringGetter({ key: STRING_KEYS.STAKING })}</Styled.Title>}
slotRight={panelArrow}
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.STAKING_DESCRIPTION })}
<Link href={stakingLearnMore} onClick={(e) => e.stopPropagation()}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
</Styled.Description>
<Styled.Row>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.STAKING_DESCRIPTION })}
<Link href={STAKING_HELP_URL} onClick={(e) => e.stopPropagation()}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
</Styled.Description>
{/* TODO: vertically center based on Panel height */}
<Styled.IconButton
action={ButtonAction.Base}
iconName={IconName.Arrow}
size={ButtonSize.Small}
/>
</Styled.Row>
</Styled.Panel>
{isNotTablet && (
@@ -87,25 +191,61 @@ const Styled: Record<string, AnyStyledComponent> = {};
Styled.Page = styled.div`
${layoutMixins.contentContainerPage}
gap: 1.5rem;
@media ${breakpoints.tablet} {
padding: 1rem;
}
`;
Styled.Panel = styled(Panel)`
padding: 1rem 1.5rem;
padding: 0 1.5rem 1rem;
@media ${breakpoints.tablet} {
max-width: calc(100vw - 2rem);
}
`;
Styled.Title = styled.h3`
font: var(--font-medium-book);
color: var(--color-text-2);
padding: 1rem 1.5rem 0;
Styled.Row = styled.div`
${layoutMixins.spacedRow}
gap: 1rem;
align-items: center;
`;
Styled.Description = styled.div`
color: var(--color-text-0);
--link-color: var(--color-text-1);
a {
color: var(--color-text-1);
}
`;
Styled.PanelRow = styled.div`
${layoutMixins.spacedRow}
Styled.Migrate = styled.section`
max-width: min(100vw, var(--content-max-width));
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;
max-width: min(100vw, var(--content-max-width));
align-items: flex-start;
@@ -129,11 +269,65 @@ Styled.BalancePanelContainer = styled.div`
}
`;
Styled.IconButton = styled(IconButton)`
color: var(--color-text-0);
--color-border: var(--color-layer-6);
Styled.Title = styled.h3`
${layoutMixins.inlineRow}
padding: 1.25rem 1.5rem 0.5rem;
font: var(--font-medium-book);
color: var(--color-text-2);
`;
Styled.Arrow = styled.div`
padding: 1rem 1.5rem;
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)`
color: var(--color-text-0);
`;
+2 -2
View File
@@ -17,7 +17,7 @@ import { MustBigNumber } from '@/lib/numbers';
import { MidMarketPrice } from '@/views/MidMarketPrice';
export const TradeHeaderMobile = () => {
const { name, id } = useSelector(getCurrentMarketAssetData, shallowEqual) ?? {};
const { name, symbol } = useSelector(getCurrentMarketAssetData, shallowEqual) ?? {};
const navigate = useNavigate();
const { market, priceChange24H, priceChange24HPercent } =
@@ -27,7 +27,7 @@ export const TradeHeaderMobile = () => {
<Styled.Header>
<BackButton onClick={() => navigate(AppRoute.Markets)} />
<Styled.MarketName>
<Styled.AssetIcon symbol={id} />
<Styled.AssetIcon symbol={symbol} />
<Styled.Name>
<h3>{name}</h3>
<span>{market}</span>
+1 -1
View File
@@ -168,7 +168,7 @@ Styled.TriggerIcon = styled.span`
width: 0.75em;
display: inline-flex;
transition: rotate 0.3s var(--ease-out-expo);
transition: transform 0.3s var(--ease-out-expo);
${Styled.Trigger}[data-state='open'] & {
rotate: -0.5turn;
+7 -6
View File
@@ -2,7 +2,7 @@ import styled, { type AnyStyledComponent } from 'styled-components';
import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { useBreakpoints, useStringGetter, useURLConfigs } from '@/hooks';
import { useBreakpoints, useStringGetter } from '@/hooks';
import { Button } from '@/components/Button';
import { Dialog, DialogPlacement } from '@/components/Dialog';
@@ -15,10 +15,12 @@ type ElementProps = {
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) => {
const stringGetter = useStringGetter();
const { keplrDashboard, accountExportLearnMore } = useURLConfigs();
const { isTablet } = useBreakpoints();
return (
@@ -29,7 +31,7 @@ export const ExternalNavKeplrDialog = ({ setIsOpen }: ElementProps) => {
placement={isTablet ? DialogPlacement.FullScreen : DialogPlacement.Default}
>
<Styled.Content>
<Styled.Button type={ButtonType.Link} size={ButtonSize.XLarge} href={keplrDashboard}>
<Styled.Button type={ButtonType.Link} size={ButtonSize.XLarge} href={KEPLR_DASHBOARD_URL}>
<span>
{stringGetter({
key: STRING_KEYS.NAVIGATE_TO_KEPLR,
@@ -46,7 +48,7 @@ export const ExternalNavKeplrDialog = ({ setIsOpen }: ElementProps) => {
/>
</Styled.Button>
<Styled.Button type={ButtonType.Link} size={ButtonSize.XLarge} href={accountExportLearnMore}>
<Styled.Button type={ButtonType.Link} size={ButtonSize.XLarge} href={HELP_URL}>
<span>
{stringGetter({
key: STRING_KEYS.LEARN_TO_EXPORT,
@@ -102,5 +104,4 @@ Styled.Button = styled(Button)`
Styled.IconButton = styled(IconButton)`
color: var(--color-text-0);
--color-border: var(--color-layer-6);
`;
+29 -14
View File
@@ -2,10 +2,10 @@ import { useMemo } from 'react';
import styled, { AnyStyledComponent } from 'styled-components';
import { STRING_KEYS } from '@/constants/localization';
import { useStringGetter, useURLConfigs } from '@/hooks';
import { useStringGetter } from '@/hooks';
import { ChatIcon, FeedbackIcon, FileIcon, TerminalIcon } from '@/icons';
import { ComboboxDialogMenu } from '@/components/ComboboxDialogMenu';
import { Icon, IconName } from '@/components/Icon';
import { isTruthy } from '@/lib/isTruthy';
@@ -13,24 +13,39 @@ type ElementProps = {
setIsOpen: (open: boolean) => void;
};
const HELP_LINKS = {
apiDocumentation: 'https://v4-teacher.vercel.app/',
helpCenter: null,
feedback: null,
};
export const HelpDialog = ({ setIsOpen }: ElementProps) => {
const stringGetter = useStringGetter();
const { help: helpCenter, community } = useURLConfigs();
const HELP_ITEMS = useMemo(
() => [
{
group: 'help-items',
items: [
helpCenter && {
HELP_LINKS.helpCenter && {
value: 'help-center',
label: stringGetter({ key: STRING_KEYS.HELP_CENTER }),
description: stringGetter({ key: STRING_KEYS.HELP_CENTER_DESCRIPTION }),
onSelect: () => {
helpCenter && globalThis.open(helpCenter, '_blank');
HELP_LINKS.helpCenter && globalThis.open(HELP_LINKS.helpCenter, '_blank');
setIsOpen(false);
},
slotBefore: <Icon iconName={IconName.File} />,
slotBefore: <FileIcon />,
},
HELP_LINKS.apiDocumentation && {
value: 'api-documentation',
label: stringGetter({ key: STRING_KEYS.API_DOCUMENTATION }),
description: stringGetter({ key: STRING_KEYS.API_DOCUMENTATION_DESCRIPTION }),
onSelect: () => {
HELP_LINKS.apiDocumentation && globalThis.open(HELP_LINKS.apiDocumentation, '_blank');
setIsOpen(false);
},
slotBefore: <TerminalIcon />,
},
globalThis?.Intercom && {
value: 'live-chat',
@@ -40,22 +55,22 @@ export const HelpDialog = ({ setIsOpen }: ElementProps) => {
globalThis.Intercom('show');
setIsOpen(false);
},
slotBefore: <Icon iconName={IconName.Chat} />,
slotBefore: <ChatIcon />,
},
community && {
value: 'community',
label: stringGetter({ key: STRING_KEYS.COMMUNITY }),
description: stringGetter({ key: STRING_KEYS.COMMUNITY_DESCRIPTION }),
HELP_LINKS.feedback && {
value: 'feedback',
label: stringGetter({ key: STRING_KEYS.PROVIDE_FEEDBACK }),
description: stringGetter({ key: STRING_KEYS.PROVIDE_FEEDBACK_DESCRIPTION }),
onSelect: () => {
community && globalThis.open(community, '_blank');
HELP_LINKS.feedback && globalThis.open(HELP_LINKS.feedback, '_blank');
setIsOpen(false);
},
slotBefore: <Icon iconName={IconName.Discord} />,
slotBefore: <FeedbackIcon />,
},
].filter(isTruthy),
},
],
[stringGetter, helpCenter, community]
[stringGetter]
);
return (
@@ -13,15 +13,16 @@ import { Button } from '@/components/Button';
import { Icon } from '@/components/Icon';
import { Link } from '@/components/Link';
import { useAccounts, useStringGetter, useURLConfigs } from '@/hooks';
import { useAccounts, useStringGetter } from '@/hooks';
import { useDisplayedWallets } from '@/hooks/useDisplayedWallets';
import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins';
const aboutWalletsLink = `https://www.dydx.academy/video/defi-wallet`;
export const ChooseWallet = () => {
const stringGetter = useStringGetter();
const { walletLearnMore } = useURLConfigs();
const displayedWallets = useDisplayedWallets();
@@ -62,7 +63,7 @@ export const ChooseWallet = () => {
</Styled.Wallets>
<Styled.Footer>
<Link href={walletLearnMore} withIcon>
<Link href={aboutWalletsLink} withIcon>
{stringGetter({ key: STRING_KEYS.ABOUT_WALLETS })}
</Link>
</Styled.Footer>
+1 -1
View File
@@ -37,7 +37,7 @@ export const TradeDialog = ({ isOpen, setIsOpen, slotTrigger }: ElementProps) =>
const selectedTradeType = getSelectedTradeType(type);
const { typeOptions } = useSelector(getInputTradeOptions, shallowEqual) ?? {};
const allTradeTypeItems = (typeOptions?.toArray() ?? []).map(({ type, stringKey }) => ({
const allTradeTypeItems = typeOptions?.toArray()?.map(({ type, stringKey }) => ({
value: type,
label: stringGetter({
key: stringKey as StringKey,
+1
View File
@@ -322,6 +322,7 @@ export const TradeForm = ({
summary={summary ?? undefined}
currentStep={currentStep}
showDeposit={inputAlert?.errorAction === TradeInputErrorAction.DEPOSIT}
showConnectWallet={inputAlert?.errorAction === TradeInputErrorAction.CONNECT_WALLET}
/>
</Styled.Footer>
</Styled.TradeForm>
@@ -7,8 +7,9 @@ import { DialogTypes } from '@/constants/dialogs';
import { STRING_KEYS } from '@/constants/localization';
import { TRADE_TYPE_STRINGS, MobilePlaceOrderSteps } from '@/constants/trade';
import { useStringGetter, useTokenConfigs } from '@/hooks';
import { useStringGetter } from '@/hooks';
import { AssetIcon } from '@/components/AssetIcon';
import { Button } from '@/components/Button';
import { Output, OutputType, ShowSign } from '@/components/Output';
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
@@ -46,7 +47,6 @@ export const PlaceOrderButtonAndReceipt = ({
}: ElementProps) => {
const stringGetter = useStringGetter();
const dispatch = useDispatch();
const { chainTokenLabel } = useTokenConfigs();
const canAccountTrade = useSelector(calculateCanAccountTrade);
const subaccountNumber = useSelector(getSubaccountId);
@@ -88,14 +88,7 @@ export const PlaceOrderButtonAndReceipt = ({
{/* <AssetIcon symbol="DYDX" /> */}
</>
),
value: (
<Output
type={OutputType.Asset}
value={reward}
useGrouping
tag={reward ? chainTokenLabel : ''}
/>
),
value: <Output type={OutputType.Asset} value={reward} useGrouping tag={reward ? "Dv4TNT" : ''} />,
tooltip: 'max-reward',
},
{
@@ -118,7 +111,7 @@ export const PlaceOrderButtonAndReceipt = ({
? actionStringKey
: STRING_KEYS.UNAVAILABLE,
buttonAction: ButtonAction.Primary,
buttonState: { isDisabled: !shouldEnableTrade, isLoading: hasMissingData },
buttonState: { isDisabled: !shouldEnableTrade },
},
[MobilePlaceOrderSteps.PreviewOrder]: {
@@ -155,10 +148,7 @@ export const PlaceOrderButtonAndReceipt = ({
const buttonState = currentStep
? buttonStatesPerStep[currentStep].buttonState
: {
isDisabled: !shouldEnableTrade || isLoading,
isLoading: isLoading || hasMissingData,
};
: { isDisabled: !shouldEnableTrade || isLoading, isLoading };
return (
<WithDetailsReceipt detailItems={items}>
+4 -4
View File
@@ -15,7 +15,6 @@ import {
useTokenConfigs,
useStringGetter,
useAccountBalance,
useURLConfigs,
} from '@/hooks';
import { OnboardingTriggerButton } from '@/views/dialogs/OnboardingTriggerButton';
@@ -37,9 +36,10 @@ import { truncateAddress } from '@/lib/wallet';
import { layoutMixins } from '@/styles/layoutMixins';
import { headerMixins } from '@/styles/headerMixins';
const explorerBaseUri = 'https://testnet.mintscan.io/dydx-testnet';
export const AccountMenu = () => {
const stringGetter = useStringGetter();
const { mintscanBase } = useURLConfigs();
const { isTablet } = useBreakpoints();
const dispatch = useDispatch();
const onboardingState = useSelector(getOnboardingState);
@@ -92,7 +92,7 @@ export const AccountMenu = () => {
/>
<IconButton
action={ButtonAction.Base}
href={`${mintscanBase}/account/${dydxAddress}`}
href={`${explorerBaseUri}/account/${dydxAddress}`}
iconName={IconName.LinkOut}
shape={ButtonShape.Square}
type={ButtonType.Link}
@@ -167,7 +167,7 @@ export const AccountMenu = () => {
// value: 'ViewInExplorer',
// icon: <Icon iconName={IconName.Etherscan} />,
// label: stringGetter({ key: STRING_KEYS.OPEN_IN_ETHERSCAN }),
// onSelect: () => globalThis.open(`${mintscanBase}/address/${address}`),
// onSelect: () => globalThis.open(`${explorerBaseUri}/address/${address}`),
// separator: true,
// },
...(onboardingState === OnboardingState.AccountConnected && hdKey
+3 -3
View File
@@ -231,7 +231,7 @@ const getOrdersTableColumnDef = ({
key: STRING_KEYS.FILL,
})}`,
renderCell: ({
asset,
asset: { symbol: assetSymbol },
createdAtMilliseconds,
size,
status,
@@ -254,7 +254,7 @@ const getOrdersTableColumnDef = ({
value={createdAtMilliseconds}
/>
<Styled.AssetIconWithStatus>
<Styled.AssetIcon symbol={asset?.id} />
<Styled.AssetIcon symbol={assetSymbol} />
<Styled.StatusDot color={statusIconColor} />
</Styled.AssetIconWithStatus>
</>
@@ -276,7 +276,7 @@ const getOrdersTableColumnDef = ({
type={OutputType.Asset}
value={size}
fractionDigits={TOKEN_DECIMALS}
tag={asset?.id}
tag={assetSymbol}
/>
</Styled.InlineRow>
</TableCell>