Compare commits

..
Author SHA1 Message Date
jaredvu af5d11e058 Change dep in hook to fix input bug 2023-11-12 21:45:13 -08:00
145 changed files with 2472 additions and 5482 deletions
+5 -6
View File
@@ -39,12 +39,11 @@
"@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": "^1.2.5", "@dydxprotocol/v4-abacus": "^1.0.24",
"@dydxprotocol/v4-client-js": "^1.0.11", "@dydxprotocol/v4-client-js": "^1.0.0",
"@dydxprotocol/v4-localization": "^1.1.11", "@dydxprotocol/v4-localization": "^1.0.5",
"@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-accordion": "^1.1.2",
"@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-collapsible": "^1.0.3",
"@radix-ui/react-dialog": "^1.0.4", "@radix-ui/react-dialog": "^1.0.4",
@@ -111,8 +110,8 @@
"reselect": "^4.1.8", "reselect": "^4.1.8",
"styled-components": "^5.3.11", "styled-components": "^5.3.11",
"use-latest": "^1.2.1", "use-latest": "^1.2.1",
"viem": "^1.20.0", "viem": "^1.12.2",
"wagmi": "^1.4.12" "wagmi": "^1.4.5"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.22.5", "@babel/core": "^7.22.5",
+364 -1037
View File
File diff suppressed because it is too large Load Diff
-12
View File
@@ -1,12 +0,0 @@
[
{
"chainId": "1",
"tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "Ethereum"
},
{
"chainId": "5",
"tokenAddress": "0x07865c6E87B9F70255377e024ace6630C1Eaa37F",
"name": "Ethereum Goerli"
}
]
-16
View File
@@ -1,16 +0,0 @@
{
"tradingRewardsFAQs": [
{
"questionLocalizationKey": "APP.TRADING_REWARDS.FAQ_WHO_IS_ELIGIBLE_QUESTION",
"answerLocalizationKey": "APP.TRADING_REWARDS.FAQ_WHO_IS_ELIGIBLE_ANSWER"
},
{
"questionLocalizationKey": "APP.TRADING_REWARDS.FAQ_HOW_DO_TRADING_REWARDS_WORK_QUESTION",
"answerLocalizationKey": "APP.TRADING_REWARDS.FAQ_HOW_DO_TRADING_REWARDS_WORK_ANSWER"
},
{
"questionLocalizationKey": "APP.TRADING_REWARDS.FAQ_HOW_DO_I_CLAIM_MY_REWARDS_QUESTION",
"answerLocalizationKey": "APP.TRADING_REWARDS.FAQ_HOW_DO_I_CLAIM_MY_REWARDS_ANSWER"
}
]
}
+63 -80
View File
@@ -39,10 +39,10 @@
"environments": { "environments": {
"dydxprotocol-dev": { "dydxprotocol-dev": {
"name": "v4 Dev", "name": "v4 Dev",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydxprotocol-testnet", "dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -71,7 +71,6 @@
"https://validator.v4dev.dydx.exchange" "https://validator.v4dev.dydx.exchange"
], ],
"0xsquid": "https://testnet.api.0xsquid.com", "0xsquid": "https://testnet.api.0xsquid.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4dev.dydx.exchange" "faucet": "https://faucet.v4dev.dydx.exchange"
}, },
"links": { "links": {
@@ -89,7 +88,7 @@
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain", "accountExportLearnMore": "https://help.dydx.exchange",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -113,10 +112,10 @@
}, },
"dydxprotocol-dev-2": { "dydxprotocol-dev-2": {
"name": "v4 Dev 2", "name": "v4 Dev 2",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydxprotocol-testnet", "dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -144,8 +143,7 @@
"validators": [ "validators": [
"http://54.92.118.111" "http://54.92.118.111"
], ],
"0xsquid": "https://testnet.api.0xsquid.com", "0xsquid": "https://testnet.api.0xsquid.com"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
}, },
"links": { "links": {
"tos": "https://dydx.exchange/v4-terms", "tos": "https://dydx.exchange/v4-terms",
@@ -162,7 +160,7 @@
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain", "accountExportLearnMore": "https://help.dydx.exchange",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -186,10 +184,10 @@
}, },
"dydxprotocol-dev-4": { "dydxprotocol-dev-4": {
"name": "v4 Dev 4", "name": "v4 Dev 4",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydxprotocol-testnet", "dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -215,11 +213,9 @@
} }
], ],
"validators": [ "validators": [
"https://validator.v4dev4.dydx.exchange" "http://validator.v4dev4.dydx.exchange"
], ],
"0xsquid": "https://testnet.api.0xsquid.com", "0xsquid": "https://testnet.api.0xsquid.com"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4dev4.dydx.exchange"
}, },
"links": { "links": {
"tos": "https://dydx.exchange/v4-terms", "tos": "https://dydx.exchange/v4-terms",
@@ -236,7 +232,7 @@
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain", "accountExportLearnMore": "https://help.dydx.exchange",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -260,10 +256,10 @@
}, },
"dydxprotocol-dev-5": { "dydxprotocol-dev-5": {
"name": "v4 Dev 5", "name": "v4 Dev 5",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydxprotocol-testnet", "dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -291,8 +287,7 @@
"validators": [ "validators": [
"http://18.223.78.50" "http://18.223.78.50"
], ],
"0xsquid": "https://testnet.api.0xsquid.com", "0xsquid": "https://testnet.api.0xsquid.com"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
}, },
"links": { "links": {
"tos": "https://dydx.exchange/v4-terms", "tos": "https://dydx.exchange/v4-terms",
@@ -309,7 +304,7 @@
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain", "accountExportLearnMore": "https://help.dydx.exchange",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -333,10 +328,10 @@
}, },
"dydxprotocol-staging": { "dydxprotocol-staging": {
"name": "v4 Staging", "name": "v4 Staging",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydxprotocol-testnet", "dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -365,8 +360,7 @@
"validators": [ "validators": [
"https://validator.v4staging.dydx.exchange" "https://validator.v4staging.dydx.exchange"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
}, },
"links": { "links": {
"tos": "https://dydx.exchange/v4-terms", "tos": "https://dydx.exchange/v4-terms",
@@ -384,7 +378,7 @@
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain", "accountExportLearnMore": "https://help.dydx.exchange",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -408,11 +402,10 @@
}, },
"dydxprotocol-staging-forced-update": { "dydxprotocol-staging-forced-update": {
"name": "v4 Staging Forced Update", "name": "v4 Staging Forced Update",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"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": {
@@ -440,8 +433,7 @@
"validators": [ "validators": [
"https://validator.v4staging.dydx.exchange" "https://validator.v4staging.dydx.exchange"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
}, },
"links": { "links": {
"tos": "https://dydx.exchange/v4-terms", "tos": "https://dydx.exchange/v4-terms",
@@ -474,17 +466,17 @@
"apps": { "apps": {
"ios": { "ios": {
"minimalVersion": "1.0", "minimalVersion": "1.0",
"build": 40000, "build":40000,
"url": "https://apps.apple.com/app/dydx/id1564787350" "url": "https://apps.apple.com/app/dydx/id1564787350"
} }
} }
}, },
"dydxprotocol-staging-west": { "dydxprotocol-staging-west": {
"name": "v4 Staging West", "name": "v4 Staging West",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"dydxChainId": "dydxprotocol-testnet", "dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain", "chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png", "chainLogo": "dydx-chain.png",
"squidIntegratorId": "dYdX-api", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -513,8 +505,7 @@
"validators": [ "validators": [
"https://validator-uswest1.v4staging.dydx.exchange" "https://validator-uswest1.v4staging.dydx.exchange"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
}, },
"links": { "links": {
"tos": "https://dydx.exchange/v4-terms", "tos": "https://dydx.exchange/v4-terms",
@@ -532,7 +523,7 @@
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain", "accountExportLearnMore": "https://help.dydx.exchange",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -556,10 +547,10 @@
}, },
"dydxprotocol-testnet": { "dydxprotocol-testnet": {
"name": "v4 Public Testnet", "name": "v4 Public Testnet",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"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", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -580,8 +571,8 @@
"endpoints": { "endpoints": {
"indexers": [ "indexers": [
{ {
"api": "https://indexer.v4testnet.dydx.exchange", "api": "https://dydx-testnet.imperator.co",
"socket": "wss://indexer.v4testnet.dydx.exchange" "socket": "wss://dydx-testnet.imperator.co"
} }
], ],
"validators": [ "validators": [
@@ -592,7 +583,6 @@
"https://dydx-rpc.liquify.com/api=8878132/dydx" "https://dydx-rpc.liquify.com/api=8878132/dydx"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -611,7 +601,7 @@
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain", "accountExportLearnMore": "https://help.dydx.exchange",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -635,10 +625,10 @@
}, },
"dydxprotocol-testnet-dydx": { "dydxprotocol-testnet-dydx": {
"name": "v4 Public Testnet/dYdX", "name": "v4 Public Testnet/dYdX",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"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", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -667,7 +657,6 @@
"https://validator.v4testnet.dydx.exchange" "https://validator.v4testnet.dydx.exchange"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -687,7 +676,7 @@
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain", "accountExportLearnMore": "https://help.dydx.exchange",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -711,10 +700,10 @@
}, },
"dydxprotocol-testnet-nodefleet": { "dydxprotocol-testnet-nodefleet": {
"name": "v4 Public Testnet/nodefleet", "name": "v4 Public Testnet/nodefleet",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"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", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -735,15 +724,14 @@
"endpoints": { "endpoints": {
"indexers": [ "indexers": [
{ {
"api": "https://indexer.v4testnet.dydx.exchange", "api": "https://dydx-testnet.imperator.co",
"socket": "wss://indexer.v4testnet.dydx.exchange" "socket": "wss://dydx-testnet.imperator.co"
} }
], ],
"validators": [ "validators": [
"https://dydx-testnet.nodefleet.org" "https://dydx-testnet.nodefleet.org"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -763,7 +751,7 @@
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain", "accountExportLearnMore": "https://help.dydx.exchange",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -787,10 +775,10 @@
}, },
"dydxprotocol-testnet-kingnodes": { "dydxprotocol-testnet-kingnodes": {
"name": "v4 Public Testnet/KingNodes", "name": "v4 Public Testnet/KingNodes",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"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", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -811,15 +799,14 @@
"endpoints": { "endpoints": {
"indexers": [ "indexers": [
{ {
"api": "https://indexer.v4testnet.dydx.exchange", "api": "https://dydx-testnet.imperator.co",
"socket": "wss://indexer.v4testnet.dydx.exchange" "socket": "wss://dydx-testnet.imperator.co"
} }
], ],
"validators": [ "validators": [
"https://test-dydx.kingnodes.com" "https://test-dydx.kingnodes.com"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -839,7 +826,7 @@
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain", "accountExportLearnMore": "https://help.dydx.exchange",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -863,10 +850,10 @@
}, },
"dydxprotocol-testnet-liquify": { "dydxprotocol-testnet-liquify": {
"name": "v4 Public Testnet/Liquify", "name": "v4 Public Testnet/Liquify",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"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", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -887,15 +874,14 @@
"endpoints": { "endpoints": {
"indexers": [ "indexers": [
{ {
"api": "https://indexer.v4testnet.dydx.exchange", "api": "https://dydx-testnet.imperator.co",
"socket": "wss://indexer.v4testnet.dydx.exchange" "socket": "wss://dydx-testnet.imperator.co"
} }
], ],
"validators": [ "validators": [
"https://dydx-rpc.liquify.com/api=8878132/dydx" "https://dydx-rpc.liquify.com/api=8878132/dydx"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -915,7 +901,7 @@
"governanceLearnMore": "https://help.dydx.exchange", "governanceLearnMore": "https://help.dydx.exchange",
"stakingLearnMore": "https://help.dydx.exchange", "stakingLearnMore": "https://help.dydx.exchange",
"keplrDashboard": "https://testnet.keplr.app/", "keplrDashboard": "https://testnet.keplr.app/",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain", "accountExportLearnMore": "https://help.dydx.exchange",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet" "walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
}, },
"wallets": { "wallets": {
@@ -939,10 +925,10 @@
}, },
"dydxprotocol-testnet-polkachu": { "dydxprotocol-testnet-polkachu": {
"name": "v4 Public Testnet/Polkahcu", "name": "v4 Public Testnet/Polkahcu",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"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", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -963,15 +949,14 @@
"endpoints": { "endpoints": {
"indexers": [ "indexers": [
{ {
"api": "https://indexer.v4testnet.dydx.exchange", "api": "https://dydx-testnet.imperator.co",
"socket": "wss://indexer.v4testnet.dydx.exchange" "socket": "wss://dydx-testnet.imperator.co"
} }
], ],
"validators": [ "validators": [
"https://dydx-testnet-rpc.polkachu.com/" "https://dydx-testnet-rpc.polkachu.com/"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -1006,10 +991,10 @@
}, },
"dydxprotocol-testnet-bware": { "dydxprotocol-testnet-bware": {
"name": "v4 Public Testnet/BWare", "name": "v4 Public Testnet/BWare",
"ethereumChainId": "11155111", "ethereumChainId": "5",
"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", "squidIntegratorId": "dYdX-api",
"isMainNet": false, "isMainNet": false,
"tokens": { "tokens": {
@@ -1030,15 +1015,14 @@
"endpoints": { "endpoints": {
"indexers": [ "indexers": [
{ {
"api": "https://indexer.v4testnet.dydx.exchange", "api": "https://dydx-testnet.imperator.co",
"socket": "wss://indexer.v4testnet.dydx.exchange" "socket": "wss://dydx-testnet.imperator.co"
} }
], ],
"validators": [ "validators": [
"https://dydx-testnet-full-rpc.public.blastapi.io/" "https://dydx-testnet-full-rpc.public.blastapi.io/"
], ],
"0xsquid": "https://testnet.api.squidrouter.com", "0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange" "faucet": "https://faucet.v4testnet.dydx.exchange"
}, },
"links": { "links": {
@@ -1085,7 +1069,7 @@
"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]", "squidIntegratorId": "[mainnet squid integrator id]",
"isMainNet": true, "isMainNet": true,
"tokens": { "tokens": {
@@ -1115,8 +1099,7 @@
"[Validator endpoint 1", "[Validator endpoint 1",
"[Validator endpoint n]" "[Validator endpoint n]"
], ],
"0xsquid": "[0xSquid endpoint for mainnet]", "0xsquid": "[0xSquid endpoint for mainnet]"
"nobleValidator": "[noble validator endpoint for mainnet]"
}, },
"links": { "links": {
"tos": "[HTTP link to TOS]", "tos": "[HTTP link to TOS]",
@@ -1127,7 +1110,7 @@
"blogs": "[HTTP link to blogs, can be null]", "blogs": "[HTTP link to blogs, can be null]",
"foundation": "[HTTP link to foundation, can be null]", "foundation": "[HTTP link to foundation, can be null]",
"initialMarginFractionLearnMore": "[HTTP link to initial margin fraction learn more, can be null]", "initialMarginFractionLearnMore": "[HTTP link to initial margin fraction learn more, can be null]",
"reduceOnlyLearnMore": "[HTTP link to reduce-only 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]",
"help": "[HTTP link to help page, can be null]", "help": "[HTTP link to help page, can be null]",
@@ -1157,4 +1140,4 @@
} }
} }
} }
} }
+453 -359
View File
@@ -1,360 +1,454 @@
{ {
"1INCH-USD": { "1INCH-USD":{
"name": "1inch", "name":"1inch",
"tags": ["Defi"], "tags":[
"websiteLink": "https://1inch.io/", "Defi"
"whitepaperLink": "https://github.com/1inch", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/1inch/" "websiteLink":"https://1inch.io/",
}, "whitepaperLink":"https://github.com/1inch",
"AAVE-USD": { "coinMarketCapsLink":"https://coinmarketcap.com/currencies/1inch/"
"name": "Aave", },
"tags": ["Defi"], "AAVE-USD":{
"websiteLink": "https://aave.com/", "name":"Aave",
"whitepaperLink": "https://github.com/aave/protocol-v2/blob/master/aave-v2-whitepaper.pdf", "tags":[
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/aave/" "Defi"
}, ],
"ADA-USD": { "websiteLink":"https://aave.com/",
"name": "Cardano", "whitepaperLink":"https://github.com/aave/protocol-v2/blob/master/aave-v2-whitepaper.pdf",
"tags": ["Layer 1"], "coinMarketCapsLink":"https://coinmarketcap.com/currencies/aave/"
"websiteLink": "https://cardano.org/", },
"whitepaperLink": "https://why.cardano.org/en/introduction/motivation/", "ADA-USD":{
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/cardano/" "name":"Cardano",
}, "tags":[
"ALGO-USD": { "Layer 1"
"name": "Algorand", ],
"tags": ["Layer 1"], "websiteLink":"https://cardano.org/",
"websiteLink": "https://algorand.com/", "whitepaperLink":"https://why.cardano.org/en/introduction/motivation/",
"whitepaperLink": "https://algorand.com/technology/white-papers", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/cardano/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/algorand/" },
}, "ALGO-USD":{
"APE-USD": { "name":"Algorand",
"name": "ApeCoin", "tags":[
"tags": [], "Layer 1"
"websiteLink": "https://apecoin.com/", ],
"whitepaperLink": "https://apecoin.com/about", "websiteLink":"https://algorand.com/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/apecoin-ape/" "whitepaperLink":"https://algorand.com/technology/white-papers",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/algorand/"
"APT-USD": { },
"name": "Aptos", "APE-USD":{
"tags": ["Layer 1"], "name":"ApeCoin",
"websiteLink": "https://aptoslabs.com/", "tags":[
"whitepaperLink": "https://aptos.dev/aptos-white-paper/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/aptos/" ],
}, "websiteLink":"https://apecoin.com/",
"ARB-USD": { "whitepaperLink":"https://apecoin.com/about",
"name": "Arbitrum", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/apecoin-ape/"
"tags": [], },
"websiteLink": "https://arbitrum.io/", "APT-USD":{
"whitepaperLink": "https://github.com/OffchainLabs/nitro", "name":"Aptos",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/arbitrum/" "tags":[
}, "Layer 1"
"ATOM-USD": { ],
"name": "Cosmos", "websiteLink":"https://aptoslabs.com/",
"tags": ["Layer 1"], "whitepaperLink":"https://aptos.dev/aptos-white-paper/",
"websiteLink": "https://cosmos.network/", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/aptos/"
"whitepaperLink": "https://v1.cosmos.network/resources/whitepaper", },
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/cosmos/" "ARB-USD":{
}, "name":"Arbitrum",
"AVAX-USD": { "tags":[
"name": "Avalanche",
"tags": ["Layer 1"], ],
"websiteLink": "https://www.avalabs.org/", "websiteLink":"https://arbitrum.io/",
"whitepaperLink": "https://assets.website-files.com/5d80307810123f5ffbb34d6e/6008d7bbf8b10d1eb01e7e16_Avalanche%20Platform%20Whitepaper.pdf", "whitepaperLink":"https://github.com/OffchainLabs/nitro",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/avalanche/" "coinMarketCapsLink":"https://coinmarketcap.com/currencies/arbitrum/"
}, },
"BCH-USD": { "ATOM-USD":{
"name": "Bitcoin Cash", "name":"Cosmos",
"tags": ["Layer 1"], "tags":[
"websiteLink": "https://bitcoincash.org/", "Layer 1"
"whitepaperLink": "https://bitcoincash.org/", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/bitcoin-cash/" "websiteLink":"https://cosmos.network/",
}, "whitepaperLink":"https://v1.cosmos.network/resources/whitepaper",
"BLUR-USD": { "coinMarketCapsLink":"https://coinmarketcap.com/currencies/cosmos/"
"name": "Blur", },
"tags": [], "AVAX-USD":{
"websiteLink": "https://blur.io/", "name":"Avalanche",
"whitepaperLink": "https://docs.blur.foundation/", "tags":[
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/blur-token/" "Layer 1"
}, ],
"CELO-USD": { "websiteLink":"https://www.avalabs.org/",
"name": "Celo", "whitepaperLink":"https://assets.website-files.com/5d80307810123f5ffbb34d6e/6008d7bbf8b10d1eb01e7e16_Avalanche%20Platform%20Whitepaper.pdf",
"tags": [], "coinMarketCapsLink":"https://coinmarketcap.com/currencies/avalanche/"
"websiteLink": "https://celo.org", },
"whitepaperLink": "https://docs.celo.org", "BCH-USD":{
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/celo/" "name":"Bitcoin Cash",
}, "tags":[
"BTC-USD": { "Layer 1"
"name": "Bitcoin", ],
"tags": ["Layer 1"], "websiteLink":"https://bitcoincash.org/",
"websiteLink": "https://bitcoin.org/", "whitepaperLink":"https://bitcoincash.org/",
"whitepaperLink": "https://bitcoin.org/bitcoin.pdf", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/bitcoin-cash/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/bitcoin/" },
}, "BLUR-USD":{
"COMP-USD": { "name":"Blur",
"name": "Compound", "tags":[
"tags": ["Defi"],
"websiteLink": "https://compound.finance/", ],
"whitepaperLink": "https://compound.finance/documents/Compound.Whitepaper.pdf", "websiteLink":"https://blur.io/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/compound/" "whitepaperLink":"https://docs.blur.foundation/",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/blur-token/"
"CRV-USD": { },
"name": "Curve", "CELO-USD":{
"tags": ["Governance"], "name":"Celo",
"websiteLink": "https://curve.fi/", "tags":[
"whitepaperLink": "https://curve.fi/whitepaper",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/curve-dao-token/" ],
}, "websiteLink":"https://celo.org",
"DOGE-USD": { "whitepaperLink":"https://docs.celo.org",
"name": "Dogecoin", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/celo/"
"tags": ["Layer 1"], },
"websiteLink": "https://dogecoin.com/", "BTC-USD":{
"whitepaperLink": "https://github.com/dogecoin/dogecoin", "name":"Bitcoin",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/dogecoin/" "tags":[
}, "Layer 1"
"DOT-USD": { ],
"name": "Polkadot", "websiteLink":"https://bitcoin.org/",
"tags": ["Layer 1"], "whitepaperLink":"https://bitcoin.org/bitcoin.pdf",
"websiteLink": "https://polkadot.network/", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/bitcoin/"
"whitepaperLink": "https://polkadot.network/PolkaDotPaper.pdf", },
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/polkadot-new/" "COMP-USD":{
}, "name":"Compound",
"ENJ-USD": { "tags":[
"name": "Enjin", "Defi"
"tags": [], ],
"websiteLink": "https://enjin.io/", "websiteLink":"https://compound.finance/",
"whitepaperLink": "https://cdn.enjin.io/downloads/whitepapers/enjin-coin/en.pdf/", "whitepaperLink":"https://compound.finance/documents/Compound.Whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/enjin-coin/" "coinMarketCapsLink":"https://coinmarketcap.com/currencies/compound/"
}, },
"EOS-USD": { "CRV-USD":{
"name": "EOS", "name":"Curve",
"tags": ["Layer 1"], "tags":[
"websiteLink": "https://eos.io/", "Governance"
"whitepaperLink": "https://github.com/EOSIO/Documentation/blob/master/TechnicalWhitePaper.md", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/eos/" "websiteLink":"https://curve.fi/",
}, "whitepaperLink":"https://curve.fi/whitepaper",
"ETC-USD": { "coinMarketCapsLink":"https://coinmarketcap.com/currencies/curve-dao-token/"
"name": "Ethereum Classic", },
"tags": ["Layer 1"], "DOGE-USD":{
"websiteLink": "https://ethereumclassic.org/", "name":"Dogecoin",
"whitepaperLink": "https://ethereumclassic.org/why-classic", "tags":[
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/ethereum-classic/" "Layer 1"
}, ],
"ETH-USD": { "websiteLink":"https://dogecoin.com/",
"name": "Ethereum", "whitepaperLink":"https://github.com/dogecoin/dogecoin",
"tags": ["Layer 1"], "coinMarketCapsLink":"https://coinmarketcap.com/currencies/dogecoin/"
"websiteLink": "https://ethereum.org/", },
"whitepaperLink": "https://ethereum.org/whitepaper/", "DOT-USD":{
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/ethereum/", "name":"Polkadot",
"displayStepSize": "0.001", "tags":[
"displayTickSize": "0.1" "Layer 1"
}, ],
"FIL-USD": { "websiteLink":"https://polkadot.network/",
"name": "Filecoin", "whitepaperLink":"https://polkadot.network/PolkaDotPaper.pdf",
"tags": ["Layer 1"], "coinMarketCapsLink":"https://coinmarketcap.com/currencies/polkadot-new/"
"websiteLink": "https://filecoin.io/", },
"whitepaperLink": "https://filecoin.io/filecoin.pdf", "ENJ-USD":{
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/filecoin/" "name":"Enjin",
}, "tags":[
"HNT-USD": {
"name": "Helium", ],
"tags": ["Layer 1"], "websiteLink":"https://enjin.io/",
"websiteLink": "https://www.helium.com", "whitepaperLink":"https://cdn.enjin.io/downloads/whitepapers/enjin-coin/en.pdf/",
"whitepaperLink": "http://whitepaper.helium.com", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/enjin-coin/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/helium/" },
}, "EOS-USD":{
"ICP-USD": { "name":"EOS",
"name": "Internet Computer", "tags":[
"tags": ["Layer 1"], "Layer 1"
"websiteLink": "https://dfinity.org", ],
"whitepaperLink": "https://dfinity.org/whitepaper.pdf", "websiteLink":"https://eos.io/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/internet-computer/" "whitepaperLink":"https://github.com/EOSIO/Documentation/blob/master/TechnicalWhitePaper.md",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/eos/"
"LDO-USD": { },
"name": "Lido DAO", "ETC-USD":{
"tags": ["Defi"], "name":"Ethereum Classic",
"websiteLink": "https://lido.fi/", "tags":[
"whitepaperLink": "https://lido.fi/static/Lido:Ethereum-Liquid-Staking.pdf", "Layer 1"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/lido-dao/" ],
}, "websiteLink":"https://ethereumclassic.org/",
"LINK-USD": { "whitepaperLink":"https://ethereumclassic.org/why-classic",
"name": "Chainlink", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/ethereum-classic/"
"tags": ["Defi"], },
"websiteLink": "https://chain.link/", "ETH-USD":{
"whitepaperLink": "https://link.smartcontract.com/whitepaper", "name":"Ethereum",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/chainlink/" "tags":[
}, "Layer 1"
"LTC-USD": { ],
"name": "Litecoin", "websiteLink":"https://ethereum.org/",
"tags": ["Layer 1"], "whitepaperLink":"https://ethereum.org/whitepaper/",
"websiteLink": "https://litecoin.org/", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/ethereum/",
"whitepaperLink": "https://litecoin.info/index.php/Main_Page", "displayStepSize":"0.001",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/litecoin/" "displayTickSize":"0.1"
}, },
"MATIC-USD": { "FIL-USD":{
"name": "Polygon", "name":"Filecoin",
"tags": ["Layer 2"], "tags":[
"websiteLink": "https://polygon.technology/", "Layer 1"
"whitepaperLink": "https://polygon.technology/lightpaper-polygon.pdf", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/polygon/" "websiteLink":"https://filecoin.io/",
}, "whitepaperLink":"https://filecoin.io/filecoin.pdf",
"MKR-USD": { "coinMarketCapsLink":"https://coinmarketcap.com/currencies/filecoin/"
"name": "Maker", },
"tags": ["Governance"], "HNT-USD":{
"websiteLink": "https://makerdao.com", "name":"Helium",
"whitepaperLink": "https://makerdao.com/whitepaper", "tags":[
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/maker/" "Layer 1"
}, ],
"NEAR-USD": { "websiteLink":"https://www.helium.com",
"name": "NEAR Protocol", "whitepaperLink":"http://whitepaper.helium.com",
"tags": ["Layer 1"], "coinMarketCapsLink":"https://coinmarketcap.com/currencies/helium/"
"websiteLink": "https://near.org", },
"whitepaperLink": "https://near.org/papers/the-official-near-white-paper/", "ICP-USD":{
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/near-protocol/" "name":"Internet Computer",
}, "tags":[
"OP-USD": { "Layer 1"
"name": "Optimism", ],
"tags": [], "websiteLink":"https://dfinity.org",
"websiteLink": "https://www.optimism.io/", "whitepaperLink":"https://dfinity.org/whitepaper.pdf",
"whitepaperLink": "https://github.com/ethereum-optimism", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/internet-computer/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/optimism-ethereum/" },
}, "LDO-USD":{
"PEPE-USD": { "name":"Lido DAO",
"name": "Pepe", "tags":[
"tags": [], "Defi"
"websiteLink": "https://www.pepe.vip/", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/pepe/" "websiteLink":"https://lido.fi/",
}, "whitepaperLink":"https://lido.fi/static/Lido:Ethereum-Liquid-Staking.pdf",
"RUNE-USD": { "coinMarketCapsLink":"https://coinmarketcap.com/currencies/lido-dao/"
"name": "THORChain", },
"tags": ["Layer 1"], "LINK-USD":{
"websiteLink": "https://thorchain.org", "name":"Chainlink",
"whitepaperLink": "https://whitepaper.io/document/709/thorchain-whitepaper", "tags":[
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/thorchain/" "Defi"
}, ],
"SEI-USD": { "websiteLink":"https://chain.link/",
"name": "Sei", "whitepaperLink":"https://link.smartcontract.com/whitepaper",
"tags": ["Layer 1", "Defi"], "coinMarketCapsLink":"https://coinmarketcap.com/currencies/chainlink/"
"websiteLink": "https://www.sei.io/", },
"whitepaperLink": "https://github.com/sei-protocol/sei-chain/blob/3c9576fee3494ce039df684624f918dd8066ba3f/whitepaper/Sei_Whitepaper.pdf", "LTC-USD":{
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/sei/" "name":"Litecoin",
}, "tags":[
"SHIB-USD": { "Layer 1"
"name": "Shiba Inu", ],
"tags": [], "websiteLink":"https://litecoin.org/",
"websiteLink": "https://shibatoken.com/", "whitepaperLink":"https://litecoin.info/index.php/Main_Page",
"whitepaperLink": "https://docs.shibatoken.com/", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/litecoin/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/shiba-inu/" },
}, "MATIC-USD":{
"SNX-USD": { "name":"Polygon",
"name": "Synthetix", "tags":[
"tags": ["Defi"], "Layer 2"
"websiteLink": "https://synthetix.io/", ],
"whitepaperLink": "https://docs.synthetix.io/litepaper", "websiteLink":"https://polygon.technology/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/synthetix-network-token/" "whitepaperLink":"https://polygon.technology/lightpaper-polygon.pdf",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/polygon/"
"SOL-USD": { },
"name": "Solana", "MKR-USD":{
"tags": ["Layer 1"], "name":"Maker",
"websiteLink": "https://solana.com/", "tags":[
"whitepaperLink": "https://solana.com/solana-whitepaper.pdf", "Governance"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/solana/" ],
}, "websiteLink":"https://makerdao.com",
"SUI-USD": { "whitepaperLink":"https://makerdao.com/whitepaper",
"name": "Sui", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/maker/"
"tags": ["Layer 1"], },
"websiteLink": "https://sui.io/", "NEAR-USD":{
"whitepaperLink": "https://github.com/MystenLabs", "name":"NEAR Protocol",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/sui/" "tags":[
}, "Layer 1"
"SUSHI-USD": { ],
"name": "Sushi", "websiteLink":"https://near.org",
"tags": ["Defi"], "whitepaperLink":"https://near.org/papers/the-official-near-white-paper/",
"websiteLink": "https://sushi.com/", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/near-protocol/"
"whitepaperLink": "https://docs.sushi.com/", },
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/sushiswap/" "OP-USD":{
}, "name":"Optimism",
"TIA-USD": { "tags":[
"name": "Celestia",
"tags": ["Layer 1"], ],
"websiteLink": "https://celestia.org/", "websiteLink":"https://www.optimism.io/",
"whitepaperLink": "https://arxiv.org/pdf/1905.09274.pdf", "whitepaperLink":"https://github.com/ethereum-optimism",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/celestia/" "coinMarketCapsLink":"https://coinmarketcap.com/currencies/optimism-ethereum/"
}, },
"TRX-USD": { "PEPE-USD":{
"name": "TRON", "name":"Pepe",
"tags": ["Defi"], "tags":[
"websiteLink": "https://tron.network/",
"whitepaperLink": "https://tron.network/static/doc/white_paper_v_2_0.pdf", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/tron/" "websiteLink":"https://www.pepe.vip/",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/pepe/"
"UMA-USD": { },
"name": "UMA", "RUNE-USD":{
"tags": ["Defi"], "name":"THORChain",
"websiteLink": "https://umaproject.org/", "tags":[
"whitepaperLink": "https://github.com/UMAprotocol/whitepaper", "Layer 1"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/uma/" ],
}, "websiteLink":"https://thorchain.org",
"UNI-USD": { "whitepaperLink":"https://whitepaper.io/document/709/thorchain-whitepaper",
"name": "Uniswap", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/thorchain/"
"tags": ["Defi"], },
"websiteLink": "https://uniswap.org/", "SEI-USD":{
"whitepaperLink": "https://uniswap.org/whitepaper-v3.pdf", "name":"Sei",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/uniswap/" "tags":[
}, "Layer 1",
"WLD-USD": { "Defi"
"name": "Worldcoin", ],
"tags": [], "websiteLink":"https://www.sei.io/",
"websiteLink": "https://worldcoin.org/", "whitepaperLink":"https://github.com/sei-protocol/sei-chain/blob/3c9576fee3494ce039df684624f918dd8066ba3f/whitepaper/Sei_Whitepaper.pdf",
"whitepaperLink": "https://whitepaper.worldcoin.org/", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/sei/"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/worldcoin-org/" },
}, "SHIB-USD":{
"XLM-USD": { "name":"Shiba Inu",
"name": "Stellar", "tags":[
"tags": ["Layer 1"],
"websiteLink": "https://www.stellar.org/", ],
"whitepaperLink": "https://www.stellar.org/papers/stellar-consensus-protocol", "websiteLink":"https://shibatoken.com/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/stellar/" "whitepaperLink":"https://docs.shibatoken.com/",
}, "coinMarketCapsLink":"https://coinmarketcap.com/currencies/shiba-inu/"
"XMR-USD": { },
"name": "Monero", "SNX-USD":{
"tags": ["Layer 1"], "name":"Synthetix",
"websiteLink": "https://www.getmonero.org/", "tags":[
"whitepaperLink": "https://www.getmonero.org/resources/research-lab/", "Defi"
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/monero/" ],
}, "websiteLink":"https://synthetix.io/",
"XRP-USD": { "whitepaperLink":"https://docs.synthetix.io/litepaper",
"name": "Ripple", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/synthetix-network-token/"
"tags": ["Layer 1"], },
"websiteLink": "https://ripple.com/currency/", "SOL-USD":{
"whitepaperLink": "https://github.com/ripple", "name":"Solana",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/xrp/" "tags":[
}, "Layer 1"
"XTZ-USD": { ],
"name": "Tezos", "websiteLink":"https://solana.com/",
"tags": ["Layer 1"], "whitepaperLink":"https://solana.com/solana-whitepaper.pdf",
"websiteLink": "https://tezos.com", "coinMarketCapsLink":"https://coinmarketcap.com/currencies/solana/"
"whitepaperLink": "https://tezos.com/whitepaper.pdf", },
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/tezos/" "SUI-USD":{
}, "name":"Sui",
"YFI-USD": { "tags":[
"name": "Yearn", "Layer 1"
"tags": ["Defi"], ],
"websiteLink": "https://yearn.finance/", "websiteLink":"https://sui.io/",
"whitepaperLink": "https://docs.yearn.finance/", "whitepaperLink":"https://github.com/MystenLabs",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/yearn-finance/" "coinMarketCapsLink":"https://coinmarketcap.com/currencies/sui/"
}, },
"ZEC-USD": { "SUSHI-USD":{
"name": "Zcash", "name":"Sushi",
"tags": ["Layer 1"], "tags":[
"websiteLink": "https://z.cash/", "Defi"
"whitepaperLink": "https://z.cash/technology/", ],
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/zcash/" "websiteLink":"https://sushi.com/",
}, "whitepaperLink":"https://docs.sushi.com/",
"ZRX-USD": { "coinMarketCapsLink":"https://coinmarketcap.com/currencies/sushiswap/"
"name": "0x", },
"tags": ["Defi"], "TRX-USD":{
"websiteLink": "https://0x.org/", "name":"TRON",
"whitepaperLink": "https://0x.org/pdfs/0x_white_paper.pdf", "tags":[
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/0x/" "Defi"
} ],
} "websiteLink":"https://tron.network/",
"whitepaperLink":"https://tron.network/static/doc/white_paper_v_2_0.pdf",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/tron/"
},
"UMA-USD":{
"name":"UMA",
"tags":[
"Defi"
],
"websiteLink":"https://umaproject.org/",
"whitepaperLink":"https://github.com/UMAprotocol/whitepaper",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/uma/"
},
"UNI-USD":{
"name":"Uniswap",
"tags":[
"Defi"
],
"websiteLink":"https://uniswap.org/",
"whitepaperLink":"https://uniswap.org/whitepaper-v3.pdf",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/uniswap/"
},
"WLD-USD":{
"name":"Worldcoin",
"tags":[
],
"websiteLink":"https://worldcoin.org/",
"whitepaperLink":"https://whitepaper.worldcoin.org/",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/worldcoin-org/"
},
"XLM-USD":{
"name":"Stellar",
"tags":[
"Layer 1"
],
"websiteLink":"https://www.stellar.org/",
"whitepaperLink":"https://www.stellar.org/papers/stellar-consensus-protocol",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/stellar/"
},
"XMR-USD":{
"name":"Monero",
"tags":[
"Layer 1"
],
"websiteLink":"https://www.getmonero.org/",
"whitepaperLink":"https://www.getmonero.org/resources/research-lab/",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/monero/"
},
"XRP-USD":{
"name":"Ripple",
"tags":[
"Layer 1"
],
"websiteLink":"https://ripple.com/currency/",
"whitepaperLink":"https://github.com/ripple",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/xrp/"
},
"XTZ-USD":{
"name":"Tezos",
"tags":[
"Layer 1"
],
"websiteLink":"https://tezos.com",
"whitepaperLink":"https://tezos.com/whitepaper.pdf",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/tezos/"
},
"YFI-USD":{
"name":"Yearn",
"tags":[
"Defi"
],
"websiteLink":"https://yearn.finance/",
"whitepaperLink":"https://docs.yearn.finance/",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/yearn-finance/"
},
"ZEC-USD":{
"name":"Zcash",
"tags":[
"Layer 1"
],
"websiteLink":"https://z.cash/",
"whitepaperLink":"https://z.cash/technology/",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/zcash/"
},
"ZRX-USD":{
"name":"0x",
"tags":[
"Defi"
],
"websiteLink":"https://0x.org/",
"whitepaperLink":"https://0x.org/pdfs/0x_white_paper.pdf",
"coinMarketCapsLink":"https://coinmarketcap.com/currencies/0x/"
}
}
+1 -1
View File
@@ -199,7 +199,7 @@
}, },
"mobile": { "mobile": {
"native": "trust:", "native": "trust:",
"universal": "" "universal": "https://link.trustwallet.com"
}, },
"desktop": { "desktop": {
"native": "", "native": "",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

-230
View File
@@ -1,230 +0,0 @@
<svg width="254" height="77" viewBox="0 0 254 77" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 1258">
<g id="Ellipse 9" opacity="0.4" filter="url(#filter0_f_20300_14972)">
<ellipse cx="86.5425" cy="-3.91219" rx="116.542" ry="20.0878" fill="#7774FF"/>
</g>
<g id="Ellipse 10" opacity="0.3" filter="url(#filter1_f_20300_14972)">
<circle cx="74.5734" cy="4.63007" r="1.00507" fill="#9A9AFF"/>
</g>
<g id="Ellipse 12" opacity="0.3" filter="url(#filter2_f_20300_14972)">
<circle cx="82.1105" cy="7.64179" r="1.00507" fill="#9A9AFF"/>
</g>
<g id="Ellipse 22" opacity="0.3" filter="url(#filter3_f_20300_14972)">
<circle cx="116.785" cy="4.63007" r="1.00507" fill="#9A9AFF"/>
</g>
<g id="Ellipse 11" opacity="0.3" filter="url(#filter4_f_20300_14972)">
<circle cx="64.774" cy="8.90488" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 18" opacity="0.3" filter="url(#filter5_f_20300_14972)">
<circle cx="96.4322" cy="3.87363" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 20" opacity="0.3" filter="url(#filter6_f_20300_14972)">
<circle cx="76.0807" cy="14.9361" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 21" opacity="0.3" filter="url(#filter7_f_20300_14972)">
<circle cx="104.725" cy="4.87754" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 23" opacity="0.3" filter="url(#filter8_f_20300_14972)">
<circle cx="114.021" cy="7.13925" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 24" opacity="0.3" filter="url(#filter9_f_20300_14972)">
<circle cx="109.75" cy="15.4361" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 25" opacity="0.3" filter="url(#filter10_f_20300_14972)">
<circle cx="119.801" cy="12.6705" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 27" opacity="0.3" filter="url(#filter11_f_20300_14972)">
<circle cx="94.0885" cy="11.0182" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 30" opacity="0.3" filter="url(#filter12_f_20300_14972)">
<circle cx="154.475" cy="11.6666" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 29" opacity="0.3" filter="url(#filter13_f_20300_14972)">
<circle cx="146.435" cy="8.90488" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 15" opacity="0.3" filter="url(#filter14_f_20300_14972)">
<circle cx="24.0103" cy="4.44785" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 33" opacity="0.3" filter="url(#filter15_f_20300_14972)">
<circle cx="-1.05899" cy="13.6783" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 16" opacity="0.3" filter="url(#filter16_f_20300_14972)">
<circle cx="17.441" cy="16.4908" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 35" opacity="0.3" filter="url(#filter17_f_20300_14972)">
<circle cx="36.0553" cy="6.63535" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 32" opacity="0.3" filter="url(#filter18_f_20300_14972)">
<circle cx="10.8707" cy="14.2994" r="0.502536" fill="#9A9AFF"/>
</g>
<g id="Ellipse 13" opacity="0.3" filter="url(#filter19_f_20300_14972)">
<circle cx="55.7274" cy="9.65615" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 19" opacity="0.3" filter="url(#filter20_f_20300_14972)">
<circle cx="87.3886" cy="20.7108" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 26" opacity="0.3" filter="url(#filter21_f_20300_14972)">
<circle cx="123.82" cy="15.1874" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 36" opacity="0.3" filter="url(#filter22_f_20300_14972)">
<circle cx="134.876" cy="14.4335" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 28" opacity="0.3" filter="url(#filter23_f_20300_14972)">
<circle cx="129.6" cy="6.38662" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 14" opacity="0.3" filter="url(#filter24_f_20300_14972)">
<circle cx="41.6571" cy="14.9335" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 31" opacity="0.3" filter="url(#filter25_f_20300_14972)">
<circle cx="4.21767" cy="17.9491" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 34" opacity="0.3" filter="url(#filter26_f_20300_14972)">
<circle cx="12.2177" cy="6.88662" r="0.753803" fill="#9A9AFF"/>
</g>
<g id="Ellipse 17" opacity="0.3" filter="url(#filter27_f_20300_14972)">
<circle cx="50.2001" cy="3.6249" r="0.753803" fill="#9A9AFF"/>
</g>
</g>
<defs>
<filter id="filter0_f_20300_14972" x="-94" y="-88" width="361.085" height="168.176" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="32" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter1_f_20300_14972" x="72.5633" y="2.61993" width="4.01991" height="4.02186" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter2_f_20300_14972" x="80.6029" y="6.13418" width="3.01484" height="3.01679" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.251268" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter3_f_20300_14972" x="115.278" y="3.12246" width="3.01484" height="3.01679" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.251268" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter4_f_20300_14972" x="63.2664" y="7.39727" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter5_f_20300_14972" x="94.9246" y="2.36602" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter6_f_20300_14972" x="74.5731" y="13.4285" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter7_f_20300_14972" x="103.218" y="3.36993" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter8_f_20300_14972" x="112.513" y="5.63165" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter9_f_20300_14972" x="108.242" y="13.9285" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter10_f_20300_14972" x="118.294" y="11.1629" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter11_f_20300_14972" x="92.5809" y="9.51055" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter12_f_20300_14972" x="153.47" y="10.6615" width="2.00995" height="2.00898" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.251268" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter13_f_20300_14972" x="144.928" y="7.39727" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter14_f_20300_14972" x="22.5027" y="2.94024" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter15_f_20300_14972" x="-2.56659" y="12.1707" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter16_f_20300_14972" x="15.9334" y="14.9832" width="3.01502" height="3.01405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter17_f_20300_14972" x="35.0502" y="5.63028" width="2.00995" height="2.00898" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.251268" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter18_f_20300_14972" x="9.86563" y="13.2943" width="2.00995" height="2.00898" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.251268" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter19_f_20300_14972" x="53.9686" y="7.89727" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter20_f_20300_14972" x="85.6297" y="18.952" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter21_f_20300_14972" x="122.061" y="13.4285" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter22_f_20300_14972" x="133.117" y="12.6746" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter23_f_20300_14972" x="127.842" y="4.62774" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter24_f_20300_14972" x="39.8982" y="13.1746" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter25_f_20300_14972" x="2.4588" y="16.1902" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter26_f_20300_14972" x="10.4588" y="5.12774" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
<filter id="filter27_f_20300_14972" x="48.4412" y="1.86602" width="3.51795" height="3.51795" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.502536" result="effect1_foregroundBlur_20300_14972"/>
</filter>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 300 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.6 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 481 KiB

+16 -13
View File
@@ -1,4 +1,4 @@
import { lazy, Suspense } from 'react'; import { Suspense } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom'; import { Navigate, Route, Routes } from 'react-router-dom';
import styled, { AnyStyledComponent, css } from 'styled-components'; import styled, { AnyStyledComponent, css } from 'styled-components';
import { WagmiConfig } from 'wagmi'; import { WagmiConfig } from 'wagmi';
@@ -22,9 +22,21 @@ import { NotificationsProvider } from '@/hooks/useNotifications';
import { LocalNotificationsProvider } from '@/hooks/useLocalNotifications'; import { LocalNotificationsProvider } from '@/hooks/useLocalNotifications';
import { RestrictionProvider } from '@/hooks/useRestrictions'; import { RestrictionProvider } from '@/hooks/useRestrictions';
import { SubaccountProvider } from '@/hooks/useSubaccount'; import { SubaccountProvider } from '@/hooks/useSubaccount';
import { SquidProvider } from '@/hooks/useSquid';
import { TestFlagsProvider } from '@/hooks/useTestFlags';
import { GuardedMobileRoute } from '@/components/GuardedMobileRoute'; import { GuardedMobileRoute } from '@/components/GuardedMobileRoute';
import MarketsPage from '@/pages/markets/Markets';
import PortfolioPage from '@/pages/portfolio/Portfolio';
import { AlertsPage } from '@/pages/AlertsPage';
import ProfilePage from '@/pages/Profile';
import { SettingsPage } from '@/pages/settings/Settings';
import TradePage from '@/pages/trade/Trade';
import { RewardsPage } from '@/pages/rewards/RewardsPage';
import { TermsOfUsePage } from '@/pages/TermsOfUsePage';
import { PrivacyPolicyPage } from '@/pages/PrivacyPolicyPage';
import { HeaderDesktop } from '@/layout/Header/HeaderDesktop'; import { HeaderDesktop } from '@/layout/Header/HeaderDesktop';
import { FooterDesktop } from '@/layout/Footer/FooterDesktop'; import { FooterDesktop } from '@/layout/Footer/FooterDesktop';
import { FooterMobile } from '@/layout/Footer/FooterMobile'; import { FooterMobile } from '@/layout/Footer/FooterMobile';
@@ -36,22 +48,11 @@ import { config } from '@/lib/wagmi';
import { breakpoints } from '@/styles'; import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { LoadingSpace } from './components/Loading/LoadingSpinner';
import '@/styles/constants.css'; import '@/styles/constants.css';
import '@/styles/fonts.css'; import '@/styles/fonts.css';
import '@/styles/web3modal.css'; import '@/styles/web3modal.css';
const MarketsPage = lazy(() => import('@/pages/markets/Markets'));
const PortfolioPage = lazy(() => import('@/pages/portfolio/Portfolio'));
const AlertsPage = lazy(() => import('@/pages/AlertsPage'));
const ProfilePage = lazy(() => import('@/pages/Profile'));
const SettingsPage = lazy(() => import('@/pages/settings/Settings'));
const TradePage = lazy(() => import('@/pages/trade/Trade'));
const RewardsPage = lazy(() => import('@/pages/rewards/RewardsPage'));
const TermsOfUsePage = lazy(() => import('@/pages/TermsOfUsePage'));
const PrivacyPolicyPage = lazy(() => import('@/pages/PrivacyPolicyPage'));
const queryClient = new QueryClient(); const queryClient = new QueryClient();
const Content = () => { const Content = () => {
@@ -70,7 +71,7 @@ const Content = () => {
{isNotTablet && <HeaderDesktop />} {isNotTablet && <HeaderDesktop />}
<Styled.Main> <Styled.Main>
<Suspense fallback={<LoadingSpace id="main" />}> <Suspense fallback={null}>
<Routes> <Routes>
<Route path={AppRoute.Trade}> <Route path={AppRoute.Trade}>
<Route path=":market" element={<TradePage />} /> <Route path=":market" element={<TradePage />} />
@@ -123,11 +124,13 @@ const providers = [
wrapProvider(QueryClientProvider, { client: queryClient }), wrapProvider(QueryClientProvider, { client: queryClient }),
wrapProvider(GrazProvider), wrapProvider(GrazProvider),
wrapProvider(WagmiConfig, { config }), wrapProvider(WagmiConfig, { config }),
wrapProvider(TestFlagsProvider),
wrapProvider(LocaleProvider), wrapProvider(LocaleProvider),
wrapProvider(RestrictionProvider), wrapProvider(RestrictionProvider),
wrapProvider(DydxProvider), wrapProvider(DydxProvider),
wrapProvider(AccountsProvider), wrapProvider(AccountsProvider),
wrapProvider(SubaccountProvider), wrapProvider(SubaccountProvider),
wrapProvider(SquidProvider),
wrapProvider(LocalNotificationsProvider), wrapProvider(LocalNotificationsProvider),
wrapProvider(NotificationsProvider), wrapProvider(NotificationsProvider),
wrapProvider(DialogAreaProvider), wrapProvider(DialogAreaProvider),
-390
View File
@@ -1,390 +0,0 @@
[
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [{ "name": "", "type": "string" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_upgradedAddress", "type": "address" }],
"name": "deprecate",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "name": "_spender", "type": "address" },
{ "name": "_value", "type": "uint256" }
],
"name": "approve",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "deprecated",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_evilUser", "type": "address" }],
"name": "addBlackList",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "name": "_from", "type": "address" },
{ "name": "_to", "type": "address" },
{ "name": "_value", "type": "uint256" }
],
"name": "transferFrom",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "upgradedAddress",
"outputs": [{ "name": "", "type": "address" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "", "type": "address" }],
"name": "balances",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "maximumFee",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "_totalSupply",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "unpause",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "_maker", "type": "address" }],
"name": "getBlackListStatus",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{ "name": "", "type": "address" },
{ "name": "", "type": "address" }
],
"name": "allowed",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "paused",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "who", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "pause",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getOwner",
"outputs": [{ "name": "", "type": "address" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "owner",
"outputs": [{ "name": "", "type": "address" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [{ "name": "", "type": "string" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "name": "_to", "type": "address" },
{ "name": "_value", "type": "uint256" }
],
"name": "transfer",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "name": "newBasisPoints", "type": "uint256" },
{ "name": "newMaxFee", "type": "uint256" }
],
"name": "setParams",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "amount", "type": "uint256" }],
"name": "issue",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "amount", "type": "uint256" }],
"name": "redeem",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{ "name": "_owner", "type": "address" },
{ "name": "_spender", "type": "address" }
],
"name": "allowance",
"outputs": [{ "name": "remaining", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "basisPointsRate",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "", "type": "address" }],
"name": "isBlackListed",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_clearedUser", "type": "address" }],
"name": "removeBlackList",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "MAX_UINT",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "newOwner", "type": "address" }],
"name": "transferOwnership",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_blackListedUser", "type": "address" }],
"name": "destroyBlackFunds",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "name": "_initialSupply", "type": "uint256" },
{ "name": "_name", "type": "string" },
{ "name": "_symbol", "type": "string" },
{ "name": "_decimals", "type": "uint256" }
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [{ "indexed": false, "name": "amount", "type": "uint256" }],
"name": "Issue",
"type": "event"
},
{
"anonymous": false,
"inputs": [{ "indexed": false, "name": "amount", "type": "uint256" }],
"name": "Redeem",
"type": "event"
},
{
"anonymous": false,
"inputs": [{ "indexed": false, "name": "newAddress", "type": "address" }],
"name": "Deprecate",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": false, "name": "feeBasisPoints", "type": "uint256" },
{ "indexed": false, "name": "maxFee", "type": "uint256" }
],
"name": "Params",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": false, "name": "_blackListedUser", "type": "address" },
{ "indexed": false, "name": "_balance", "type": "uint256" }
],
"name": "DestroyedBlackFunds",
"type": "event"
},
{
"anonymous": false,
"inputs": [{ "indexed": false, "name": "_user", "type": "address" }],
"name": "AddedBlackList",
"type": "event"
},
{
"anonymous": false,
"inputs": [{ "indexed": false, "name": "_user", "type": "address" }],
"name": "RemovedBlackList",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "owner", "type": "address" },
{ "indexed": true, "name": "spender", "type": "address" },
{ "indexed": false, "name": "value", "type": "uint256" }
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "from", "type": "address" },
{ "indexed": true, "name": "to", "type": "address" },
{ "indexed": false, "name": "value", "type": "uint256" }
],
"name": "Transfer",
"type": "event"
},
{ "anonymous": false, "inputs": [], "name": "Pause", "type": "event" },
{ "anonymous": false, "inputs": [], "name": "Unpause", "type": "event" }
]
-26
View File
@@ -1,26 +0,0 @@
import type { Story } from '@ladle/react';
import { Accordion as AccordionComponent, AccordionProps } from '@/components/Accordion';
import { StoryWrapper } from '.ladle/components';
export const Accordion: Story<AccordionProps> = (args) => {
return (
<StoryWrapper>
<AccordionComponent {...args} />
</StoryWrapper>
);
};
Accordion.args = {
items: [
{
header: 'Question 1?',
content: 'Answer 1.',
},
{
header: 'Question 2?',
content: 'Answer 2.',
},
],
};
-129
View File
@@ -1,129 +0,0 @@
import styled, { keyframes, type AnyStyledComponent } from 'styled-components';
import { Root, Item, Header, Trigger, Content } from '@radix-ui/react-accordion';
import { layoutMixins } from '@/styles/layoutMixins';
import { breakpoints } from '@/styles';
import { PlusIcon } from '@/icons';
export type AccordionItem = {
header: React.ReactNode;
content: React.ReactNode;
};
export type AccordionProps = {
items: AccordionItem[];
className?: string;
};
export const Accordion = ({ items, className }: AccordionProps) => (
<Styled.Root className={className} type="single" collapsible>
{items.map(({ header, content }, idx) => (
<Styled.Item key={idx} value={idx.toString()}>
<Header>
<Styled.Trigger>
{header}
<Styled.Icon>
<PlusIcon />
</Styled.Icon>
</Styled.Trigger>
</Header>
<Styled.Content>{content}</Styled.Content>
</Styled.Item>
))}
</Styled.Root>
);
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Root = styled(Root)`
--accordion-paddingY: 1rem;
--accordion-paddingX: 1rem;
@media ${breakpoints.notTablet} {
--accordion-paddingX: 1.5rem;
}
> *:not(:last-child) {
border-bottom: var(--border-width) solid var(--border-color);
}
`;
Styled.Item = styled(Item)``;
Styled.Icon = styled.div`
display: inline-flex;
justify-content: center;
align-items: center;
width: 2.25rem;
height: 2.25rem;
--color-border: var(--color-layer-6);
color: var(--color-text-1);
background-color: var(--color-layer-5);
border: solid var(--border-width) var(--color-border);
border-radius: 50%;
font: var(--font-small-book);
svg {
height: 1.125em;
width: 1.125em;
}
`;
Styled.Trigger = styled(Trigger)`
${layoutMixins.spacedRow}
width: 100%;
padding: var(--accordion-paddingY) var(--accordion-paddingX);
gap: 0.5rem;
color: var(--color-text-1);
text-align: start;
&:hover {
${Styled.Icon} {
color: var(--color-text-2);
filter: brightness(1.1);
}
}
svg {
color: var(--color-text-0);
transition: transform 0.3s var(--ease-out-expo);
}
&[data-state='open'] svg {
transform: rotate(45deg);
}
`;
Styled.Content = styled(Content)`
overflow: hidden;
margin: 0 var(--accordion-paddingX) var(--accordion-paddingY);
color: var(--color-text-0);
&[data-state='open'] {
animation: ${keyframes`
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
`} 0.3s var(--ease-out-expo);
}
&[data-state='closed'] {
animation: ${keyframes`
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
`} 0.1s var(--ease-in-expo);
}
`;
+2 -8
View File
@@ -45,7 +45,6 @@ const assetIcons = {
SOL: '/currencies/sol.png', SOL: '/currencies/sol.png',
SUI: '/currencies/sui.png', SUI: '/currencies/sui.png',
SUSHI: '/currencies/sushi.png', SUSHI: '/currencies/sushi.png',
TIA: '/currencies/tia.png',
TRX: '/currencies/trx.png', TRX: '/currencies/trx.png',
UMA: '/currencies/uma.png', UMA: '/currencies/uma.png',
UNI: '/currencies/uni.png', UNI: '/currencies/uni.png',
@@ -72,13 +71,8 @@ export const AssetIcon = ({
}: { }: {
symbol?: Nullable<string>; symbol?: Nullable<string>;
className?: string; className?: string;
}) => ( }) =>
<Styled.Img isAssetSymbol(symbol) ? <Styled.Img src={assetIcons[symbol]} className={className} /> : null;
src={isAssetSymbol(symbol) ? assetIcons[symbol] : '/currencies/unavailable.png'}
className={className}
alt={symbol}
/>
);
const Styled: Record<string, AnyStyledComponent> = {}; const Styled: Record<string, AnyStyledComponent> = {};
+1 -1
View File
@@ -61,7 +61,7 @@ export const Button = forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonPr
return ( return (
<StyledBaseButton <StyledBaseButton
disabled={state[ButtonState.Disabled] || state[ButtonState.Loading]} disabled={state[ButtonState.Disabled]}
{...{ ref, action, size, shape, state, ...otherProps }} {...{ ref, action, size, shape, state, ...otherProps }}
> >
{ {
+5 -7
View File
@@ -31,12 +31,10 @@ type ElementProps<TabItemsValue> = {
}; };
type StyleProps = { type StyleProps = {
className?: string;
fullWidthTabs?: boolean; fullWidthTabs?: boolean;
className?: string;
}; };
export type CollapsibleTabsProps<TabItemsValue> = ElementProps<TabItemsValue> & StyleProps;
export const CollapsibleTabs = <TabItemsValue extends string>({ export const CollapsibleTabs = <TabItemsValue extends string>({
defaultValue, defaultValue,
items, items,
@@ -45,9 +43,8 @@ export const CollapsibleTabs = <TabItemsValue extends string>({
onOpenChange, onOpenChange,
fullWidthTabs, fullWidthTabs,
className, className,
}: CollapsibleTabsProps<TabItemsValue>) => { }: ElementProps<TabItemsValue> & StyleProps) => {
const [value, setValue] = useState(defaultValue); const [value, setValue] = useState(defaultValue);
const currentItem = items.find((item) => item.value === value); const currentItem = items.find((item) => item.value === value);
@@ -89,8 +86,8 @@ export const CollapsibleTabs = <TabItemsValue extends string>({
</Styled.Header> </Styled.Header>
<Styled.CollapsibleContent> <Styled.CollapsibleContent>
{items.map(({ asChild, value, content }) => ( {items.map(({ value, content }) => (
<Styled.TabsContent key={value} asChild={asChild} value={value}> <Styled.TabsContent key={value} value={value}>
{content} {content}
</Styled.TabsContent> </Styled.TabsContent>
))} ))}
@@ -222,6 +219,7 @@ Styled.Header = styled.header`
Styled.CollapsibleContent = styled(CollapsibleContent)` Styled.CollapsibleContent = styled(CollapsibleContent)`
${layoutMixins.stack} ${layoutMixins.stack}
${layoutMixins.perspectiveArea}
box-shadow: none; box-shadow: none;
`; `;
-1
View File
@@ -122,7 +122,6 @@ Styled.Dialog = styled(Dialog)`
/* Net 0 sticky top inset (let stickyArea1 header stick to top) */ /* Net 0 sticky top inset (let stickyArea1 header stick to top) */
--stickyArea0-topGap: calc(-1 * var(--stickyArea0-topHeight)); --stickyArea0-topGap: calc(-1 * var(--stickyArea0-topHeight));
overflow-x: clip;
} }
`; `;
+9 -6
View File
@@ -44,6 +44,13 @@ export const ComboboxMenu = <MenuItemValue extends string, MenuGroupValue extend
}: ComboboxMenuProps<MenuItemValue, MenuGroupValue>) => { }: ComboboxMenuProps<MenuItemValue, MenuGroupValue>) => {
const [highlightedCommand, setHighlightedCommand] = useState<MenuItemValue>(); const [highlightedCommand, setHighlightedCommand] = useState<MenuItemValue>();
const [searchValue, setSearchValue] = useState(''); const [searchValue, setSearchValue] = useState('');
// const inputRef = useRef<HTMLInputElement | null>(null);
// console.log({ commandValue: highlightedCommand });
// useEffect(() => {
// inputRef?.current?.focus();
// }, []);
return ( return (
<Styled.Command <Styled.Command
@@ -60,14 +67,11 @@ export const ComboboxMenu = <MenuItemValue extends string, MenuGroupValue extend
{withSearch && ( {withSearch && (
<Styled.Header $withStickyLayout={withStickyLayout}> <Styled.Header $withStickyLayout={withStickyLayout}>
<Styled.Input <Styled.Input
/** // ref={inputRef}
* Mobile Issue: Search Input will always trigger mobile keyboard drawer. There is no fix.
* https://github.com/pacocoursey/cmdk/issues/127
*/
autoFocus
type="search" type="search"
value={searchValue} value={searchValue}
onValueChange={setSearchValue} onValueChange={setSearchValue}
autoFocus
placeholder={inputPlaceholder} placeholder={inputPlaceholder}
/> />
</Styled.Header> </Styled.Header>
@@ -254,7 +258,6 @@ Styled.Group = styled(Command.Group)<{ $withItemBorders?: boolean; $withStickyLa
> [cmdk-group-heading] { > [cmdk-group-heading] {
${layoutMixins.stickyHeader} ${layoutMixins.stickyHeader}
z-index: 2;
} }
> [cmdk-group-items] { > [cmdk-group-items] {
+1
View File
@@ -11,5 +11,6 @@ export const DetachedScrollableSection = styled.section`
export const AttachedExpandingSection = styled.section` export const AttachedExpandingSection = styled.section`
${layoutMixins.contentSectionAttached} ${layoutMixins.contentSectionAttached}
${layoutMixins.expandingColumnWithHeader}
gap: var(--border-width); gap: var(--border-width);
`; `;
+7 -12
View File
@@ -10,7 +10,6 @@ import { layoutMixins } from '@/styles/layoutMixins';
import { Button, ButtonProps } from './Button'; import { Button, ButtonProps } from './Button';
import { Icon, IconName } from './Icon'; import { Icon, IconName } from './Icon';
import { IconButton } from './IconButton'; import { IconButton } from './IconButton';
import { WithTooltip } from './WithTooltip';
export type CopyButtonProps = { export type CopyButtonProps = {
value?: string; value?: string;
@@ -41,17 +40,13 @@ export const CopyButton = ({
<Styled.Icon copied={copied} iconName={copied ? IconName.Check : IconName.Copy} /> <Styled.Icon copied={copied} iconName={copied ? IconName.Check : IconName.Copy} />
</Styled.InlineRow> </Styled.InlineRow>
) : buttonType === 'icon' ? ( ) : buttonType === 'icon' ? (
<WithTooltip <Styled.IconButton
tooltipString={stringGetter({ key: copied ? STRING_KEYS.COPIED : STRING_KEYS.COPY })} {...buttonProps}
> copied={copied}
<Styled.IconButton action={ButtonAction.Base}
{...buttonProps} iconName={copied ? IconName.Check : IconName.Copy}
copied={copied} onClick={onCopy}
action={ButtonAction.Base} />
iconName={copied ? IconName.Check : IconName.Copy}
onClick={onCopy}
/>
</WithTooltip>
) : ( ) : (
<Button <Button
{...buttonProps} {...buttonProps}
+3 -12
View File
@@ -24,6 +24,7 @@ import {
CoinsIcon, CoinsIcon,
CommentIcon, CommentIcon,
CopyIcon, CopyIcon,
CubeIcon,
DepositIcon, DepositIcon,
DepthChartIcon, DepthChartIcon,
DiscordIcon, DiscordIcon,
@@ -37,7 +38,6 @@ import {
HelpCircleIcon, HelpCircleIcon,
HideIcon, HideIcon,
HistoryIcon, HistoryIcon,
LeaderboardIcon,
LinkOutIcon, LinkOutIcon,
LockIcon, LockIcon,
LogoShortIcon, LogoShortIcon,
@@ -53,13 +53,10 @@ import {
OrderUntriggeredIcon, OrderUntriggeredIcon,
OverviewIcon, OverviewIcon,
PencilIcon, PencilIcon,
PlayIcon,
PlusIcon,
PositionsIcon, PositionsIcon,
PriceChartIcon, PriceChartIcon,
PrivacyIcon, PrivacyIcon,
QrIcon, QrIcon,
RewardStarIcon,
SearchIcon, SearchIcon,
SendIcon, SendIcon,
ShareIcon, ShareIcon,
@@ -99,6 +96,7 @@ export enum IconName {
Coins = 'Coins', Coins = 'Coins',
Comment = 'Comment', Comment = 'Comment',
Copy = 'Copy', Copy = 'Copy',
Cube = 'Cube',
Deposit = 'Deposit', Deposit = 'Deposit',
DepthChart = 'DepthChart', DepthChart = 'DepthChart',
Discord = 'Discord', Discord = 'Discord',
@@ -112,7 +110,6 @@ export enum IconName {
HelpCircle = 'HelpCircle', HelpCircle = 'HelpCircle',
Hide = 'Hide', Hide = 'Hide',
History = 'History', History = 'History',
Leaderboard = 'Leaderboard',
LinkOut = 'LinkOut', LinkOut = 'LinkOut',
Lock = 'Lock', Lock = 'Lock',
LogoShort = 'LogoShort', LogoShort = 'LogoShort',
@@ -129,13 +126,10 @@ export enum IconName {
OrderUntriggered = 'OrderUntriggered', OrderUntriggered = 'OrderUntriggered',
Overview = 'Overview', Overview = 'Overview',
Pencil = 'Pencil', Pencil = 'Pencil',
Play = 'Play',
Plus = 'Plus',
Positions = 'Positions', Positions = 'Positions',
PriceChart = 'PriceChart', PriceChart = 'PriceChart',
Privacy = 'Privacy', Privacy = 'Privacy',
Qr = 'Qr', Qr = 'Qr',
RewardStar = 'RewardStar',
Search = 'Search', Search = 'Search',
Send = 'Send', Send = 'Send',
Share = 'Share', Share = 'Share',
@@ -175,6 +169,7 @@ const icons = {
[IconName.Coins]: CoinsIcon, [IconName.Coins]: CoinsIcon,
[IconName.Comment]: CommentIcon, [IconName.Comment]: CommentIcon,
[IconName.Copy]: CopyIcon, [IconName.Copy]: CopyIcon,
[IconName.Cube]: CubeIcon,
[IconName.Deposit]: DepositIcon, [IconName.Deposit]: DepositIcon,
[IconName.DepthChart]: DepthChartIcon, [IconName.DepthChart]: DepthChartIcon,
[IconName.Discord]: DiscordIcon, [IconName.Discord]: DiscordIcon,
@@ -188,7 +183,6 @@ const icons = {
[IconName.HelpCircle]: HelpCircleIcon, [IconName.HelpCircle]: HelpCircleIcon,
[IconName.Hide]: HideIcon, [IconName.Hide]: HideIcon,
[IconName.History]: HistoryIcon, [IconName.History]: HistoryIcon,
[IconName.Leaderboard]: LeaderboardIcon,
[IconName.LinkOut]: LinkOutIcon, [IconName.LinkOut]: LinkOutIcon,
[IconName.Lock]: LockIcon, [IconName.Lock]: LockIcon,
[IconName.LogoShort]: LogoShortIcon, [IconName.LogoShort]: LogoShortIcon,
@@ -204,13 +198,10 @@ const icons = {
[IconName.OrderUntriggered]: OrderUntriggeredIcon, [IconName.OrderUntriggered]: OrderUntriggeredIcon,
[IconName.Overview]: OverviewIcon, [IconName.Overview]: OverviewIcon,
[IconName.Pencil]: PencilIcon, [IconName.Pencil]: PencilIcon,
[IconName.Play]: PlayIcon,
[IconName.Plus]: PlusIcon,
[IconName.Positions]: PositionsIcon, [IconName.Positions]: PositionsIcon,
[IconName.PriceChart]: PriceChartIcon, [IconName.PriceChart]: PriceChartIcon,
[IconName.Privacy]: PrivacyIcon, [IconName.Privacy]: PrivacyIcon,
[IconName.Qr]: QrIcon, [IconName.Qr]: QrIcon,
[IconName.RewardStar]: RewardStarIcon,
[IconName.Search]: SearchIcon, [IconName.Search]: SearchIcon,
[IconName.Send]: SendIcon, [IconName.Send]: SendIcon,
[IconName.Share]: ShareIcon, [IconName.Share]: ShareIcon,
+21 -30
View File
@@ -10,7 +10,7 @@ import {
USD_DECIMALS, USD_DECIMALS,
} from '@/constants/numbers'; } from '@/constants/numbers';
import { BIG_NUMBERS } from '@/lib/numbers'; import { BIG_NUMBERS, MustBigNumber } from '@/lib/numbers';
import { useLocaleSeparators } from '@/hooks'; import { useLocaleSeparators } from '@/hooks';
export enum InputType { export enum InputType {
@@ -29,38 +29,31 @@ type StyleProps = {
type ElementProps = { type ElementProps = {
type?: InputType; type?: InputType;
value?: string | number | null; value?: string | number | null;
allowNegative?: boolean;
decimals?: number;
disabled?: boolean; disabled?: boolean;
id?: string; id?: string;
max?: number;
onBlur?: () => void; onBlur?: () => void;
onChange?:
| Dispatch<SetStateAction<string>>
| React.ReactEventHandler<HTMLInputElement>
| ((values: NumberFormatValues, e: SourceInfo) => void);
onFocus?: () => void; onFocus?: () => void;
onInput?: ({
value,
floatValue,
formattedValue,
}: {
value: string;
floatValue?: number;
formattedValue: string;
}) => void;
placeholder?: string; placeholder?: string;
}; };
type ConditionalProps = export type InputProps = ElementProps & StyleProps;
| {
allowNegative?: boolean;
decimals?: number;
max?: number;
onChange?: (values: NumberFormatValues, e: SourceInfo) => void;
onInput?: ({
value,
floatValue,
formattedValue,
}: {
value: string;
floatValue?: number;
formattedValue: string;
}) => void;
}
| {
allowNegative?: never;
decimals?: never;
max?: never;
onChange?: Dispatch<SetStateAction<string>> | React.ReactEventHandler<HTMLInputElement>;
onInput?: (e: SyntheticInputEvent) => void;
};
export type InputProps = ElementProps & StyleProps & ConditionalProps;
export const Input = forwardRef<HTMLInputElement, InputProps>( export const Input = forwardRef<HTMLInputElement, InputProps>(
( (
@@ -136,7 +129,6 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
placeholder={placeholder} placeholder={placeholder}
value={value} value={value}
// Other // Other
data-1p-ignore // prevent 1Password fill
{...otherProps} {...otherProps}
/> />
) : ( ) : (
@@ -145,7 +137,6 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
ref={ref as React.Ref<typeof NumericFormat<unknown>>} ref={ref as React.Ref<typeof NumericFormat<unknown>>}
id={id} id={id}
// NumericFormat // NumericFormat
valueIsNumericString
allowNegative={allowNegative} allowNegative={allowNegative}
decimalScale={decimals} decimalScale={decimals}
decimalSeparator={LOCALE_DECIMAL_SEPARATOR} decimalSeparator={LOCALE_DECIMAL_SEPARATOR}
@@ -169,7 +160,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
? undefined ? undefined
: Number(formattedValue.replace(',', '.')); : Number(formattedValue.replace(',', '.'));
onInput?.({ value, floatValue, formattedValue, ...e }); onInput?.({ value, floatValue, formattedValue });
}} }}
// Native // Native
disabled={disabled} disabled={disabled}
@@ -177,7 +168,6 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
value={formattedValue} value={formattedValue}
autoComplete="off" autoComplete="off"
autoCorrect="off" autoCorrect="off"
data-1p-ignore // prevent 1Password fill
{...otherProps} {...otherProps}
/> />
)} )}
@@ -198,6 +188,7 @@ Styled.InputContainer = styled.div`
border-radius: inherit; border-radius: inherit;
input { input {
user-select: all;
flex: 1; flex: 1;
width: 100%; width: 100%;
} }
-7
View File
@@ -4,7 +4,6 @@ import { Link } from 'react-router-dom';
import { Icon, IconName } from '@/components/Icon'; import { Icon, IconName } from '@/components/Icon';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { breakpoints } from '@/styles';
type PanelProps = { type PanelProps = {
slotHeaderContent?: string; slotHeaderContent?: string;
@@ -68,12 +67,6 @@ Styled.Panel = styled.section<{ onClick?: () => void }>`
--panel-content-paddingY: var(--panel-paddingY); --panel-content-paddingY: var(--panel-paddingY);
--panel-content-paddingX: var(--panel-paddingX); --panel-content-paddingX: var(--panel-paddingX);
@media ${breakpoints.notTablet} {
--panel-paddingX: 1.5rem;
--panel-paddingY: 1.25rem;
--panel-content-paddingY: 1rem;
}
${layoutMixins.row} ${layoutMixins.row}
background-color: var(--color-layer-3); background-color: var(--color-layer-3);
+12 -71
View File
@@ -33,20 +33,16 @@ import {
import { useAsyncList } from 'react-stately'; import { useAsyncList } from 'react-stately';
import { useBreakpoints, useStringGetter } from '@/hooks'; import { useBreakpoints } from '@/hooks';
import { MediaQueryKeys } from '@/hooks/useBreakpoints'; import { MediaQueryKeys } from '@/hooks/useBreakpoints';
import { Checkbox } from '@/components/Checkbox';
import { breakpoints } from '@/styles'; import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { CaretIcon } from '@/icons';
import { STRING_KEYS } from '@/constants/localization';
import { MustBigNumber } from '@/lib/numbers';
import { Icon, IconName } from './Icon'; import { Icon, IconName } from './Icon';
import { Tag } from './Tag'; import { Tag } from './Tag';
import { Button } from './Button';
export { TableCell } from './Table/TableCell'; export { TableCell } from './Table/TableCell';
export { TableColumnHeader } from './Table/TableColumnHeader'; export { TableColumnHeader } from './Table/TableColumnHeader';
@@ -68,7 +64,7 @@ export type TableItem<TableRowData> = {
onSelect?: (key: TableRowData) => void; onSelect?: (key: TableRowData) => void;
}; };
type ColumnDef<TableRowData extends object> = { export type ColumnDef<TableRowData extends object> = {
columnKey: string; columnKey: string;
label: React.ReactNode; label: React.ReactNode;
tag?: React.ReactNode; tag?: React.ReactNode;
@@ -83,7 +79,7 @@ type ColumnDef<TableRowData extends object> = {
width?: ColumnSize; width?: ColumnSize;
}; };
export type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey extends Key> = { type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey extends Key> = {
label?: string; label?: string;
columns: ColumnDef<TableRowData>[]; columns: ColumnDef<TableRowData>[];
data: TableRowData[]; data: TableRowData[];
@@ -95,7 +91,6 @@ export type ElementProps<TableRowData extends object | CustomRowConfig, TableRow
selectionBehavior?: 'replace' | 'toggle'; selectionBehavior?: 'replace' | 'toggle';
onRowAction?: (key: TableRowKey, row: TableRowData) => void; onRowAction?: (key: TableRowKey, row: TableRowData) => void;
slotEmpty?: React.ReactNode; slotEmpty?: React.ReactNode;
initialNumRowsToShow?: number;
// collection: TableCollection<string>; // collection: TableCollection<string>;
// children: React.ReactNode; // children: React.ReactNode;
}; };
@@ -125,7 +120,6 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
selectionMode = 'single', selectionMode = 'single',
selectionBehavior = 'toggle', selectionBehavior = 'toggle',
slotEmpty, slotEmpty,
initialNumRowsToShow = data.length,
// shouldRowRender, // shouldRowRender,
// collection, // collection,
@@ -141,7 +135,6 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
style, style,
}: ElementProps<TableRowData, TableRowKey> & StyleProps) => { }: ElementProps<TableRowData, TableRowKey> & StyleProps) => {
const [selectedKeys, setSelectedKeys] = useState(new Set<TableRowKey>()); const [selectedKeys, setSelectedKeys] = useState(new Set<TableRowKey>());
const [numRowsToShow, setNumRowsToShow] = useState(initialNumRowsToShow);
const currentBreakpoints = useBreakpoints(); const currentBreakpoints = useBreakpoints();
const shownColumns = columns.filter( const shownColumns = columns.filter(
@@ -168,7 +161,10 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
? // String ? // String
collator.compare(first as string, second as string) collator.compare(first as string, second as string)
: // Number : // Number
MustBigNumber(first).comparedTo(MustBigNumber(second))) * Math.sign(
(parseInt(first as string) || (first as number)) -
(parseInt(second as string) || (second as number))
)) *
// Flip the direction if descending order is specified. // Flip the direction if descending order is specified.
(sortDirection === 'descending' ? -1 : 1) (sortDirection === 'descending' ? -1 : 1)
); );
@@ -215,12 +211,6 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
onRowAction && onRowAction &&
((key: TableRowKey) => onRowAction(key, data.find((row) => getRowKey(row) === key)!)) ((key: TableRowKey) => onRowAction(key, data.find((row) => getRowKey(row) === key)!))
} }
numColumns={shownColumns.length}
onViewMoreClick={
numRowsToShow !== undefined && numRowsToShow < data.length
? () => setNumRowsToShow(data.length)
: undefined
}
// shouldRowRender={shouldRowRender} // shouldRowRender={shouldRowRender}
hideHeader={hideHeader} hideHeader={hideHeader}
withGradientCardRows={withGradientCardRows} withGradientCardRows={withGradientCardRows}
@@ -245,7 +235,7 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
)} )}
</TableHeader> </TableHeader>
<TableBody items={list.items.slice(0, numRowsToShow)}> <TableBody items={list.items}>
{(item) => ( {(item) => (
<Row key={getRowKey(item)}> <Row key={getRowKey(item)}>
{(columnKey) => ( {(columnKey) => (
@@ -279,8 +269,6 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
onRowAction?: (key: TableRowKey) => void; onRowAction?: (key: TableRowKey) => void;
// shouldRowRender?: (prevRowData: object, currentRowData: object) => boolean; // shouldRowRender?: (prevRowData: object, currentRowData: object) => boolean;
children: CollectionChildren<TableRowData>; children: CollectionChildren<TableRowData>;
numColumns: number;
onViewMoreClick?: () => void;
hideHeader?: boolean; hideHeader?: boolean;
withGradientCardRows?: boolean; withGradientCardRows?: boolean;
@@ -290,7 +278,7 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
withScrollSnapColumns?: boolean; withScrollSnapColumns?: boolean;
withScrollSnapRows?: boolean; withScrollSnapRows?: boolean;
}) => { }) => {
const { selectionMode, selectionBehavior, numColumns, onViewMoreClick } = props; const { selectionMode, selectionBehavior } = props;
const state = useTableState<TableRowData>({ const state = useTableState<TableRowData>({
...props, ...props,
@@ -351,7 +339,6 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
<TableBodyRowGroup <TableBodyRowGroup
withGradientCardRows={props.withGradientCardRows} withGradientCardRows={props.withGradientCardRows}
withInnerBorders={props.withInnerBorders} withInnerBorders={props.withInnerBorders}
withOuterBorder={props.withOuterBorder}
> >
{/* {Array.from(collection.getChildren!(collection.body.key), (row) => */} {/* {Array.from(collection.getChildren!(collection.body.key), (row) => */}
{[...collection.body.childNodes].map((row) => {[...collection.body.childNodes].map((row) =>
@@ -397,9 +384,6 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
</TableRow> </TableRow>
) )
)} )}
{onViewMoreClick ? (
<ViewMoreRow colSpan={numColumns} onClick={onViewMoreClick} />
) : undefined}
</TableBodyRowGroup> </TableBodyRowGroup>
</Styled.Table> </Styled.Table>
); );
@@ -433,7 +417,6 @@ const TableBodyRowGroup = ({
children, children,
withGradientCardRows, withGradientCardRows,
withInnerBorders, withInnerBorders,
withOuterBorder,
}: { children: React.ReactNode } & StyleProps) => { }: { children: React.ReactNode } & StyleProps) => {
const { rowGroupProps } = useTableRowGroup(); const { rowGroupProps } = useTableRowGroup();
@@ -442,7 +425,6 @@ const TableBodyRowGroup = ({
{...rowGroupProps} {...rowGroupProps}
withGradientCardRows={withGradientCardRows} withGradientCardRows={withGradientCardRows}
withInnerBorders={withInnerBorders} withInnerBorders={withInnerBorders}
withOuterBorder={withOuterBorder}
> >
{children} {children}
</Styled.Tbody> </Styled.Tbody>
@@ -509,23 +491,6 @@ const TableColumnHeader = <TableRowData extends object>({
); );
}; };
export const ViewMoreRow = ({ colSpan, onClick }: { colSpan: number; onClick: () => void }) => {
const stringGetter = useStringGetter();
return (
<Styled.Tr key="viewmore">
<Styled.Td
colSpan={colSpan}
onMouseDown={(e: MouseEvent) => e.preventDefault()}
onPointerDown={(e: MouseEvent) => e.preventDefault()}
>
<Styled.ViewMoreButton slotRight={<CaretIcon />} onClick={onClick}>
{stringGetter({ key: STRING_KEYS.VIEW_MORE })}
</Styled.ViewMoreButton>
</Styled.Td>
</Styled.Tr>
);
};
export const TableRow = <TableRowData extends object>({ export const TableRow = <TableRowData extends object>({
item, item,
children, children,
@@ -697,7 +662,7 @@ Styled.Empty = styled.div<{ withOuterBorder: boolean }>`
justify-items: center; justify-items: center;
align-content: center; align-content: center;
padding: 4rem; padding: 2rem;
gap: 0.75em; gap: 0.75em;
color: var(--color-text-0); color: var(--color-text-0);
@@ -905,18 +870,6 @@ Styled.Tbody = styled.tbody<StyleProps>`
--stickyArea2-paddingLeft: var(--border-width); --stickyArea2-paddingLeft: var(--border-width);
--stickyArea2-paddingRight: var(--border-width); --stickyArea2-paddingRight: var(--border-width);
tr:first-of-type {
box-shadow: 0 calc(var(--border-width)) 0 0 var(--border-color);
}
`}
${({ withOuterBorder }) =>
withOuterBorder &&
css`
tr:last-of-type:not(:only-of-type) {
box-shadow: 0 calc(-1 * var(--border-width)) 0 0 var(--border-color);
}
tr:first-of-type { tr:first-of-type {
box-shadow: none; box-shadow: none;
} }
@@ -971,15 +924,3 @@ Styled.Row = styled.div`
${layoutMixins.inlineRow} ${layoutMixins.inlineRow}
padding: var(--tableCell-padding); padding: var(--tableCell-padding);
`; `;
Styled.ViewMoreButton = styled(Button)`
--button-backgroundColor: var(--color-layer-2);
--button-textColor: var(--color-text-1);
width: 100%;
svg {
width: 0.675rem;
margin-left: 0.5ch;
}
`;
+2 -5
View File
@@ -21,7 +21,6 @@ export type TabItem<TabItemsValue> = {
content?: React.ReactNode; content?: React.ReactNode;
subitems?: TabItem<TabItemsValue>[]; subitems?: TabItem<TabItemsValue>[];
customTrigger?: ReactNode; customTrigger?: ReactNode;
asChild?: boolean;
}; };
type ElementProps<TabItemsValue> = { type ElementProps<TabItemsValue> = {
@@ -42,8 +41,6 @@ type StyleProps = {
className?: string; className?: string;
}; };
export type TabsProps<TabItemsValue> = ElementProps<TabItemsValue> & StyleProps;
export const Tabs = <TabItemsValue extends string>({ export const Tabs = <TabItemsValue extends string>({
defaultValue, defaultValue,
value, value,
@@ -110,10 +107,9 @@ export const Tabs = <TabItemsValue extends string>({
sharedContent sharedContent
) : ( ) : (
<Styled.Stack> <Styled.Stack>
{items.map(({ asChild, value, content, forceMount }) => ( {items.map(({ value, content, forceMount }) => (
<Styled.Content <Styled.Content
key={value} key={value}
asChild={asChild}
value={value} value={value}
forceMount={forceMount} forceMount={forceMount}
$hide={forceMount && currentItem?.value !== value} $hide={forceMount && currentItem?.value !== value}
@@ -246,6 +242,7 @@ Styled.Trigger = styled(Trigger)<{ $withBorders?: boolean }>`
Styled.Stack = styled.div` Styled.Stack = styled.div`
${layoutMixins.stack} ${layoutMixins.stack}
${layoutMixins.perspectiveArea}
box-shadow: none; box-shadow: none;
`; `;
+2 -7
View File
@@ -4,7 +4,6 @@ import { Root, Action, Close } from '@radix-ui/react-toast';
import { ButtonShape, ButtonSize } from '@/constants/buttons'; import { ButtonShape, ButtonSize } from '@/constants/buttons';
import { popoverMixins } from '@/styles/popoverMixins'; import { popoverMixins } from '@/styles/popoverMixins';
import { breakpoints } from '@/styles';
import { Notification, type NotificationProps } from '@/components/Notification'; import { Notification, type NotificationProps } from '@/components/Notification';
@@ -77,7 +76,7 @@ export const Toast = ({
<Close asChild> <Close asChild>
<$CloseButton <$CloseButton
iconName={IconName.Close} iconName={IconName.Close}
shape={ButtonShape.Circle} shape={ButtonShape.Square}
size={ButtonSize.XSmall} size={ButtonSize.XSmall}
onClick={(e: MouseEvent) => e.stopPropagation()} onClick={(e: MouseEvent) => e.stopPropagation()}
/> />
@@ -250,16 +249,12 @@ const $CloseButton = styled(IconButton)`
right: 0; right: 0;
border: solid var(--border-width) var(--color-border); border: solid var(--border-width) var(--color-border);
border-radius: 50%;
${$Root}:hover & { ${$Root}:hover & {
display: block; display: block;
z-index: 2; z-index: 2;
} }
@media ${breakpoints.mobile} {
display: block;
z-index: 2;
}
`; `;
const $Action = styled(Action)` const $Action = styled(Action)`
+4 -6
View File
@@ -1,7 +1,6 @@
import styled from 'styled-components';
import { Provider, Viewport } from '@radix-ui/react-toast'; import { Provider, Viewport } from '@radix-ui/react-toast';
import styled from 'styled-components';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
type ElementProps = { type ElementProps = {
@@ -13,9 +12,7 @@ type StyleProps = {
className?: string; className?: string;
}; };
type ToastAreaProps = ElementProps & StyleProps; export const ToastArea = ({ swipeDirection, children, className }: ElementProps & StyleProps) => (
export const ToastArea = ({ swipeDirection, children, className }: ToastAreaProps) => (
<$ToastArea className={className}> <$ToastArea className={className}>
<Provider swipeDirection={swipeDirection}> <Provider swipeDirection={swipeDirection}>
{children} {children}
@@ -27,8 +24,9 @@ export const ToastArea = ({ swipeDirection, children, className }: ToastAreaProp
const $ToastArea = styled.aside` const $ToastArea = styled.aside`
// Params // Params
--toasts-gap: 0.5rem; --toasts-gap: 0.5rem;
// Rules // Rules
${layoutMixins.scrollArea}
z-index: 1; z-index: 1;
pointer-events: none; pointer-events: none;
@@ -1,33 +1,26 @@
import React, { PropsWithChildren, useContext, useState } from 'react'; import React, { useContext, useState } from 'react';
import { Point } from '@visx/point'; import { Point } from '@visx/point';
import { localPoint } from '@visx/event'; import { localPoint } from '@visx/event';
import { XYChart, DataContext, type EventHandlerParams } from '@visx/xychart'; import { XYChart, DataContext } from '@visx/xychart';
import { getScaleBandwidth } from '@/components/visx/getScaleBandwidth'; import { getScaleBandwidth } from '@/components/visx/getScaleBandwidth';
export const XYChartWithPointerEvents = ({ export const XYChartWithPointerEvents = ({
onPointerMove, onPointerMove, onPointerUp, onPointerPressedChange, ...props
onPointerUp,
onPointerPressedChange,
...props
}: { }: {
onPointerMove?: (point: Point | EventHandlerParams<object>) => void; onPointerMove?: (point: Point) => void;
onPointerUp?: (point: Point | EventHandlerParams<object>) => void; onPointerUp?: (point: Point) => void;
onPointerPressedChange?: (isPointerPressed: boolean) => void; onPointerPressedChange?: (isPointerPressed: boolean) => void;
} & PropsWithChildren<Parameters<typeof XYChart>[0]>) => { } & React.PropsWithChildren<Parameters<typeof XYChart>>) => {
const { xScale, yScale } = useContext(DataContext); const { xScale, yScale } = useContext(DataContext);
const [lastPointerMoveEvent, setLastPointerMoveEvent] = useState<React.PointerEvent>(); const [lastPointerMoveEvent, setLastPointerMoveEvent] = useState<React.PointerEvent>();
const pointerContainerPosition = lastPointerMoveEvent ? localPoint(lastPointerMoveEvent) : null; const pointerContainerPosition = lastPointerMoveEvent ? localPoint(lastPointerMoveEvent) : null;
const pointerChartPosition = const pointerChartPosition = xScale && yScale && pointerContainerPosition &&
xScale &&
yScale &&
pointerContainerPosition &&
new Point({ new Point({
// @ts-expect-error invert supposedly doesn't exist on AxisScale
x: xScale.invert(pointerContainerPosition?.x - getScaleBandwidth(xScale) / 2), x: xScale.invert(pointerContainerPosition?.x - getScaleBandwidth(xScale) / 2),
// @ts-expect-error invert supposedly doesn't exist on AxisScale
y: yScale.invert(pointerContainerPosition?.y - getScaleBandwidth(yScale) / 2), y: yScale.invert(pointerContainerPosition?.y - getScaleBandwidth(yScale) / 2),
}); });
@@ -36,13 +29,15 @@ export const XYChartWithPointerEvents = ({
{...props} {...props}
onPointerMove={({ event }) => { onPointerMove={({ event }) => {
setLastPointerMoveEvent(event as React.PointerEvent); setLastPointerMoveEvent(event as React.PointerEvent);
if (pointerChartPosition) onPointerMove?.(pointerChartPosition); if (pointerChartPosition)
onPointerMove?.(pointerChartPosition);
}} }}
onPointerOut={() => setLastPointerMoveEvent(undefined)} onPointerOut={() => setLastPointerMoveEvent(undefined)}
onPointerDown={() => onPointerPressedChange?.(true)} onPointerDown={() => onPointerPressedChange?.(true)}
onPointerUp={() => { onPointerUp={() => {
onPointerPressedChange?.(false); onPointerPressedChange?.(false);
if (pointerChartPosition) onPointerUp?.(pointerChartPosition); if (pointerChartPosition)
onPointerUp?.(pointerChartPosition);
}} }}
> >
{props.children} {props.children}
+3 -3
View File
@@ -142,7 +142,7 @@ const historicalPnlPeriod = [...HistoricalPnlPeriod.values()] as const;
export type HistoricalPnlPeriods = (typeof historicalPnlPeriod)[number]; export type HistoricalPnlPeriods = (typeof historicalPnlPeriod)[number];
// ------ Transfer Items ------ // // ------ Transfer Items ------ //
export const TransferInputField = Abacus.exchange.dydx.abacus.state.model.TransferInputField; export const TransferInputField = Abacus.exchange.dydx.abacus.state.modal.TransferInputField;
const transferInputFields = [...TransferInputField.values()] as const; const transferInputFields = [...TransferInputField.values()] as const;
export type TransferInputFields = (typeof transferInputFields)[number]; export type TransferInputFields = (typeof transferInputFields)[number];
@@ -151,7 +151,7 @@ const transferTypes = [...TransferType.values()] as const;
export type TransferTypes = (typeof transferTypes)[number]; export type TransferTypes = (typeof transferTypes)[number];
// ------ Trade Items ------ // // ------ Trade Items ------ //
export const TradeInputField = Abacus.exchange.dydx.abacus.state.model.TradeInputField; export const TradeInputField = Abacus.exchange.dydx.abacus.state.modal.TradeInputField;
const tradeInputFields = [...TradeInputField.values()] as const; const tradeInputFields = [...TradeInputField.values()] as const;
export type TradeInputFields = (typeof tradeInputFields)[number]; export type TradeInputFields = (typeof tradeInputFields)[number];
@@ -162,7 +162,7 @@ export type TradeState<T> = {
}; };
export const ClosePositionInputField = export const ClosePositionInputField =
Abacus.exchange.dydx.abacus.state.model.ClosePositionInputField; Abacus.exchange.dydx.abacus.state.modal.ClosePositionInputField;
const closePositionInputFields = [...ClosePositionInputField.values()] as const; const closePositionInputFields = [...ClosePositionInputField.values()] as const;
export type ClosePositionInputFields = (typeof closePositionInputFields)[number]; export type ClosePositionInputFields = (typeof closePositionInputFields)[number];
-1
View File
@@ -96,7 +96,6 @@ export type AnalyticsEventData<T extends AnalyticsEvent> =
elapsedTime?: number; elapsedTime?: number;
blockHeight?: number; blockHeight?: number;
indexerBlockHeight?: number; indexerBlockHeight?: number;
trailingBlocks?: number;
} }
: // Navigation : // Navigation
T extends AnalyticsEvent.NavigatePage T extends AnalyticsEvent.NavigatePage
-40
View File
@@ -1,40 +0,0 @@
import { OrderSide } from '@dydxprotocol/v4-client-js';
import { FundingDirection } from './markets';
// ------ Depth Chart ------ //
export enum DepthChartSeries {
Asks = 'Asks',
Bids = 'Bids',
MidMarket = 'MidMarket',
}
export type DepthChartDatum = {
size: number;
price: number;
depth: number;
seriesKey: DepthChartSeries;
};
export type DepthChartPoint = {
side: OrderSide;
price: number;
size: number;
};
export const SERIES_KEY_FOR_ORDER_SIDE = {
[OrderSide.BUY]: DepthChartSeries.Bids,
[OrderSide.SELL]: DepthChartSeries.Asks,
};
// ------ Funding Chart ------ //
export enum FundingRateResolution {
OneHour = 'OneHour',
EightHour = 'EightHour',
Annualized = 'Annualized',
}
export type FundingChartDatum = {
time: number;
fundingRate: number;
direction: FundingDirection;
};
+1 -1
View File
@@ -3,7 +3,6 @@ export enum DialogTypes {
Deposit = 'Deposit', Deposit = 'Deposit',
DisconnectWallet = 'DisconnectWallet', DisconnectWallet = 'DisconnectWallet',
ExchangeOffline = 'ExchangeOffline', ExchangeOffline = 'ExchangeOffline',
ExternalLink = 'ExternalLink',
FillDetails = 'FillDetails', FillDetails = 'FillDetails',
Help = 'Help', Help = 'Help',
ExternalNavKeplr = 'ExternalNavKeplr', ExternalNavKeplr = 'ExternalNavKeplr',
@@ -13,6 +12,7 @@ export enum DialogTypes {
OrderDetails = 'OrderDetails', OrderDetails = 'OrderDetails',
Preferences = 'Preferences', Preferences = 'Preferences',
RateLimit = 'RateLimit', RateLimit = 'RateLimit',
Receive = 'Receive',
RestrictedGeo = 'RestrictedGeo', RestrictedGeo = 'RestrictedGeo',
RestrictedWallet = 'RestrictedWallet', RestrictedWallet = 'RestrictedWallet',
Trade = 'Trade', Trade = 'Trade',
-1
View File
@@ -22,7 +22,6 @@ export enum LocalStorageKey {
SelectedTheme = 'dydx.SelectedTheme', SelectedTheme = 'dydx.SelectedTheme',
SelectedTradeLayout = 'dydx.SelectedTradeLayout', SelectedTradeLayout = 'dydx.SelectedTradeLayout',
TradingViewChartConfig = 'dydx.TradingViewChartConfig', TradingViewChartConfig = 'dydx.TradingViewChartConfig',
HasSeenLaunchIncentives = 'dydx.HasSeenLaunchIncentives',
} }
export const LOCAL_STORAGE_VERSIONS = { export const LOCAL_STORAGE_VERSIONS = {
-1
View File
@@ -25,5 +25,4 @@ export const DEFAULT_MARKETID = 'ETH-USD';
export enum FundingDirection { export enum FundingDirection {
ToShort = 'ToShort', ToShort = 'ToShort',
ToLong = 'ToLong', ToLong = 'ToLong',
None = 'None',
} }
-10
View File
@@ -4,7 +4,6 @@ import { StatusResponse } from '@0xsquid/sdk';
export enum NotificationType { export enum NotificationType {
AbacusGenerated = 'AbacusGenerated', AbacusGenerated = 'AbacusGenerated',
SquidTransfer = 'SquidTransfer', SquidTransfer = 'SquidTransfer',
ReleaseUpdates = 'ReleaseUpdates',
} }
export enum NotificationComponentType {} export enum NotificationComponentType {}
@@ -87,8 +86,6 @@ export type NotificationDisplayData = {
slotTitleLeft?: React.ReactNode; slotTitleLeft?: React.ReactNode;
slotTitleRight?: React.ReactNode; slotTitleRight?: React.ReactNode;
groupKey: string; // Grouping key toast notification stacking
// Overrides title/body for Notification in NotificationMenu // Overrides title/body for Notification in NotificationMenu
renderCustomBody?: ({ renderCustomBody?: ({
isToast, isToast,
@@ -124,20 +121,13 @@ export type NotificationDisplayData = {
toastDuration?: number; toastDuration?: number;
}; };
export enum TransferNotificationTypes {
Withdrawal = 'withdrawal',
Deposit = 'deposit',
}
// Notification types // Notification types
export type TransferNotifcation = { export type TransferNotifcation = {
txHash: string; txHash: string;
type?: TransferNotificationTypes;
toChainId?: string; toChainId?: string;
fromChainId?: string; fromChainId?: string;
toAmount?: number; toAmount?: number;
triggeredAt?: number; triggeredAt?: number;
isCctp?: boolean;
errorCount?: number; errorCount?: number;
status?: StatusResponse; status?: StatusResponse;
}; };
-5
View File
@@ -10,7 +10,6 @@ export const LEVERAGE_DECIMALS = 2;
export const TOKEN_DECIMALS = 4; export const TOKEN_DECIMALS = 4;
export const LARGE_TOKEN_DECIMALS = 2; export const LARGE_TOKEN_DECIMALS = 2;
export const FEE_DECIMALS = 3; export const FEE_DECIMALS = 3;
export const FUNDING_DECIMALS = 6;
export const QUANTUM_MULTIPLIER = 1_000_000; export const QUANTUM_MULTIPLIER = 1_000_000;
@@ -19,7 +18,3 @@ export enum NumberSign {
Negative = 'Negative', Negative = 'Negative',
Neutral = 'Neutral', Neutral = 'Neutral',
} }
// Deposit/Withdraw
export const MAX_CCTP_TRANSFER_AMOUNT = 1_000_000;
export const MAX_PRICE_IMPACT = 0.02; // 2%
-4
View File
@@ -1,10 +1,6 @@
import { type TooltipStrings, TOOLTIP_STRING_KEYS } from '@/constants/localization'; import { type TooltipStrings, TOOLTIP_STRING_KEYS } from '@/constants/localization';
export const depositTooltips: TooltipStrings = { export const depositTooltips: TooltipStrings = {
'minimum-deposit-amount': ({ stringGetter }) => ({
title: stringGetter({ key: TOOLTIP_STRING_KEYS.MINIMUM_DEPOSIT_AMOUNT_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.MINIMUM_DEPOSIT_AMOUNT_BODY }),
}),
swap: ({ stringGetter }) => ({ swap: ({ stringGetter }) => ({
title: stringGetter({ key: TOOLTIP_STRING_KEYS.SWAP_TITLE }), title: stringGetter({ key: TOOLTIP_STRING_KEYS.SWAP_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.SWAP_BODY }), body: stringGetter({ key: TOOLTIP_STRING_KEYS.SWAP_BODY }),
-4
View File
@@ -5,10 +5,6 @@ export const withdrawTooltips: TooltipStrings = {
title: stringGetter({ key: TOOLTIP_STRING_KEYS.FAST_WITHDRAW_FEE_TITLE }), title: stringGetter({ key: TOOLTIP_STRING_KEYS.FAST_WITHDRAW_FEE_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.FAST_WITHDRAW_FEE_BODY }), body: stringGetter({ key: TOOLTIP_STRING_KEYS.FAST_WITHDRAW_FEE_BODY }),
}), }),
'minimum-amount-received': ({ stringGetter }) => ({
title: stringGetter({ key: TOOLTIP_STRING_KEYS.MINIMUM_AMOUNT_RECEIVED_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.MINIMUM_AMOUNT_RECEIVED_BODY }),
}),
'withdraw-types': ({ stringGetter }) => ({ 'withdraw-types': ({ stringGetter }) => ({
title: stringGetter({ key: TOOLTIP_STRING_KEYS.WITHDRAW_TYPES_TITLE }), title: stringGetter({ key: TOOLTIP_STRING_KEYS.WITHDRAW_TYPES_TITLE }),
body: stringGetter({ key: TOOLTIP_STRING_KEYS.WITHDRAW_TYPES_BODY }), body: stringGetter({ key: TOOLTIP_STRING_KEYS.WITHDRAW_TYPES_BODY }),
-12
View File
@@ -116,15 +116,3 @@ export enum MobilePlaceOrderSteps {
PlacingOrder = 'PlacingOrder', PlacingOrder = 'PlacingOrder',
Confirmation = 'Confirmation', Confirmation = 'Confirmation',
} }
export const CLEARED_TRADE_INPUTS = {
limitPriceInput: '',
triggerPriceInput: '',
trailingPercentInput: '',
};
export const CLEARED_SIZE_INPUTS = {
amountInput: '',
usdAmountInput: '',
leverageInput: '',
};
-2
View File
@@ -22,7 +22,6 @@ 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 { useTradeFormInputs } from './useTradeFormInputs';
import { useURLConfigs } from './useURLConfigs'; import { useURLConfigs } from './useURLConfigs';
export { export {
@@ -50,6 +49,5 @@ export {
useSelectedNetwork, useSelectedNetwork,
useStringGetter, useStringGetter,
useSubaccount, useSubaccount,
useTradeFormInputs,
useURLConfigs, useURLConfigs,
}; };
+1 -11
View File
@@ -2,7 +2,7 @@ import { useCallback, useContext, createContext, useEffect, useState, useMemo }
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { AES, enc } from 'crypto-js'; import { AES, enc } from 'crypto-js';
import { NOBLE_BECH32_PREFIX, LocalWallet, type Subaccount } from '@dydxprotocol/v4-client-js'; import { LocalWallet, type Subaccount } from '@dydxprotocol/v4-client-js';
import { OnboardingGuard, OnboardingState, type EvmDerivedAddresses } from '@/constants/account'; import { OnboardingGuard, OnboardingState, type EvmDerivedAddresses } from '@/constants/account';
import { DialogTypes } from '@/constants/dialogs'; import { DialogTypes } from '@/constants/dialogs';
@@ -219,16 +219,6 @@ const useAccountsContext = () => {
else abacusStateManager.attemptDisconnectAccount(); else abacusStateManager.attemptDisconnectAccount();
}, [localDydxWallet]); }, [localDydxWallet]);
useEffect(() => {
const setNobleWallet = async () => {
if (hdKey?.mnemonic) {
const nobleWallet = await LocalWallet.fromMnemonic(hdKey.mnemonic, NOBLE_BECH32_PREFIX);
abacusStateManager.setNobleWallet(nobleWallet);
}
};
setNobleWallet();
}, [hdKey?.mnemonic]);
// clear subaccounts when no dydxAddress is set // clear subaccounts when no dydxAddress is set
useEffect(() => { useEffect(() => {
(async () => { (async () => {
+1 -2
View File
@@ -97,7 +97,7 @@ export const useAnalytics = () => {
}, []); }, []);
// AnalyticsEvent.NetworkStatus // AnalyticsEvent.NetworkStatus
const { height, indexerHeight, status, trailingBlocks} = useApiState(); const { height, indexerHeight, status } = useApiState();
useEffect(() => { useEffect(() => {
if (status) { if (status) {
@@ -114,7 +114,6 @@ export const useAnalytics = () => {
elapsedTime: lastSuccessfulIndexerRpcQuery && Date.now() - lastSuccessfulIndexerRpcQuery, elapsedTime: lastSuccessfulIndexerRpcQuery && Date.now() - lastSuccessfulIndexerRpcQuery,
blockHeight: height ?? undefined, blockHeight: height ?? undefined,
indexerBlockHeight: indexerHeight ?? undefined, indexerBlockHeight: indexerHeight ?? undefined,
trailingBlocks: trailingBlocks ?? undefined
}); });
} }
}, [status]); }, [status]);
+1 -1
View File
@@ -71,7 +71,7 @@ export const getIndexerHeight = (apiState: Nullable<AbacusApiState>) => {
export const useApiState = () => { export const useApiState = () => {
const stringGetter = useStringGetter(); const stringGetter = useStringGetter();
const apiState = useSelector(getApiState, shallowEqual); const apiState = useSelector(getApiState, shallowEqual);
const { haltedBlock, height, status, trailingBlocks} = apiState ?? {}; const { haltedBlock, height, status, trailingBlocks } = apiState ?? {};
const statusErrorMessage = getStatusErrorMessage({ apiState, stringGetter }); const statusErrorMessage = getStatusErrorMessage({ apiState, stringGetter });
const indexerHeight = getIndexerHeight(apiState); const indexerHeight = getIndexerHeight(apiState);
+11 -29
View File
@@ -5,15 +5,16 @@ import { useMatch, useNavigate } from 'react-router-dom';
import { LocalStorageKey } from '@/constants/localStorage'; import { LocalStorageKey } from '@/constants/localStorage';
import { DEFAULT_MARKETID } from '@/constants/markets'; import { DEFAULT_MARKETID } from '@/constants/markets';
import { AppRoute } from '@/constants/routes'; import { AppRoute } from '@/constants/routes';
import { useLocalStorage } from '@/hooks/useLocalStorage';
import { getSelectedNetwork } from '@/state/appSelectors'; import { getSelectedNetwork } from '@/state/appSelectors';
import { closeDialogInTradeBox } from '@/state/dialogs'; import { closeDialogInTradeBox } from '@/state/dialogs';
import { setCurrentMarketId } from '@/state/perpetuals'; import { setCurrentMarketId } from '@/state/perpetuals';
import { getMarketIds } from '@/state/perpetualsSelectors';
import abacusStateManager from '@/lib/abacus'; import abacusStateManager from '@/lib/abacus';
import { useLocalStorage } from './useLocalStorage';
import { getMarketIds } from '@/state/perpetualsSelectors';
export const useCurrentMarketId = () => { export const useCurrentMarketId = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const match = useMatch(`/${AppRoute.Trade}/:marketId`); const match = useMatch(`/${AppRoute.Trade}/:marketId`);
@@ -22,7 +23,6 @@ export const useCurrentMarketId = () => {
const selectedNetwork = useSelector(getSelectedNetwork); const selectedNetwork = useSelector(getSelectedNetwork);
const marketIds = useSelector(getMarketIds, shallowEqual); const marketIds = useSelector(getMarketIds, shallowEqual);
const hasMarketIds = marketIds.length > 0; const hasMarketIds = marketIds.length > 0;
const [lastViewedMarket, setLastViewedMarket] = useLocalStorage({ const [lastViewedMarket, setLastViewedMarket] = useLocalStorage({
key: LocalStorageKey.LastViewedMarket, key: LocalStorageKey.LastViewedMarket,
defaultValue: DEFAULT_MARKETID, defaultValue: DEFAULT_MARKETID,
@@ -32,35 +32,17 @@ export const useCurrentMarketId = () => {
if (marketIds.length === 0) return marketId ?? lastViewedMarket; if (marketIds.length === 0) return marketId ?? lastViewedMarket;
if (!marketIds.includes(marketId ?? lastViewedMarket)) return DEFAULT_MARKETID; if (!marketIds.includes(marketId ?? lastViewedMarket)) return DEFAULT_MARKETID;
return marketId ?? lastViewedMarket; return marketId ?? lastViewedMarket;
}, [hasMarketIds, marketId]); }, [marketIds, marketId]);
useEffect(() => { useEffect(() => {
// If v4_markets has not been subscribed to yet or marketId is not specified, default to validId setLastViewedMarket(validId);
if (!hasMarketIds || !marketId) { dispatch(setCurrentMarketId(validId));
setLastViewedMarket(validId); dispatch(closeDialogInTradeBox());
dispatch(setCurrentMarketId(validId));
dispatch(closeDialogInTradeBox());
if (validId !== marketId) { navigate(`${AppRoute.Trade}/${validId}`, {
navigate(`${AppRoute.Trade}/${validId}`, { replace: true,
replace: true, });
}); }, [validId]);
}
} else {
// If v4_markets has been subscribed to, check if marketId is valid
if (!marketIds.includes(marketId)) {
// If marketId is not valid (i.e. final settlement), navigate to markets page
navigate(AppRoute.Markets, {
replace: true,
});
} else {
// If marketId is valid, set currentMarketId
setLastViewedMarket(marketId);
dispatch(setCurrentMarketId(marketId));
dispatch(closeDialogInTradeBox());
}
}
}, [hasMarketIds, marketId]);
useEffect(() => { useEffect(() => {
// Check for marketIds otherwise Abacus will silently fail its isMarketValid check // Check for marketIds otherwise Abacus will silently fail its isMarketValid check
+9 -11
View File
@@ -1,11 +1,11 @@
import { createContext, useContext, useCallback, useEffect, useMemo } from 'react'; import { createContext, useContext, useCallback, useEffect, useMemo } from 'react';
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
import type { StatusResponse } from '@0xsquid/sdk';
import { LOCAL_STORAGE_VERSIONS, LocalStorageKey } from '@/constants/localStorage'; import { LOCAL_STORAGE_VERSIONS, LocalStorageKey } from '@/constants/localStorage';
import { type TransferNotifcation } from '@/constants/notifications'; import { type TransferNotifcation } from '@/constants/notifications';
import { useAccounts } from '@/hooks/useAccounts'; import { useAccounts } from '@/hooks/useAccounts';
import { STATUS_ERROR_GRACE_PERIOD, useSquid } from '@/hooks/useSquid';
import { fetchSquidStatus, STATUS_ERROR_GRACE_PERIOD } from '@/lib/squid';
import { useLocalStorage } from './useLocalStorage'; import { useLocalStorage } from './useLocalStorage';
@@ -68,6 +68,8 @@ const useLocalNotificationsContext = () => {
[transferNotifications] [transferNotifications]
); );
const squid = useSquid();
useQuery({ useQuery({
queryKey: 'getTransactionStatus', queryKey: 'getTransactionStatus',
queryFn: async () => { queryFn: async () => {
@@ -79,27 +81,23 @@ const useLocalNotificationsContext = () => {
toChainId, toChainId,
fromChainId, fromChainId,
triggeredAt, triggeredAt,
isCctp,
errorCount, errorCount,
status: currentStatus, status: currentStatus,
} = transferNotification; } = transferNotification;
// @ts-ignore status.errors is not in the type definition but can be returned
// also error can some time come back as an empty object so we need to ignore for that
const hasErrors = !!currentStatus?.errors ||
(currentStatus?.error && Object.keys(currentStatus.error).length !== 0);
if ( if (
!hasErrors && // @ts-ignore status.errors is not in the type definition but can be returned
!currentStatus?.errors &&
!currentStatus?.error &&
(!currentStatus?.squidTransactionStatus || (!currentStatus?.squidTransactionStatus ||
currentStatus?.squidTransactionStatus === 'ongoing') currentStatus?.squidTransactionStatus === 'ongoing')
) { ) {
try { try {
const status = await fetchSquidStatus({ const status = await squid?.getStatus({
transactionId: txHash, transactionId: txHash,
toChainId, toChainId,
fromChainId, fromChainId,
}, isCctp); });
if (status) { if (status) {
transferNotification.status = status; transferNotification.status = status;
+7 -85
View File
@@ -20,15 +20,12 @@ import {
type NotificationTypeConfig, type NotificationTypeConfig,
NotificationType, NotificationType,
DEFAULT_TOAST_AUTO_CLOSE_MS, DEFAULT_TOAST_AUTO_CLOSE_MS,
TransferNotificationTypes,
} from '@/constants/notifications'; } from '@/constants/notifications';
import { useSelectedNetwork, useStringGetter } from '@/hooks'; import { useSelectedNetwork, useStringGetter } from '@/hooks';
import { useLocalNotifications } from '@/hooks/useLocalNotifications'; import { useLocalNotifications } from '@/hooks/useLocalNotifications';
import { AssetIcon } from '@/components/AssetIcon';
import { Icon, IconName } from '@/components/Icon'; import { Icon, IconName } from '@/components/Icon';
import { BlockRewardNotification } from '@/views/notifications/BlockRewardNotification';
import { TradeNotification } from '@/views/notifications/TradeNotification'; import { TradeNotification } from '@/views/notifications/TradeNotification';
import { TransferStatusNotification } from '@/views/notifications/TransferStatusNotification'; import { TransferStatusNotification } from '@/views/notifications/TransferStatusNotification';
@@ -81,7 +78,6 @@ export const notificationTypes: NotificationTypeConfig[] = [
body: abacusNotif.text ? stringGetter({ key: abacusNotif.text, params }) : '', body: abacusNotif.text ? stringGetter({ key: abacusNotif.text, params }) : '',
toastDuration: DEFAULT_TOAST_AUTO_CLOSE_MS, toastDuration: DEFAULT_TOAST_AUTO_CLOSE_MS,
toastSensitivity: 'foreground', toastSensitivity: 'foreground',
groupKey: abacusNotificationType,
renderCustomBody: ({ isToast, notification }) => ( renderCustomBody: ({ isToast, notification }) => (
<TradeNotification <TradeNotification
isToast={isToast} isToast={isToast}
@@ -95,29 +91,6 @@ export const notificationTypes: NotificationTypeConfig[] = [
); );
break; break;
} }
case 'blockReward': {
trigger(
abacusNotif.id,
{
icon: abacusNotif.image && <$Icon src={abacusNotif.image} alt="" />,
title: stringGetter({ key: abacusNotif.title }),
body: abacusNotif.text ? stringGetter({ key: abacusNotif.text, params }) : '',
toastDuration: DEFAULT_TOAST_AUTO_CLOSE_MS,
toastSensitivity: 'foreground',
groupKey: abacusNotificationType,
renderCustomBody: ({ isToast, notification }) => (
<BlockRewardNotification
isToast={isToast}
data={parsedData}
notification={notification}
/>
),
},
[abacusNotif.updateTimeInMilliseconds, abacusNotif.data],
true
);
break;
}
default: default:
trigger( trigger(
abacusNotif.id, abacusNotif.id,
@@ -127,7 +100,6 @@ export const notificationTypes: NotificationTypeConfig[] = [
body: abacusNotif.text ? stringGetter({ key: abacusNotif.text, params }) : '', body: abacusNotif.text ? stringGetter({ key: abacusNotif.text, params }) : '',
toastDuration: DEFAULT_TOAST_AUTO_CLOSE_MS, toastDuration: DEFAULT_TOAST_AUTO_CLOSE_MS,
toastSensitivity: 'foreground', toastSensitivity: 'foreground',
groupKey: abacusNotificationType,
}, },
[abacusNotif.updateTimeInMilliseconds, abacusNotif.data] [abacusNotif.updateTimeInMilliseconds, abacusNotif.data]
); );
@@ -179,20 +151,20 @@ export const notificationTypes: NotificationTypeConfig[] = [
useEffect(() => { useEffect(() => {
for (const transfer of transferNotifications) { for (const transfer of transferNotifications) {
const { fromChainId, status, txHash, toAmount, type } = transfer; const { fromChainId, status, txHash, toAmount } = transfer;
const isFinished = Boolean(status) && status?.squidTransactionStatus !== 'ongoing'; const isFinished = Boolean(status) && status?.squidTransactionStatus !== 'ongoing';
const icon = <Icon iconName={isFinished ? IconName.Transfer : IconName.Clock} />; const icon = <Icon iconName={isFinished ? IconName.Transfer : IconName.Clock} />;
const transferType = const type =
type ?? fromChainId === ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId fromChainId === ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId
? TransferNotificationTypes.Withdrawal ? 'withdrawal'
: TransferNotificationTypes.Deposit; : 'deposit';
const title = stringGetter({ const title = stringGetter({
key: { key: {
deposit: isFinished ? STRING_KEYS.DEPOSIT : STRING_KEYS.DEPOSIT_IN_PROGRESS, deposit: isFinished ? STRING_KEYS.DEPOSIT : STRING_KEYS.DEPOSIT_IN_PROGRESS,
withdrawal: isFinished ? STRING_KEYS.WITHDRAW : STRING_KEYS.WITHDRAW_IN_PROGRESS, withdrawal: isFinished ? STRING_KEYS.WITHDRAW : STRING_KEYS.WITHDRAW_IN_PROGRESS,
}[transferType], }[type],
}); });
const toChainEta = status?.toChain?.chainData?.estimatedRouteDuration || 0; const toChainEta = status?.toChain?.chainData?.estimatedRouteDuration || 0;
@@ -217,13 +189,12 @@ export const notificationTypes: NotificationTypeConfig[] = [
slotIcon={icon} slotIcon={icon}
slotTitle={title} slotTitle={title}
transfer={transfer} transfer={transfer}
type={transferType} type={type}
triggeredAt={transfer.triggeredAt} triggeredAt={transfer.triggeredAt}
notification={notification} notification={notification}
/> />
), ),
toastSensitivity: 'foreground', toastSensitivity: 'foreground',
groupKey: NotificationType.SquidTransfer,
}, },
[isFinished] [isFinished]
); );
@@ -234,58 +205,9 @@ export const notificationTypes: NotificationTypeConfig[] = [
return () => {}; return () => {};
}, },
}, },
{
type: NotificationType.ReleaseUpdates,
useTrigger: ({ trigger }) => {
const stringGetter = useStringGetter();
useEffect(() => {
trigger(
'rewards-and-full-trading-live',
{
icon: <AssetIcon symbol="DYDX" />,
title: stringGetter({ key: 'NOTIFICATIONS.RELEASE_REWARDS_AND_FULL_TRADING.TITLE' }),
body: stringGetter({
key: 'NOTIFICATIONS.RELEASE_REWARDS_AND_FULL_TRADING.BODY',
params: {
DOS_BLOGPOST: (
<$Link
href="https://www.dydxopsdao.com/blog/deep-dive-full-trading"
target="_blank"
rel="noopener noreferrer"
>
{stringGetter({ key: STRING_KEYS.HERE })}
</$Link>
),
TRADING_BLOGPOST: (
<$Link
href="https://dydx.exchange/blog/v4-full-trading"
target="_blank"
rel="noopener noreferrer"
>
{stringGetter({ key: STRING_KEYS.HERE })}
</$Link>
),
},
}),
toastSensitivity: 'foreground',
groupKey: NotificationType.ReleaseUpdates,
},
[]
);
}, [stringGetter]);
},
useNotificationAction: () => {
return () => {};
},
},
]; ];
const $Icon = styled.img` const $Icon = styled.img`
height: 1.5rem; height: 1.5rem;
width: 1.5rem; width: 1.5rem;
`; `;
const $Link = styled.a`
--link-color: var(--color-text-2);
`;
-1
View File
@@ -81,7 +81,6 @@ const useNotificationsContext = () => {
setNotificationPreferences({ setNotificationPreferences({
[NotificationType.AbacusGenerated]: true, [NotificationType.AbacusGenerated]: true,
[NotificationType.SquidTransfer]: true, [NotificationType.SquidTransfer]: true,
[NotificationType.ReleaseUpdates]: true,
version: LOCAL_STORAGE_VERSIONS[LocalStorageKey.NotificationPreferences], version: LOCAL_STORAGE_VERSIONS[LocalStorageKey.NotificationPreferences],
}); });
} }
-44
View File
@@ -1,44 +0,0 @@
import { useMemo } from 'react';
import { shallowEqual, useSelector } from 'react-redux';
import { DepthChartSeries, DepthChartDatum } from '@/constants/charts';
import { getCurrentMarketOrderbook } from '@/state/perpetualsSelectors';
import { MustBigNumber } from '@/lib/numbers';
export const useOrderbookValuesForDepthChart = () => {
const orderbook = useSelector(getCurrentMarketOrderbook, shallowEqual);
return useMemo(() => {
const bids = (orderbook?.bids?.toArray() ?? [])
.filter(Boolean)
.map((datum) => ({ ...datum, seriesKey: DepthChartSeries.Bids } as DepthChartDatum));
const asks = (orderbook?.asks?.toArray() ?? [])
.filter(Boolean)
.map((datum) => ({ ...datum, seriesKey: DepthChartSeries.Asks } as DepthChartDatum));
const lowestBid = bids[bids.length - 1];
const highestBid = bids[0];
const lowestAsk = asks[0];
const highestAsk = asks[asks.length - 1];
const midMarketPrice = orderbook?.midPrice;
const spread = MustBigNumber(lowestAsk?.price ?? 0).minus(highestBid?.price ?? 0);
const spreadPercent = orderbook?.spreadPercent;
return {
bids,
asks,
lowestBid,
highestBid,
lowestAsk,
highestAsk,
midMarketPrice,
spread,
spreadPercent,
orderbook,
};
}, [orderbook]);
};
+50
View File
@@ -0,0 +1,50 @@
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
import { useSelector } from 'react-redux';
import { Squid } from '@0xsquid/sdk';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { getSelectedNetwork } from '@/state/appSelectors';
export const NATIVE_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
export const STATUS_ERROR_GRACE_PERIOD = 300_000;
const useSquidContext = () => {
const selectedNetwork = useSelector(getSelectedNetwork);
const [_, setInitialized] = useState(false);
const initializeClient = async () => {
setInitialized(false);
if (!squid) return;
await squid.init();
setInitialized(true);
};
const squid = useMemo(
() =>
new Squid({
baseUrl: ENVIRONMENT_CONFIG_MAP[selectedNetwork]?.endpoints['0xsquid'],
integratorId: ENVIRONMENT_CONFIG_MAP[selectedNetwork]?.squidIntegratorId,
}),
[selectedNetwork]
);
useEffect(() => {
if (squid) {
initializeClient();
}
}, [squid]);
return squid;
};
type SquidContextType = ReturnType<typeof useSquidContext>;
const SquidContext = createContext<SquidContextType | undefined>(undefined);
SquidContext.displayName = '0xSquid';
export const SquidProvider = ({ ...props }) => (
<SquidContext.Provider value={useSquidContext()} {...props} />
);
export const useSquid = () => useContext(SquidContext);
+3 -21
View File
@@ -31,7 +31,6 @@ import { log } from '@/lib/telemetry';
import { useAccounts } from './useAccounts'; import { useAccounts } from './useAccounts';
import { useTokenConfigs } from './useTokenConfigs'; import { useTokenConfigs } from './useTokenConfigs';
import { useDydxClient } from './useDydxClient'; import { useDydxClient } from './useDydxClient';
import { hashFromTx } from '@/lib/hashfromTx';
type SubaccountContextType = ReturnType<typeof useSubaccountContext>; type SubaccountContextType = ReturnType<typeof useSubaccountContext>;
const SubaccountContext = createContext<SubaccountContextType>({} as SubaccountContextType); const SubaccountContext = createContext<SubaccountContextType>({} as SubaccountContextType);
@@ -294,29 +293,12 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
); );
const sendSquidWithdraw = useCallback( const sendSquidWithdraw = useCallback(
async (amount: number, payload: string, isCctp?: boolean) => { async (amount: number, payload: string) => {
const cctpWithdraw = () => {
return new Promise<string>((resolve, reject) =>
abacusStateManager.cctpWithdraw((success, error, data) => {
const parsedData = JSON.parse(data);
if (success && parsedData?.code == 0) {
resolve(parsedData?.transactionHash);
} else {
reject(error);
}
})
)
}
if (isCctp) {
return await cctpWithdraw();
}
if (!subaccountClient) { if (!subaccountClient) {
return; return;
} }
const tx = await sendSquidWithdrawFromSubaccount({ subaccountClient, amount, payload });
return hashFromTx(tx?.hash); return await sendSquidWithdrawFromSubaccount({ subaccountClient, amount, payload });
}, },
[subaccountClient, sendSquidWithdrawFromSubaccount] [subaccountClient, sendSquidWithdrawFromSubaccount]
); );
+46
View File
@@ -0,0 +1,46 @@
import { createContext, useContext, useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
import queryString from 'query-string';
class TestFlags {
public queryParams: queryString.ParsedQuery<string>;
constructor() {
this.queryParams = {};
}
setQueryParams(flags: queryString.ParsedQuery<string>) {
this.queryParams = flags;
}
get displayInitializingMarkets() {
return !!this.queryParams.displayInitializingMarkets;
}
}
export const testFlags = new TestFlags();
const useTestFlagsContext = () => {
const [queryParams, setQueryParams] = useState<queryString.ParsedQuery<string>>({});
const location = useLocation();
useEffect(() => {
const parsedQueryParams = queryString.parse(location.search.substring(-1));
testFlags.setQueryParams(parsedQueryParams);
setQueryParams(parsedQueryParams);
}, []);
return {
...queryParams,
};
};
type TestFlagsContextType = ReturnType<typeof useTestFlagsContext>;
const TestFlagsContext = createContext<TestFlagsContextType>({} as TestFlagsContextType);
TestFlagsContext.displayName = 'TestFlags';
export const TestFlagsProvider = ({ ...props }) => (
<TestFlagsContext.Provider value={useTestFlagsContext()} {...props} />
);
export const useTestFlags = () => useContext(TestFlagsContext);
-30
View File
@@ -1,30 +0,0 @@
import { getTradeFormInputs } from '@/state/inputsSelectors';
import { useEffect } from 'react';
import { shallowEqual, useSelector } from 'react-redux';
import { TradeInputField } from '@/constants/abacus';
import abacusStateManager from '@/lib/abacus';
export const useTradeFormInputs = () => {
const tradeFormInputValues = useSelector(getTradeFormInputs, shallowEqual);
const { limitPriceInput, triggerPriceInput, trailingPercentInput } = tradeFormInputValues;
useEffect(() => {
abacusStateManager.setTradeValue({
value: triggerPriceInput,
field: TradeInputField.triggerPrice,
});
}, [triggerPriceInput]);
useEffect(() => {
abacusStateManager.setTradeValue({ value: limitPriceInput, field: TradeInputField.limitPrice });
}, [limitPriceInput]);
useEffect(() => {
abacusStateManager.setTradeValue({
value: trailingPercentInput,
field: TradeInputField.trailingPercent,
});
}, [trailingPercentInput]);
};
+3 -20
View File
@@ -1,7 +1,6 @@
import { useCallback, useEffect, useState, useMemo } from 'react'; import { useCallback, useEffect, useState, useMemo } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { EvmDerivedAddresses } from '@/constants/account';
import { LocalStorageKey } from '@/constants/localStorage'; import { LocalStorageKey } from '@/constants/localStorage';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks'; import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
@@ -105,17 +104,11 @@ export const useWalletConnection = () => {
[walletConnectConfig, walletType, walletConnectionType] [walletConnectConfig, walletType, walletConnectionType]
); );
const { connectAsync: connectWagmi } = useConnectWagmi({ connector: wagmiConnector }); const { connectAsync: connectWagmi } = useConnectWagmi({ connector: wagmiConnector })
const { suggestAndConnect: connectGraz } = useConnectGraz(); const { suggestAndConnect: connectGraz } = useConnectGraz();
const [evmDerivedAddresses] = useLocalStorage({
key: LocalStorageKey.EvmDerivedAddresses,
defaultValue: {} as EvmDerivedAddresses,
});
const connectWallet = useCallback( const connectWallet = useCallback(
async ({ walletType, forceConnect }: { walletType?: WalletType; forceConnect?: boolean }) => { async ({ walletType }: { walletType: WalletType }) => {
if (!walletType) return { walletType, walletConnectionType };
const walletConnection = getWalletConnection({ walletType }); const walletConnection = getWalletConnection({ walletType });
try { try {
@@ -139,11 +132,7 @@ export const useWalletConnection = () => {
}); });
} }
} else { } else {
const isAccountConnected = Boolean( if (!isConnectedWagmi) {
evmAddress && evmDerivedAddresses[evmAddress]?.encryptedSignature
);
// if account connected (via remember me), do not show wagmi popup until forceConnect
if (!isConnectedWagmi && (forceConnect || !isAccountConnected)) {
await connectWagmi({ await connectWagmi({
connector: resolveWagmiConnector({ connector: resolveWagmiConnector({
walletType, walletType,
@@ -239,12 +228,6 @@ export const useWalletConnection = () => {
evmAddressWagmi, evmAddressWagmi,
signerWagmi, signerWagmi,
publicClientWagmi, publicClientWagmi,
isConnectedWagmi,
connectWallet: () =>
connectWallet({
walletType: selectedWalletType,
forceConnect: true,
}),
// Wallet connection (Cosmos) // Wallet connection (Cosmos)
dydxAddress, dydxAddress,
+3 -1
View File
@@ -1 +1,3 @@
<svg fill="none" height="10" viewBox="0 0 15 10" width="15" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="m.321829 1.09389c.200562-.192959.469529-.298401.747791-.29315.27827.00525.54307.120763.73621.32115l5.194 5.5132 5.19397-5.5132c.0944-.10408.2088-.188152.3363-.247234.1275-.059081.2655-.091968.406-.096713.1404-.004746.2804.018748.4116.069088s.2509.126504.3522.223979c.1012.09747.1818.21427.2371.34347.0552.12921.084.26819.0845.40871.0006.14052-.0271.27972-.0813.40936s-.1339.24707-.2344.34534l-5.94997 6.3c-.09795.10163-.21538.18245-.34527.23766-.1299.05521-.26959.08367-.41073.08367s-.28083-.02846-.41073-.08367c-.12989-.05521-.24732-.13603-.34527-.23766l-5.950001-6.3c-.192962-.20056-.29840394-.46953-.29315364-.74779.00525031-.27827.12076264-.54307.32115364-.73621z" fill="currentColor" fill-rule="evenodd"/></svg> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 6L7.83335 10.5L2 6" stroke="currentColor" stroke-width="2.25" stroke-linecap="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 840 B

After

Width:  |  Height:  |  Size: 205 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.95513 1.00169C7.89506 1.00645 7.83628 1.02054 7.78124 1.04337L1.31971 3.71042C1.2243 3.74983 1.14329 3.81414 1.08653 3.89553C1.02977 3.97691 0.999705 4.07186 1 4.16883V11.8366C1.00078 11.9327 1.03135 12.0265 1.08805 12.1069C1.14474 12.1873 1.22517 12.2508 1.31971 12.2898L7.78124 14.9568C7.85011 14.9853 7.92463 15 8 15C8.07536 15 8.14989 14.9853 8.21876 14.9568L14.6803 12.2898C14.7748 12.2508 14.8552 12.1873 14.9119 12.1069C14.9686 12.0265 14.9992 11.9327 15 11.8366V4.16883C15.0003 4.07186 14.9702 3.97691 14.9134 3.89553C14.8567 3.81414 14.7756 3.74983 14.6803 3.71042L8.21876 1.04337C8.13605 1.00911 8.04538 0.994778 7.95513 1.00169ZM8 2.04351L13.1378 4.16883L8 6.28894L2.86219 4.16883L8 2.04351ZM2.07693 4.93457L7.46153 7.15886V13.7328L2.07693 11.5084V4.93457ZM13.923 4.93457V11.5084L8.53846 13.7328V7.15886L13.923 4.93457Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 969 B

+1 -3
View File
@@ -19,6 +19,7 @@ export { default as CoinMarketCapIcon } from './logos/coinmarketcap.svg';
export { default as CoinsIcon } from './coins.svg'; 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 DepositIcon } from './deposit.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';
@@ -31,7 +32,6 @@ export { default as GiftboxIcon } from './giftbox.svg';
export { default as HelpCircleIcon } from './help-circle.svg'; export { default as HelpCircleIcon } from './help-circle.svg';
export { default as HideIcon } from './hide.svg'; export { default as HideIcon } from './hide.svg';
export { default as HistoryIcon } from './history.svg'; export { default as HistoryIcon } from './history.svg';
export { default as LeaderboardIcon } from './leaderboard.svg';
export { default as LinkOutIcon } from './link-out.svg'; export { default as LinkOutIcon } from './link-out.svg';
export { default as LockIcon } from './lock.svg'; export { default as LockIcon } from './lock.svg';
export { default as LogoShortIcon } from './logo-short'; export { default as LogoShortIcon } from './logo-short';
@@ -43,14 +43,12 @@ export { default as OrderbookIcon } from './orderbook.svg';
export { default as OverviewIcon } from './overview.svg'; export { default as OverviewIcon } from './overview.svg';
export { default as PencilIcon } from './pencil.svg'; export { default as PencilIcon } from './pencil.svg';
export { default as PlayIcon } from './play.svg'; export { default as PlayIcon } from './play.svg';
export { default as PlusIcon } from './plus.svg';
export { default as PortfolioIcon } from './portfolio.svg'; export { default as PortfolioIcon } from './portfolio.svg';
export { default as PositionsIcon } from './positions.svg'; export { default as PositionsIcon } from './positions.svg';
export { default as PriceChartIcon } from './price-chart.svg'; export { default as PriceChartIcon } from './price-chart.svg';
export { default as PrivacyIcon } from './privacy.svg'; export { default as PrivacyIcon } from './privacy.svg';
export { default as ProfileIcon } from './profile.svg'; export { default as ProfileIcon } from './profile.svg';
export { default as QrIcon } from './qr.svg'; export { default as QrIcon } from './qr.svg';
export { default as RewardStarIcon } from './reward-star.svg';
export { default as SearchIcon } from './search.svg'; export { default as SearchIcon } from './search.svg';
export { default as SendIcon } from './send.svg'; export { default as SendIcon } from './send.svg';
export { default as ShareIcon } from './share.svg'; export { default as ShareIcon } from './share.svg';
-3
View File
@@ -1,3 +0,0 @@
<svg width="13" height="14" viewBox="0 0 13 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.0996094 2.60156C0.0996094 2.07113 0.310323 1.56242 0.685396 1.18735C1.06047 0.812276 1.56918 0.601563 2.09961 0.601562H10.8996C11.43 0.601563 11.9387 0.812276 12.3138 1.18735C12.6889 1.56242 12.8996 2.07113 12.8996 2.60156C12.8996 3.132 12.6889 3.6407 12.3138 4.01578C11.9387 4.39085 11.43 4.60156 10.8996 4.60156H2.09961C1.56918 4.60156 1.06047 4.39085 0.685396 4.01578C0.310323 3.6407 0.0996094 3.132 0.0996094 2.60156ZM0.699609 6.26796C0.540479 6.26796 0.387867 6.33118 0.275345 6.4437C0.162823 6.55622 0.0996094 6.70883 0.0996094 6.86796C0.0996094 7.02709 0.162823 7.1797 0.275345 7.29223C0.387867 7.40475 0.540479 7.46796 0.699609 7.46796H12.2996C12.4587 7.46796 12.6114 7.40475 12.7239 7.29223C12.8364 7.1797 12.8996 7.02709 12.8996 6.86796C12.8996 6.70883 12.8364 6.55622 12.7239 6.4437C12.6114 6.33118 12.4587 6.26796 12.2996 6.26796H0.699609ZM0.699609 9.13196C0.540479 9.13196 0.387867 9.19518 0.275345 9.3077C0.162823 9.42022 0.0996094 9.57283 0.0996094 9.73196C0.0996094 9.89109 0.162823 10.0437 0.275345 10.1562C0.387867 10.2687 0.540479 10.332 0.699609 10.332H12.2996C12.4587 10.332 12.6114 10.2687 12.7239 10.1562C12.8364 10.0437 12.8996 9.89109 12.8996 9.73196C12.8996 9.57283 12.8364 9.42022 12.7239 9.3077C12.6114 9.19518 12.4587 9.13196 12.2996 9.13196H0.699609ZM0.699609 12.0016C0.540479 12.0016 0.387867 12.0648 0.275345 12.1773C0.162823 12.2898 0.0996094 12.4424 0.0996094 12.6016C0.0996094 12.7607 0.162823 12.9133 0.275345 13.0258C0.387867 13.1383 0.540479 13.2016 0.699609 13.2016H12.2996C12.4587 13.2016 12.6114 13.1383 12.7239 13.0258C12.8364 12.9133 12.8996 12.7607 12.8996 12.6016C12.8996 12.4424 12.8364 12.2898 12.7239 12.1773C12.6114 12.0648 12.4587 12.0016 12.2996 12.0016H0.699609Z" fill="currentColor"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

-1
View File
@@ -1 +0,0 @@
<svg fill="none" height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m6.75.75c0-.198912-.07902-.389678-.21967-.53033-.14065-.1406525-.33142-.21967-.53033-.21967s-.38968.0790175-.53033.21967c-.14065.140652-.21967.331418-.21967.53033v4.5h-4.5c-.198912 0-.389678.07902-.53033.21967-.1406525.14065-.21967.33142-.21967.53033s.0790175.38968.21967.53033c.140652.14065.331418.21967.53033.21967h4.5v4.5c0 .1989.07902.3897.21967.5303.14065.1407.33142.2197.53033.2197s.38968-.079.53033-.2197c.14065-.1406.21967-.3314.21967-.5303v-4.5h4.5c.1989 0 .3897-.07902.5303-.21967.1407-.14065.2197-.33142.2197-.53033s-.079-.38968-.2197-.53033c-.1406-.14065-.3314-.21967-.5303-.21967h-4.5z" fill="currentColor"/></svg>

Before

Width:  |  Height:  |  Size: 731 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 481 KiB

+2 -2
View File
@@ -11,13 +11,13 @@ import { DepositDialog } from '@/views/dialogs/DepositDialog';
import { DisconnectDialog } from '@/views/dialogs/DisconnectDialog'; import { DisconnectDialog } from '@/views/dialogs/DisconnectDialog';
import { ExchangeOfflineDialog } from '@/views/dialogs/ExchangeOfflineDialog'; import { ExchangeOfflineDialog } from '@/views/dialogs/ExchangeOfflineDialog';
import { HelpDialog } from '@/views/dialogs/HelpDialog'; import { HelpDialog } from '@/views/dialogs/HelpDialog';
import { ExternalLinkDialog } from '@/views/dialogs/ExternalLinkDialog';
import { ExternalNavKeplrDialog } from '@/views/dialogs/ExternalNavKeplrDialog'; import { ExternalNavKeplrDialog } from '@/views/dialogs/ExternalNavKeplrDialog';
import { MnemonicExportDialog } from '@/views/dialogs/MnemonicExportDialog'; import { MnemonicExportDialog } from '@/views/dialogs/MnemonicExportDialog';
import { MobileSignInDialog } from '@/views/dialogs/MobileSignInDialog'; import { MobileSignInDialog } from '@/views/dialogs/MobileSignInDialog';
import { OnboardingDialog } from '@/views/dialogs/OnboardingDialog'; import { OnboardingDialog } from '@/views/dialogs/OnboardingDialog';
import { PreferencesDialog } from '@/views/dialogs/PreferencesDialog'; import { PreferencesDialog } from '@/views/dialogs/PreferencesDialog';
import { RateLimitDialog } from '@/views/dialogs/RateLimitDialog'; import { RateLimitDialog } from '@/views/dialogs/RateLimitDialog';
import { ReceiveDialog } from '@/views/dialogs/ReceiveDialog';
import { RestrictedGeoDialog } from '@/views/dialogs/RestrictedGeoDialog'; import { RestrictedGeoDialog } from '@/views/dialogs/RestrictedGeoDialog';
import { TradeDialog } from '@/views/dialogs/TradeDialog'; import { TradeDialog } from '@/views/dialogs/TradeDialog';
import { TransferDialog } from '@/views/dialogs/TransferDialog'; import { TransferDialog } from '@/views/dialogs/TransferDialog';
@@ -54,13 +54,13 @@ export const DialogManager = () => {
[DialogTypes.FillDetails]: <FillDetailsDialog {...modalProps} />, [DialogTypes.FillDetails]: <FillDetailsDialog {...modalProps} />,
[DialogTypes.Help]: <HelpDialog {...modalProps} />, [DialogTypes.Help]: <HelpDialog {...modalProps} />,
[DialogTypes.ExternalNavKeplr]: <ExternalNavKeplrDialog {...modalProps} />, [DialogTypes.ExternalNavKeplr]: <ExternalNavKeplrDialog {...modalProps} />,
[DialogTypes.ExternalLink]: <ExternalLinkDialog {...modalProps} />,
[DialogTypes.MnemonicExport]: <MnemonicExportDialog {...modalProps} />, [DialogTypes.MnemonicExport]: <MnemonicExportDialog {...modalProps} />,
[DialogTypes.MobileSignIn]: <MobileSignInDialog {...modalProps} />, [DialogTypes.MobileSignIn]: <MobileSignInDialog {...modalProps} />,
[DialogTypes.Onboarding]: <OnboardingDialog {...modalProps} />, [DialogTypes.Onboarding]: <OnboardingDialog {...modalProps} />,
[DialogTypes.OrderDetails]: <OrderDetailsDialog {...modalProps} />, [DialogTypes.OrderDetails]: <OrderDetailsDialog {...modalProps} />,
[DialogTypes.Preferences]: <PreferencesDialog {...modalProps} />, [DialogTypes.Preferences]: <PreferencesDialog {...modalProps} />,
[DialogTypes.RateLimit]: <RateLimitDialog {...modalProps} />, [DialogTypes.RateLimit]: <RateLimitDialog {...modalProps} />,
[DialogTypes.Receive]: <ReceiveDialog {...modalProps} />,
[DialogTypes.RestrictedGeo]: <RestrictedGeoDialog {...modalProps} />, [DialogTypes.RestrictedGeo]: <RestrictedGeoDialog {...modalProps} />,
[DialogTypes.RestrictedWallet]: <RestrictedWalletDialog {...modalProps} />, [DialogTypes.RestrictedWallet]: <RestrictedWalletDialog {...modalProps} />,
[DialogTypes.Trade]: <TradeDialog {...modalProps} />, [DialogTypes.Trade]: <TradeDialog {...modalProps} />,
+2 -4
View File
@@ -1,7 +1,7 @@
import styled, { type AnyStyledComponent, css } from 'styled-components'; import styled, { type AnyStyledComponent, css } from 'styled-components';
import { AbacusApiStatus } from '@/constants/abacus'; import { AbacusApiStatus } from '@/constants/abacus';
import { ButtonSize, ButtonType } from '@/constants/buttons'; import { ButtonSize } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization'; import { STRING_KEYS } from '@/constants/localization';
import { ENVIRONMENT_CONFIG_MAP, isDev } from '@/constants/networks'; import { ENVIRONMENT_CONFIG_MAP, isDev } from '@/constants/networks';
@@ -55,12 +55,10 @@ export const FooterDesktop = () => {
} }
> >
<Styled.FooterButton <Styled.FooterButton
type={statusPage ? ButtonType.Link : ButtonType.Button}
slotLeft={<Styled.StatusDot exchangeStatus={exchangeStatus} />} slotLeft={<Styled.StatusDot exchangeStatus={exchangeStatus} />}
slotRight={statusPage && <LinkOutIcon />} slotRight={statusPage && <LinkOutIcon />}
size={ButtonSize.XSmall} size={ButtonSize.XSmall}
state={{ isDisabled: !statusPage }} state={{ isDisabled: !statusPage }}
href={statusPage}
> >
{label} {label}
</Styled.FooterButton> </Styled.FooterButton>
@@ -134,7 +132,7 @@ Styled.StatusDot = styled.div<{ exchangeStatus: ExchangeStatus }>`
Styled.FooterButton = styled(Button)` Styled.FooterButton = styled(Button)`
--button-height: 1.5rem; --button-height: 1.5rem;
--button-radius: 0.25rem; --button-radius: 0.25rem;
--button-backgroundColor: transparent; --button-backgroundColor: var(--color-layer-2);
--button-border: none; --button-border: none;
--button-textColor: var(--color-text-0); --button-textColor: var(--color-text-0);
+13 -29
View File
@@ -1,6 +1,7 @@
import styled, { type AnyStyledComponent } from 'styled-components'; import styled, { type AnyStyledComponent } from 'styled-components';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { ButtonAction, ButtonSize } from '@/constants/buttons';
import { DialogTypes } from '@/constants/dialogs'; import { DialogTypes } from '@/constants/dialogs';
import { STRING_KEYS } from '@/constants/localization'; import { STRING_KEYS } from '@/constants/localization';
import { DEFAULT_MARKETID } from '@/constants/markets'; import { DEFAULT_MARKETID } from '@/constants/markets';
@@ -10,8 +11,8 @@ import { useShouldShowFooter, useStringGetter } from '@/hooks';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { NavigationMenu } from '@/components/NavigationMenu'; import { NavigationMenu } from '@/components/NavigationMenu';
import { Icon, IconName } from '@/components/Icon'; import { Icon } from '@/components/Icon';
import { BellIcon, MarketsIcon, PortfolioIcon, ProfileIcon } from '@/icons'; import { BellIcon, MarketsIcon, PlayIcon, PortfolioIcon, ProfileIcon, TradeIcon } from '@/icons';
import { IconButton } from '@/components/IconButton'; import { IconButton } from '@/components/IconButton';
import { calculateCanAccountTrade } from '@/state/accountCalculators'; import { calculateCanAccountTrade } from '@/state/accountCalculators';
@@ -41,9 +42,11 @@ export const FooterMobile = () => {
value: 'trade', value: 'trade',
label: stringGetter({ key: STRING_KEYS.TRADE }), label: stringGetter({ key: STRING_KEYS.TRADE }),
slotBefore: ( slotBefore: (
<Styled.StartIcon> <Styled.IconButton
<Icon iconName={IconName.Trade} /> iconComponent={TradeIcon}
</Styled.StartIcon> size={ButtonSize.Large}
action={ButtonAction.Primary}
/>
), ),
href: `${AppRoute.Trade}/${marketId ?? DEFAULT_MARKETID}`, href: `${AppRoute.Trade}/${marketId ?? DEFAULT_MARKETID}`,
} }
@@ -51,9 +54,11 @@ export const FooterMobile = () => {
value: 'onboarding', value: 'onboarding',
label: stringGetter({ key: STRING_KEYS.ONBOARDING }), label: stringGetter({ key: STRING_KEYS.ONBOARDING }),
slotBefore: ( slotBefore: (
<Styled.StartIcon> <Styled.IconButton
<Icon iconName={IconName.Play} /> iconComponent={PlayIcon}
</Styled.StartIcon> size={ButtonSize.Large}
action={ButtonAction.Primary}
/>
), ),
onClick: () => dispatch(openDialog({ type: DialogTypes.Onboarding })), onClick: () => dispatch(openDialog({ type: DialogTypes.Onboarding })),
}, },
@@ -163,24 +168,3 @@ Styled.IconButton = styled(IconButton)`
Styled.Icon = styled(Icon)` Styled.Icon = styled(Icon)`
font-size: 1.5rem; font-size: 1.5rem;
`; `;
Styled.StartIcon = styled.div`
display: inline-flex;
flex-direction: row;
justify-content: center;
align-items: center;
margin-top: -0.25rem;
width: 3.5rem;
height: 3.5rem;
color: var(--color-text-2);
background-color: var(--color-accent);
border: solid var(--border-width) var(--color-border-white);
border-radius: 50%;
svg {
width: 1.5rem;
height: 1.5rem;
}
`;
+5 -16
View File
@@ -1,6 +1,6 @@
import styled, { type AnyStyledComponent } from 'styled-components'; import styled, { type AnyStyledComponent } from 'styled-components';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch } from 'react-redux';
import { ButtonShape } from '@/constants/buttons'; import { ButtonShape } from '@/constants/buttons';
import { DialogTypes } from '@/constants/dialogs'; import { DialogTypes } from '@/constants/dialogs';
@@ -8,10 +8,6 @@ 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 { headerMixins } from '@/styles/headerMixins';
import { layoutMixins } from '@/styles/layoutMixins';
import breakpoints from '@/styles/breakpoints';
import { useTokenConfigs, useStringGetter, useURLConfigs } from '@/hooks'; import { useTokenConfigs, useStringGetter, useURLConfigs } from '@/hooks';
import { Icon, IconName } from '@/components/Icon'; import { Icon, IconName } from '@/components/Icon';
@@ -25,7 +21,10 @@ import { NotificationsMenu } from '@/views/menus/NotificationsMenu';
import { LanguageSelector } from '@/views/menus/LanguageSelector'; import { LanguageSelector } from '@/views/menus/LanguageSelector';
import { openDialog } from '@/state/dialogs'; import { openDialog } from '@/state/dialogs';
import { getHasSeenLaunchIncentives } from '@/state/configsSelectors';
import { headerMixins } from '@/styles/headerMixins';
import { layoutMixins } from '@/styles/layoutMixins';
import breakpoints from '@/styles/breakpoints';
export const HeaderDesktop = () => { export const HeaderDesktop = () => {
const stringGetter = useStringGetter(); const stringGetter = useStringGetter();
@@ -33,8 +32,6 @@ export const HeaderDesktop = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { chainTokenLabel } = useTokenConfigs(); const { chainTokenLabel } = useTokenConfigs();
const hasSeenLaunchIncentives = useSelector(getHasSeenLaunchIncentives);
const navItems = [ const navItems = [
{ {
group: 'navigation', group: 'navigation',
@@ -58,7 +55,6 @@ export const HeaderDesktop = () => {
value: chainTokenLabel, value: chainTokenLabel,
label: chainTokenLabel, label: chainTokenLabel,
href: `/${chainTokenLabel}`, href: `/${chainTokenLabel}`,
slotAfter: !hasSeenLaunchIncentives && <Styled.UnreadIndicator />,
}, },
{ {
value: 'MORE', value: 'MORE',
@@ -242,10 +238,3 @@ Styled.IconButton = styled(IconButton)<{ size?: string }>`
--button-icon-size: 1rem; --button-icon-size: 1rem;
--button-padding: 0 0.5em; --button-padding: 0 0.5em;
`; `;
Styled.UnreadIndicator = styled.div`
width: 0.4375rem;
height: 0.4375rem;
border-radius: 50%;
background-color: var(--color-accent);
`;
+112
View File
@@ -0,0 +1,112 @@
import { useMemo } from 'react';
import styled, { css } from 'styled-components';
import { NotificationStatus } from '@/constants/notifications';
import { ButtonSize } from '@/constants/buttons';
import { useNotifications } from '@/hooks/useNotifications';
import { useBreakpoints } from '@/hooks/useBreakpoints';
import { Button } from '@/components/Button';
import { Toast } from '@/components/Toast';
import { ToastArea } from '@/components/ToastArea';
type StyleProps = {
className?: string;
};
const MAX_TOASTS = 10;
export const NotificationsToastArea = ({ className }: StyleProps) => {
const {
notifications,
getKey,
getDisplayData,
markUnseen,
markSeen,
isMenuOpen,
onNotificationAction,
} = useNotifications();
const { isMobile } = useBreakpoints();
const notificationMap = useMemo(() => {
return (
Object.values(notifications)
// Sort by time of first trigger
.sort(
(n1, n2) =>
n1.timestamps[NotificationStatus.Triggered]! -
n2.timestamps[NotificationStatus.Triggered]!
)
.map((notification) => ({
notification,
key: getKey(notification),
displayData: getDisplayData(notification),
}))
.filter(({ displayData }) => displayData)
.slice(-MAX_TOASTS)
);
}, [notifications, getKey, getDisplayData]);
if (isMenuOpen) return null;
return (
<StyledToastArea swipeDirection={isMobile ? 'up' : 'right'} className={className}>
{notificationMap.map(({ notification, key, displayData }, idx) => (
<StyledToast
key={key}
layer={notificationMap.length - 1 - idx}
isOpen={notification.status < NotificationStatus.Unseen}
notification={notification}
slotIcon={displayData.icon}
slotTitle={displayData.title}
slotTitleLeft={displayData.slotTitleLeft}
slotTitleRight={displayData.slotTitleRight}
slotDescription={displayData.body}
slotCustomContent={displayData.renderCustomBody?.({ isToast: true, notification })}
onClick={() => onNotificationAction(notification)}
slotAction={
<Button size={ButtonSize.Small} onClick={() => onNotificationAction(notification)}>
{displayData.actionDescription}
</Button>
}
actionDescription={displayData.actionDescription}
actionAltText={displayData.actionAltText}
duration={displayData.toastDuration ?? Infinity}
sensitivity={displayData.toastSensitivity}
setIsOpen={(isOpen, isClosedFromTimeout) => {
if (!isOpen)
if (isClosedFromTimeout)
// Toast timer expired without user interaction
markUnseen(notification);
// Toast interacted with or dismissed
else markSeen(notification);
}}
lastUpdated={notification.timestamps[notification.status]}
/>
))}
</StyledToastArea>
);
};
const StyledToastArea = styled(ToastArea)`
position: absolute;
width: min(17.5rem, 100%);
inset: 0 0 0 auto;
padding: 0.75rem 0.75rem 0.75rem 0;
mask-image: linear-gradient(to left, transparent, white 0.5rem);
`;
const StyledToast = styled(Toast)<{ layer: number }>`
// Stacked toast
position: absolute;
top: 0;
left: 0;
right: 0;
${({ layer }) => css`
right: calc(${layer} * -2px);
top: calc(${layer} * 2px);
`}
`;
@@ -1,150 +0,0 @@
import { useState } from 'react';
import styled, { css } from 'styled-components';
import {
type Notification,
type NotificationDisplayData,
NotificationStatus,
} from '@/constants/notifications';
import { ButtonShape, ButtonSize } from '@/constants/buttons';
import { useNotifications } from '@/hooks/useNotifications';
import { useBreakpoints } from '@/hooks/useBreakpoints';
import { ChevronLeftIcon } from '@/icons';
import { breakpoints } from '@/styles';
import { Button } from '@/components/Button';
import { Toast } from '@/components/Toast';
import { ToastArea } from '@/components/ToastArea';
import { ToggleButton } from '@/components/ToggleButton';
type ElementProps = {
notifications: {
notification: Notification<any, any>;
key: string;
displayData: NotificationDisplayData;
}[];
};
type StyleProps = {
className?: string;
};
export const NotificationStack = ({ notifications, className }: ElementProps & StyleProps) => {
const [shouldStackNotifications, setshouldStackNotifications] = useState(true);
const { markUnseen, markSeen, onNotificationAction } = useNotifications();
const { isMobile } = useBreakpoints();
const hasMultipleToasts = notifications.length > 1;
return (
<StyledToastArea
swipeDirection={isMobile ? 'up' : 'right'}
className={className}
size={notifications.length}
>
{hasMultipleToasts && (
<StyledToggleButton
shape={ButtonShape.Pill}
size={ButtonSize.XSmall}
isPressed={shouldStackNotifications}
onPressedChange={() => setshouldStackNotifications(!shouldStackNotifications)}
>
<ChevronLeftIcon />
</StyledToggleButton>
)}
{notifications.map(({ notification, key, displayData }, idx) => (
<StyledToast
key={key}
isStacked={idx > 0 && shouldStackNotifications}
isOpen={notification.status < NotificationStatus.Unseen}
layer={idx}
notification={notification}
slotIcon={displayData.icon}
slotTitle={displayData.title}
slotTitleLeft={displayData.slotTitleLeft}
slotTitleRight={displayData.slotTitleRight}
slotDescription={displayData.body}
slotCustomContent={displayData.renderCustomBody?.({ isToast: true, notification })}
onClick={() => onNotificationAction(notification)}
slotAction={
<Button size={ButtonSize.Small} onClick={() => onNotificationAction(notification)}>
{displayData.actionDescription}
</Button>
}
actionDescription={displayData.actionDescription}
actionAltText={displayData.actionAltText}
duration={displayData.toastDuration ?? Infinity}
sensitivity={displayData.toastSensitivity}
setIsOpen={(isOpen: boolean, isClosedFromTimeout?: boolean) => {
if (!isOpen)
if (isClosedFromTimeout)
// Toast timer expired without user interaction
markUnseen(notification);
// Toast interacted with or dismissed
else markSeen(notification);
}}
lastUpdated={notification.timestamps[notification.status]}
/>
))}
</StyledToastArea>
);
};
const StyledToastArea = styled(ToastArea)<{ size: number }>`
position: relative;
${({ size }) =>
size &&
css`
padding-bottom: calc(${size - 1} * 2px);
`}
`;
const StyledToast = styled(Toast)<{ isStacked?: boolean; layer: number }>`
// Stacked toast
${({ isStacked, layer }) =>
isStacked
? css`
position: absolute;
left: 0;
top: calc(${layer} * 2px);
right: 0;
`
: css`
margin-bottom: 0.75rem;
`}
`;
const StyledToggleButton = styled(ToggleButton)<{ isPressed: boolean }>`
z-index: 2;
pointer-events: auto;
display: none;
position: absolute;
top: -0.5rem;
left: calc(50% - 0.75rem);
--button-width: 2rem;
--button-height: 1rem;
${StyledToastArea}:hover & {
display: flex;
}
> svg {
width: 4px;
margin-top: 1px;
transform: rotate(-90deg);
${({ isPressed }) =>
!isPressed &&
css`
transform: rotate(90deg);
`}
}
@media ${breakpoints.mobile} {
display: flex;
left: calc(50% - 2rem);
--button-width: 4rem;
--button-height: 2rem;
}
`;
@@ -1,71 +0,0 @@
import { useMemo } from 'react';
import { groupBy } from 'lodash';
import styled from 'styled-components';
import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins';
import { NotificationStatus } from '@/constants/notifications';
import { useNotifications } from '@/hooks/useNotifications';
import { NotificationStack } from './NotifcationStack';
type StyleProps = {
className?: string;
};
const MAX_TOASTS = 10;
export const NotificationsToastArea = ({ className }: StyleProps) => {
const { notifications, getKey, getDisplayData, isMenuOpen } = useNotifications();
const notificationMapByType = useMemo(() => {
const notificationMap = Object.values(notifications)
// Sort by time of first trigger
.sort(
(n1, n2) =>
n1.timestamps[NotificationStatus.Triggered]! -
n2.timestamps[NotificationStatus.Triggered]!
)
.map((notification) => ({
notification,
key: getKey(notification),
displayData: getDisplayData(notification),
}))
.filter(
({ displayData, notification }) =>
displayData && notification.status < NotificationStatus.Unseen
)
.slice(-MAX_TOASTS);
return groupBy(notificationMap, (notification) => notification.displayData?.groupKey);
}, [notifications, getKey, getDisplayData]);
if (isMenuOpen) return null;
return (
<StyledToastArea className={className}>
{Object.keys(notificationMapByType).map((groupKey) => (
<NotificationStack notifications={notificationMapByType[groupKey]} key={groupKey} />
))}
</StyledToastArea>
);
};
const StyledToastArea = styled.div`
${layoutMixins.scrollArea}
position: absolute;
width: min(17.5rem, 100%);
inset: 0 0 0 auto;
padding: 0.75rem 0.75rem 0.75rem 0;
mask-image: linear-gradient(to left, transparent, white 0.5rem);
pointer-events: none;
@media ${breakpoints.mobile} {
width: 100%;
position: fixed;
}
`;
+3 -172
View File
@@ -1,8 +1,7 @@
import Abacus, { type Nullable } from '@dydxprotocol/v4-abacus'; import Abacus, { type Nullable } from '@dydxprotocol/v4-abacus';
import Long from 'long'; import Long from 'long';
import type { IndexedTx } from '@cosmjs/stargate'; import type { IndexedTx } from '@cosmjs/stargate';
import { GAS_MULTIPLIER, encodeJson } from '@dydxprotocol/v4-client-js'; import { encodeJson } from '@dydxprotocol/v4-client-js';
import { EncodeObject } from '@cosmjs/proto-signing';
import { import {
CompositeClient, CompositeClient,
@@ -10,7 +9,6 @@ import {
type LocalWallet, type LocalWallet,
Network, Network,
NetworkOptimizer, NetworkOptimizer,
NobleClient,
SubaccountClient, SubaccountClient,
ValidatorConfig, ValidatorConfig,
OrderType, OrderType,
@@ -42,24 +40,17 @@ import { openDialog } from '@/state/dialogs';
import { StatefulOrderError } from '../errors'; import { StatefulOrderError } from '../errors';
import { bytesToBigInt } from '../numbers'; import { bytesToBigInt } from '../numbers';
import { log } from '../telemetry'; import { log } from '../telemetry';
import { hashFromTx } from '../hashfromTx';
class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol { class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
private compositeClient: CompositeClient | undefined; private compositeClient: CompositeClient | undefined;
private nobleClient: NobleClient | undefined;
private store: RootStore | undefined; private store: RootStore | undefined;
private localWallet: LocalWallet | undefined; private localWallet: LocalWallet | undefined;
private nobleWallet: LocalWallet | undefined;
constructor() { constructor() {
this.compositeClient = undefined; this.compositeClient = undefined;
this.store = undefined; this.store = undefined;
} }
get isNobleClientConnected(): boolean {
return this.nobleClient?.isConnected ?? false;
}
setStore(store: RootStore): void { setStore(store: RootStore): void {
this.store = store; this.store = store;
} }
@@ -68,17 +59,6 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
this.localWallet = localWallet; this.localWallet = localWallet;
} }
setNobleWallet(nobleWallet: LocalWallet) {
try {
this.nobleWallet = nobleWallet;
if (this.nobleClient) {
this.nobleClient.connect(nobleWallet);
}
} catch (e) {
log('DydxChainTransactions/setNobleWallet', e);
}
}
async connectNetwork( async connectNetwork(
paramsInJson: Nullable<string>, paramsInJson: Nullable<string>,
callback: (p0: Nullable<string>) => void callback: (p0: Nullable<string>) => void
@@ -90,7 +70,6 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
websocketUrl, websocketUrl,
validatorUrl, validatorUrl,
chainId, chainId,
nobleValidatorUrl,
USDC_DENOM, USDC_DENOM,
USDC_DECIMALS, USDC_DECIMALS,
USDC_GAS_DENOM, USDC_GAS_DENOM,
@@ -122,15 +101,6 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
this.compositeClient = compositeClient; this.compositeClient = compositeClient;
try {
if (nobleValidatorUrl) {
this.nobleClient = new NobleClient(nobleValidatorUrl);
if (this.nobleWallet) await this.nobleClient.connect(this.nobleWallet);
}
} catch (e) {
log('DydxChainTransactions/connectNetwork/NobleClient', e);
}
// Dispatch custom event to notify other parts of the app that the network has been connected // Dispatch custom event to notify other parts of the app that the network has been connected
const customEvent = new CustomEvent('abacus:connectNetwork', { const customEvent = new CustomEvent('abacus:connectNetwork', {
detail: parsedParams, detail: parsedParams,
@@ -216,8 +186,8 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
timeInForce as OrderTimeInForce, timeInForce as OrderTimeInForce,
goodTilTimeInSeconds ?? 0, goodTilTimeInSeconds ?? 0,
execution as OrderExecution, execution as OrderExecution,
postOnly ?? undefined, postOnly,
reduceOnly ?? undefined, reduceOnly,
triggerPrice ?? undefined triggerPrice ?? undefined
); );
@@ -355,122 +325,6 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
} }
} }
async sendNobleIBC(params: { msgTypeUrl: string; msg: any }): Promise<string> {
if (!this.nobleClient?.isConnected) {
throw new Error('Missing nobleClient or localWallet');
}
try {
const ibcMsg = {
typeUrl: params.msgTypeUrl, // '/ibc.applications.transfer.v1.MsgTransfer',
value: params.msg,
};
const fee = await this.nobleClient.simulateTransaction([ibcMsg]);
// take out fee from amount before sweeping
const amount =
parseInt(ibcMsg.value.token.amount, 10) -
Math.floor(parseInt(fee.amount[0].amount, 10) * GAS_MULTIPLIER);
if (amount <= 0) {
throw new Error('noble balance does not cover fees');
}
ibcMsg.value.token.amount = amount.toString();
const tx = await this.nobleClient.send([ibcMsg]);
const parsedTx = this.parseToPrimitives(tx);
return JSON.stringify(parsedTx);
} catch (error) {
log('DydxChainTransactions/sendNobleIBC', error);
return JSON.stringify({
error,
});
}
}
async withdrawToNobleIBC(params: {
subaccountNumber: number;
amount: string;
ibcPayload: string;
}): Promise<string> {
if (!this.compositeClient || !this.localWallet) {
throw new Error('Missing compositeClient or localWallet');
}
const { subaccountNumber, amount, ibcPayload } = params ?? {};
const parsedIbcPayload: {
msgTypeUrl: string;
msg: any;
} = ibcPayload ? JSON.parse(atob(ibcPayload)) : undefined;
try {
const msg = this.compositeClient.withdrawFromSubaccountMessage(
new SubaccountClient(this.localWallet, subaccountNumber),
parseFloat(amount).toFixed(this.compositeClient.validatorClient.config.denoms.USDC_DECIMALS)
);
const ibcMsg: EncodeObject = {
typeUrl: parsedIbcPayload.msgTypeUrl,
value: parsedIbcPayload.msg,
};
const tx = await this.compositeClient.send(
this.localWallet,
() => Promise.resolve([msg, ibcMsg]),
false
);
return JSON.stringify({
txHash: hashFromTx(tx?.hash),
});
} catch (error) {
log('DydxChainTransactions/withdrawToNobleIBC', error);
return JSON.stringify({
error,
});
}
}
async cctpWithdraw(params: { typeUrl: string; value: any }): Promise<string> {
if (!this.nobleClient?.isConnected) {
throw new Error('Missing nobleClient or localWallet');
}
try {
const ibcMsg = {
typeUrl: params.typeUrl, // '/circle.cctp.v1.MsgDepositForBurn',
value: params.value,
};
const fee = await this.nobleClient.simulateTransaction([ibcMsg]);
// take out fee from amount before sweeping
const amount =
parseInt(ibcMsg.value.amount, 10) -
Math.floor(parseInt(fee.amount[0].amount, 10) * GAS_MULTIPLIER);
if (amount <= 0) {
throw new Error('noble balance does not cover fees');
}
ibcMsg.value.amount = amount.toString();
const tx = await this.nobleClient.send([ibcMsg]);
const parsedTx = this.parseToPrimitives(tx);
return JSON.stringify(parsedTx);
} catch (error) {
log('DydxChainTransactions/cctpWithdraw', error);
return JSON.stringify({
error,
});
}
}
async transaction( async transaction(
type: TransactionTypes, type: TransactionTypes,
paramsInJson: Abacus.Nullable<string>, paramsInJson: Abacus.Nullable<string>,
@@ -500,22 +354,6 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
callback(result); callback(result);
break; break;
} }
case TransactionType.SendNobleIBC: {
const result = await this.sendNobleIBC(params);
callback(result);
break;
}
case TransactionType.WithdrawToNobleIBC: {
const result = await this.withdrawToNobleIBC(params);
callback(result);
break;
}
case TransactionType.CctpWithdraw: {
const result = await this.cctpWithdraw(params);
callback(result);
break;
break;
}
default: { default: {
break; break;
} }
@@ -603,13 +441,6 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
const parseDelegations = this.parseToPrimitives(delegations); const parseDelegations = this.parseToPrimitives(delegations);
callback(JSON.stringify(parseDelegations)); callback(JSON.stringify(parseDelegations));
break; break;
case QueryType.GetNobleBalance:
if (this.nobleClient?.isConnected) {
const nobleBalance = await this.nobleClient.getAccountBalance('uusdc');
const parsedNobleBalance = this.parseToPrimitives(nobleBalance);
callback(JSON.stringify(parsedNobleBalance));
}
break;
default: default:
break; break;
} }
+16 -33
View File
@@ -26,14 +26,12 @@ import {
} from '@/constants/abacus'; } from '@/constants/abacus';
import { DEFAULT_MARKETID } from '@/constants/markets'; import { DEFAULT_MARKETID } from '@/constants/markets';
import { CURRENT_ABACUS_DEPLOYMENT, type DydxNetwork, isMainnet } from '@/constants/networks'; import { CURRENT_ABACUS_DEPLOYMENT, type DydxNetwork } from '@/constants/networks';
import { CLEARED_SIZE_INPUTS, CLEARED_TRADE_INPUTS } from '@/constants/trade';
import type { RootStore } from '@/state/_store'; import type { RootStore } from '@/state/_store';
import { setTradeFormInputs } from '@/state/inputs';
import { getInputTradeOptions, getTransferInputs } from '@/state/inputsSelectors';
import { testFlags } from '@/lib/testFlags'; import { getInputTradeOptions } from '@/state/inputsSelectors';
import { getTransferInputs } from '@/state/inputsSelectors';
import AbacusRest from './rest'; import AbacusRest from './rest';
import AbacusAnalytics from './analytics'; import AbacusAnalytics from './analytics';
@@ -45,7 +43,6 @@ import AbacusFormatter from './formatter';
import AbacusThreading from './threading'; import AbacusThreading from './threading';
import AbacusFileSystem from './filesystem'; import AbacusFileSystem from './filesystem';
import { LocaleSeparators } from '../numbers'; import { LocaleSeparators } from '../numbers';
class AbacusStateManager { class AbacusStateManager {
private store: RootStore | undefined; private store: RootStore | undefined;
private currentMarket: string | undefined; private currentMarket: string | undefined;
@@ -83,13 +80,10 @@ class AbacusStateManager {
this.abacusFormatter this.abacusFormatter
); );
const appConfigs = AbacusAppConfig.Companion.forWeb;
appConfigs.squidVersion = AbacusAppConfig.SquidVersion.V2;
this.stateManager = new AsyncAbacusStateManager( this.stateManager = new AsyncAbacusStateManager(
'', '',
CURRENT_ABACUS_DEPLOYMENT, CURRENT_ABACUS_DEPLOYMENT,
appConfigs, AbacusAppConfig.Companion.forWeb,
ioImplementations, ioImplementations,
uiImplementations, uiImplementations,
// @ts-ignore // @ts-ignore
@@ -138,8 +132,6 @@ class AbacusStateManager {
this.setTradeValue({ value: null, field: TradeInputField.limitPrice }); this.setTradeValue({ value: null, field: TradeInputField.limitPrice });
} }
this.store?.dispatch(setTradeFormInputs(CLEARED_TRADE_INPUTS));
if (shouldResetSize) { if (shouldResetSize) {
this.setTradeValue({ value: null, field: TradeInputField.size }); this.setTradeValue({ value: null, field: TradeInputField.size });
this.setTradeValue({ value: null, field: TradeInputField.usdcSize }); this.setTradeValue({ value: null, field: TradeInputField.usdcSize });
@@ -147,8 +139,6 @@ class AbacusStateManager {
if (needsLeverage) { if (needsLeverage) {
this.setTradeValue({ value: null, field: TradeInputField.leverage }); this.setTradeValue({ value: null, field: TradeInputField.leverage });
} }
this.store?.dispatch(setTradeFormInputs(CLEARED_SIZE_INPUTS));
} }
}; };
@@ -171,15 +161,6 @@ class AbacusStateManager {
this.setTransferValue({ value: null, field: TransferInputField.usdcSize }); this.setTransferValue({ value: null, field: TransferInputField.usdcSize });
}; };
resetInputState = () => {
this.clearTransferInputValues();
this.setTransferValue({
field: TransferInputField.type,
value: null,
});
this.clearTradeInputValues();
};
// ------ Set Data ------ // // ------ Set Data ------ //
setStore = (store: RootStore) => { setStore = (store: RootStore) => {
this.store = store; this.store = store;
@@ -194,12 +175,6 @@ class AbacusStateManager {
} }
}; };
setNobleWallet = (nobleWallet?: LocalWallet) => {
if (nobleWallet) {
this.chainTransactions.setNobleWallet(nobleWallet);
}
};
setTransfersSourceAddress = (evmAddress: string) => { setTransfersSourceAddress = (evmAddress: string) => {
this.stateManager.sourceAddress = evmAddress; this.stateManager.sourceAddress = evmAddress;
}; };
@@ -243,6 +218,18 @@ class AbacusStateManager {
this.abacusFormatter.setLocaleSeparators({ group, decimal }); this.abacusFormatter.setLocaleSeparators({ group, decimal });
}; };
setTransferStatus = ({
hash,
fromChainId,
toChainId,
}: {
hash: string;
fromChainId?: string;
toChainId?: string;
}) => {
this.stateManager.transferStatus(hash, fromChainId, toChainId);
};
// ------ Transactions ------ // // ------ Transactions ------ //
placeOrder = ( placeOrder = (
@@ -270,10 +257,6 @@ class AbacusStateManager {
) => void ) => void
) => this.stateManager.cancelOrder(orderId, callback); ) => this.stateManager.cancelOrder(orderId, callback);
cctpWithdraw = (
callback: (success: boolean, parsingError: Nullable<ParsingError>, data: string) => void
): void => this.stateManager.commitCCTPWithdraw(callback);
// ------ Utils ------ // // ------ Utils ------ //
getHistoricalPnlPeriod = (): Nullable<HistoricalPnlPeriods> => getHistoricalPnlPeriod = (): Nullable<HistoricalPnlPeriods> =>
this.stateManager.historicalPnlPeriod; this.stateManager.historicalPnlPeriod;
+1 -1
View File
@@ -10,7 +10,7 @@ import {
} from '@/constants/websocket'; } from '@/constants/websocket';
import { lastSuccessfulWebsocketRequestByOrigin } from '@/hooks/useAnalytics'; import { lastSuccessfulWebsocketRequestByOrigin } from '@/hooks/useAnalytics';
import { testFlags } from '@/lib/testFlags'; import { testFlags } from '@/hooks/useTestFlags';
import { subscriptionsByChannelId } from '@/lib/tradingView/dydxfeed/cache'; import { subscriptionsByChannelId } from '@/lib/tradingView/dydxfeed/cache';
import { mapCandle } from '@/lib/tradingView/utils'; import { mapCandle } from '@/lib/tradingView/utils';
-3
View File
@@ -1,3 +0,0 @@
export const hashFromTx = (
txHash: string | Uint8Array
): string => `0x${Buffer.from(txHash).toString('hex')}`;
-48
View File
@@ -1,48 +0,0 @@
import { isMainnet } from '@/constants/networks';
import { GetStatus, StatusResponse } from '@0xsquid/sdk';
export const NATIVE_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
export const STATUS_ERROR_GRACE_PERIOD = 300_000;
const getSquidStatusUrl = (isV2: boolean) => {
if (isV2) {
return isMainnet
? 'https://v2.api.squidrouter.com/v2/status'
: 'https://testnet.v2.api.squidrouter.com/v2/status';
}
return isMainnet
? 'https://api.squidrouter.com/v1/status'
: 'https://testnet.api.squidrouter.com/v1/status';
};
export const fetchSquidStatus = async (
params: GetStatus,
isV2?: boolean,
integratorId?: string
): Promise<StatusResponse> => {
const parsedParams: { [key: string]: string } = {
transactionId: params.transactionId,
fromChainId: String(params.fromChainId),
toChainId: String(params.toChainId),
};
if (isV2) parsedParams.bridgeType = 'cctp';
const url = `${getSquidStatusUrl(!!isV2)}?${new URLSearchParams(parsedParams).toString()}`;
const response = await fetch(url, {
headers: {
"x-integrator-id": integratorId || 'dYdX-api'
},
});
if (!response.ok) {
const error = await response.json();
throw new Error(error);
}
return response.json();
};
export const getNobleChainId = () => {
return isMainnet ? 'noble-1' : 'grand-1';
}
-27
View File
@@ -1,27 +0,0 @@
class TestFlags {
public queryParams: { [key: string]: string };
constructor() {
this.queryParams = {};
const hash = window.location.hash;
const queryIndex = hash.indexOf('?');
if (queryIndex === -1) return;
const queryParamsString = hash.substring(queryIndex + 1);
const params = new URLSearchParams(queryParamsString);
for (const [key, value] of params) {
this.queryParams[key.toLowerCase()] = value;
}
}
get displayInitializingMarkets() {
return !!this.queryParams.displayinitializingmarkets;
}
get showMobileSignInOption() {
return !!this.queryParams.mobilesignin;
}
}
export const testFlags = new TestFlags();
+3 -8
View File
@@ -1,4 +1,4 @@
import { createConfig, configureChains, mainnet, Chain } from 'wagmi'; import { createConfig, configureChains, mainnet, Chain, Connector, usePublicClient } from 'wagmi';
import { goerli } from 'wagmi/chains'; import { goerli } from 'wagmi/chains';
import { import {
@@ -26,9 +26,6 @@ import {
fantomTestnet, fantomTestnet,
celo, celo,
celoAlfajores, celoAlfajores,
scroll,
kava,
sepolia,
} from 'viem/chains'; } from 'viem/chains';
import { alchemyProvider } from 'wagmi/providers/alchemy'; import { alchemyProvider } from 'wagmi/providers/alchemy';
@@ -56,7 +53,7 @@ import { isTruthy } from './isTruthy';
export const WAGMI_SUPPORTED_CHAINS: Chain[] = [ export const WAGMI_SUPPORTED_CHAINS: Chain[] = [
mainnet, mainnet,
goerli, goerli,
sepolia,
arbitrum, arbitrum,
arbitrumGoerli, arbitrumGoerli,
avalanche, avalanche,
@@ -81,8 +78,6 @@ export const WAGMI_SUPPORTED_CHAINS: Chain[] = [
fantomTestnet, fantomTestnet,
celo, celo,
celoAlfajores, celoAlfajores,
scroll,
kava,
]; ];
const { chains, publicClient, webSocketPublicClient } = configureChains( const { chains, publicClient, webSocketPublicClient } = configureChains(
@@ -151,7 +146,7 @@ const getConnectors = (walletConnectConfig: WalletConnectConfig) => [
new CoinbaseWalletConnector({ new CoinbaseWalletConnector({
chains, chains,
options: { options: {
appName: 'dYdX', appName: 'wagmi',
reloadOnDisconnect: false, reloadOnDisconnect: false,
}, },
}), }),
+1 -3
View File
@@ -1,6 +1,4 @@
import { DialogPlacement } from '@/components/Dialog'; import { DialogPlacement } from '@/components/Dialog';
import { NotificationsMenu } from '@/views/menus/NotificationsMenu'; import { NotificationsMenu } from '@/views/menus/NotificationsMenu';
const AlertsPage = () => <NotificationsMenu placement={DialogPlacement.Inline} />; export const AlertsPage = () => <NotificationsMenu placement={DialogPlacement.Inline} />;
export default AlertsPage;
+1 -3
View File
@@ -2,7 +2,7 @@ import styled, { AnyStyledComponent } from 'styled-components';
import { articleMixins } from '@/styles/articleMixins'; import { articleMixins } from '@/styles/articleMixins';
const PrivacyPolicyPage = () => ( export const PrivacyPolicyPage = () => (
<Styled.Article> <Styled.Article>
<header> <header>
<h1>Privacy Policy</h1> <h1>Privacy Policy</h1>
@@ -10,8 +10,6 @@ const PrivacyPolicyPage = () => (
</Styled.Article> </Styled.Article>
); );
export default PrivacyPolicyPage;
const Styled: Record<string, AnyStyledComponent> = {}; const Styled: Record<string, AnyStyledComponent> = {};
Styled.Article = styled.article` Styled.Article = styled.article`
+46 -125
View File
@@ -2,16 +2,12 @@ import styled, { AnyStyledComponent, css } from 'styled-components';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { useEnsName } from 'wagmi'; import { useEnsName } from 'wagmi';
import { useNavigate } from 'react-router-dom';
import { ButtonSize } from '@/constants/buttons'; import { ButtonSize } from '@/constants/buttons';
import { TransferInputField, TransferType } from '@/constants/abacus';
import { layoutMixins } from '@/styles/layoutMixins';
import { Details } from '@/components/Details'; import { Details } from '@/components/Details';
import { FillsTable, FillsTableColumnKey } from '@/views/tables/FillsTable'; import { FillsTable, FillsTableColumnKey } from '@/views/tables/FillsTable';
import { Icon, IconName } from '@/components/Icon'; import { IconName } from '@/components/Icon';
import { IconButton, type IconButtonProps } from '@/components/IconButton'; import { IconButton, type IconButtonProps } from '@/components/IconButton';
import { Panel } from '@/components/Panel'; import { Panel } from '@/components/Panel';
import { Toolbar } from '@/components/Toolbar'; import { Toolbar } from '@/components/Toolbar';
@@ -20,25 +16,22 @@ import { OnboardingState } from '@/constants/account';
import { DialogTypes } from '@/constants/dialogs'; 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 } from '@/constants/wallets'; import { wallets, WalletType } from '@/constants/wallets';
import { useAccounts, useStringGetter, useTokenConfigs } 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';
import abacusStateManager from '@/lib/abacus';
import { isTruthy } from '@/lib/isTruthy'; import { isTruthy } from '@/lib/isTruthy';
import { truncateAddress } from '@/lib/wallet'; import { truncateAddress } from '@/lib/wallet';
import { DYDXBalancePanel } from './rewards/DYDXBalancePanel'; import { layoutMixins } from '@/styles/layoutMixins';
import { MigratePanel } from './rewards/MigratePanel';
const ENS_CHAIN_ID = 1; // Ethereum const ENS_CHAIN_ID = 1; // Ethereum
const Profile = () => { const Profile = () => {
const stringGetter = useStringGetter(); const stringGetter = useStringGetter();
const dispatch = useDispatch(); const dispatch = useDispatch();
const navigate = useNavigate();
const onboardingState = useSelector(getOnboardingState); const onboardingState = useSelector(getOnboardingState);
const isConnected = onboardingState !== OnboardingState.Disconnected; const isConnected = onboardingState !== OnboardingState.Disconnected;
@@ -53,48 +46,17 @@ const Profile = () => {
const actions = [ const actions = [
{ {
key: 'deposit', key: 'settings',
label: stringGetter({ key: STRING_KEYS.DEPOSIT }), label: stringGetter({ key: STRING_KEYS.SETTINGS }),
icon: { iconName: IconName.Deposit }, icon: { iconName: IconName.Gear },
onClick: () => { href: AppRoute.Settings,
dispatch(
openDialog({
type: DialogTypes.ManageFunds,
dialogProps: {
selectedTransferType: TransferType.deposit.rawValue,
},
})
);
},
}, },
{ isConnected && {
key: 'withdraw', key: 'transfers',
label: stringGetter({ key: STRING_KEYS.WITHDRAW }), label: stringGetter({ key: STRING_KEYS.MANAGE_FUNDS }),
icon: { iconName: IconName.Withdraw }, icon: { iconName: IconName.Transfer },
onClick: () => { onClick: () => {
dispatch( dispatch(openDialog({ type: DialogTypes.ManageFunds }));
openDialog({
type: DialogTypes.ManageFunds,
dialogProps: {
selectedTransferType: TransferType.withdrawal.rawValue,
},
})
);
},
},
{
key: 'transfer',
label: stringGetter({ key: STRING_KEYS.TRANSFER }),
icon: { iconName: IconName.Send },
onClick: () => {
dispatch(
openDialog({
type: DialogTypes.ManageFunds,
dialogProps: {
selectedTransferType: TransferType.transferOut.rawValue,
},
})
);
}, },
}, },
isConnected isConnected
@@ -107,9 +69,9 @@ const Profile = () => {
}, },
} }
: { : {
key: 'connect', key: 'wallet',
label: stringGetter({ key: STRING_KEYS.CONNECT }), label: stringGetter({ key: STRING_KEYS.WALLET }),
icon: { iconName: IconName.Transfer }, icon: { iconComponent: wallets[walletType || WalletType.OtherWallet].icon },
onClick: () => { onClick: () => {
dispatch(openDialog({ type: DialogTypes.Onboarding })); dispatch(openDialog({ type: DialogTypes.Onboarding }));
}, },
@@ -145,7 +107,12 @@ const Profile = () => {
{actions.map(({ key, label, href, icon, onClick }) => { {actions.map(({ key, label, href, icon, onClick }) => {
const action = ( const action = (
<> <>
<Styled.ActionButton {...icon} size={ButtonSize.Large} onClick={onClick} /> <Styled.ActionButton
{...icon}
size={ButtonSize.Large}
onClick={onClick}
isCloseIcon={icon.iconName === IconName.Close}
/>
<span>{label}</span> <span>{label}</span>
</> </>
); );
@@ -158,47 +125,8 @@ const Profile = () => {
); );
})} })}
</Styled.Actions> </Styled.Actions>
<Styled.EqualGrid>
<Styled.PanelButton
slotHeader={
<Styled.InlineRow>
<Icon iconName={IconName.Gear} />
{stringGetter({ key: STRING_KEYS.SETTINGS })}
</Styled.InlineRow>
}
onClick={() => navigate(AppRoute.Settings)}
/>
<Styled.PanelButton
slotHeader={
<Styled.InlineRow>
<Icon iconName={IconName.HelpCircle} />
{stringGetter({ key: STRING_KEYS.HELP })}
</Styled.InlineRow>
}
onClick={() => dispatch(openDialog({ type: DialogTypes.Help }))}
/>
</Styled.EqualGrid>
<MigratePanel />
<DYDXBalancePanel />
<Styled.EqualGrid> <Styled.EqualGrid>
<Styled.RewardsPanel
slotHeaderContent="Trading Rewards"
href={`/${chainTokenLabel}`}
hasSeparator
>
<Styled.Details
items={[
{
key: 'week-rewards',
label: stringGetter({ key: STRING_KEYS.THIS_WEEK }),
value: '-',
},
]}
layout="grid"
/>
</Styled.RewardsPanel>
<Panel <Panel
slotHeaderContent={stringGetter({ key: STRING_KEYS.FEES })} slotHeaderContent={stringGetter({ key: STRING_KEYS.FEES })}
href={`${AppRoute.Portfolio}/${PortfolioRoute.Fees}`} href={`${AppRoute.Portfolio}/${PortfolioRoute.Fees}`}
@@ -213,6 +141,19 @@ const Profile = () => {
layout="grid" layout="grid"
/> />
</Panel> </Panel>
<Styled.RewardsPanel
slotHeaderContent={stringGetter({ key: STRING_KEYS.REWARDS })}
href={`/${chainTokenLabel}`}
hasSeparator
>
<Styled.Details
items={[
{ key: 'maker', label: stringGetter({ key: STRING_KEYS.YOU_WILL_EARN }), value: '-' },
{ key: 'taker', label: stringGetter({ key: STRING_KEYS.EPOCH_ENDS_IN }), value: '-' },
]}
layout="grid"
/>
</Styled.RewardsPanel>
</Styled.EqualGrid> </Styled.EqualGrid>
<Styled.TablePanel <Styled.TablePanel
@@ -242,7 +183,7 @@ Styled.MobileProfileLayout = styled.div`
${layoutMixins.contentContainerPage} ${layoutMixins.contentContainerPage}
gap: 1rem; gap: 1rem;
padding: 1.25rem 0.9rem; padding: 1.25rem;
`; `;
Styled.Header = styled.header` Styled.Header = styled.header`
@@ -307,21 +248,19 @@ Styled.Actions = styled(Toolbar)`
} }
`; `;
Styled.ActionButton = styled(IconButton)<{ iconName?: IconName }>` Styled.ActionButton = styled(IconButton)<{ isCloseIcon?: boolean }>`
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
${({ iconName }) => ${({ isCloseIcon }) =>
iconName === IconName.Close isCloseIcon &&
? css` css`
--button-textColor: var(--color-negative); --button-textColor: var(--color-negative);
--button-icon-size: 0.75em;
` svg {
: iconName === IconName.Transfer && width: 0.875em;
css` height: 0.875em;
--button-icon-size: 1.25em; }
--button-textColor: var(--color-text-2); `}
--button-backgroundColor: var(--color-accent);
`}
`; `;
Styled.EqualGrid = styled.div` Styled.EqualGrid = styled.div`
@@ -336,13 +275,6 @@ Styled.Details = styled(Details)`
`; `;
Styled.RewardsPanel = styled(Panel)` Styled.RewardsPanel = styled(Panel)`
align-self: flex-start;
&,
> * {
height: 100%;
}
dl { dl {
--details-grid-numColumns: 1; --details-grid-numColumns: 1;
} }
@@ -377,14 +309,3 @@ Styled.TablePanel = styled(Panel)`
} }
} }
`; `;
Styled.InlineRow = styled.div`
${layoutMixins.inlineRow}
padding: 1rem;
gap: 0.5rem;
`;
Styled.PanelButton = styled(Panel)`
--panel-paddingY: 0
--panel-paddingX:0;
`;
+1 -3
View File
@@ -2,7 +2,7 @@ import styled, { AnyStyledComponent } from 'styled-components';
import { articleMixins } from '@/styles/articleMixins'; import { articleMixins } from '@/styles/articleMixins';
const TermsOfUsePage = () => ( export const TermsOfUsePage = () => (
<Styled.Article> <Styled.Article>
<header> <header>
<h1>Sample Terms of Use</h1> <h1>Sample Terms of Use</h1>
@@ -1076,8 +1076,6 @@ const TermsOfUsePage = () => (
</Styled.Article> </Styled.Article>
); );
export default TermsOfUsePage;
const Styled: Record<string, AnyStyledComponent> = {}; const Styled: Record<string, AnyStyledComponent> = {};
Styled.Article = styled.article` Styled.Article = styled.article`
+57 -83
View File
@@ -1,40 +1,34 @@
import { lazy, Suspense } from 'react';
import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import styled, { type AnyStyledComponent } from 'styled-components'; import styled, { type AnyStyledComponent } from 'styled-components';
import { Navigate, Route, Routes } from 'react-router-dom'; import { Navigate, Route, Routes } from 'react-router-dom';
import { OnboardingState } from '@/constants/account'; import { OnboardingState } from '@/constants/account';
import { ButtonAction } from '@/constants/buttons';
import { DialogTypes } from '@/constants/dialogs'; import { DialogTypes } from '@/constants/dialogs';
import { STRING_KEYS } from '@/constants/localization'; import { STRING_KEYS } from '@/constants/localization';
import { HistoryRoute, PortfolioRoute } from '@/constants/routes'; import { HistoryRoute, PortfolioRoute } from '@/constants/routes';
import { useAccountBalance, useBreakpoints, useDocumentTitle, useStringGetter } from '@/hooks'; import { useAccountBalance, useBreakpoints, useDocumentTitle, useStringGetter } from '@/hooks';
import { layoutMixins } from '@/styles/layoutMixins';
import { FillsTable, FillsTableColumnKey } from '@/views/tables/FillsTable'; import { FillsTable, FillsTableColumnKey } from '@/views/tables/FillsTable';
import { FundingPaymentsTable } from '@/views/tables/FundingPaymentsTable'; import { FundingPaymentsTable } from '@/views/tables/FundingPaymentsTable';
import { TransferHistoryTable } from '@/views/tables/TransferHistoryTable'; import { TransferHistoryTable } from '@/views/tables/TransferHistoryTable';
import { Button } from '@/components/Button';
import { Icon, IconName } from '@/components/Icon'; import { Icon, IconName } from '@/components/Icon';
import { NavigationMenu } from '@/components/NavigationMenu'; import { NavigationMenu } from '@/components/NavigationMenu';
import { Tag, TagType } from '@/components/Tag';
import { WithSidebar } from '@/components/WithSidebar'; import { WithSidebar } from '@/components/WithSidebar';
import { getOnboardingState, getSubaccount, getTradeInfoNumbers } from '@/state/accountSelectors'; import { getOnboardingState, getSubaccount } from '@/state/accountSelectors';
import { openDialog } from '@/state/dialogs'; import { openDialog } from '@/state/dialogs';
import { shortenNumberForDisplay } from '@/lib/numbers';
import { PortfolioNavMobile } from './PortfolioNavMobile'; import { PortfolioNavMobile } from './PortfolioNavMobile';
import { LoadingSpace } from '@/components/Loading/LoadingSpinner'; import { Overview } from './Overview';
import { Positions } from './Positions';
import { Orders } from './Orders';
import { Fees } from './Fees';
import { History } from './History';
const Overview = lazy(() => import('./Overview').then((module) => ({ default: module.Overview }))); import { layoutMixins } from '@/styles/layoutMixins';
const Positions = lazy(() => import { Button } from '@/components/Button';
import('./Positions').then((module) => ({ default: module.Positions })) import { ButtonAction } from '@/constants/buttons';
);
const Orders = lazy(() => import('./Orders').then((module) => ({ default: module.Orders })));
const Fees = lazy(() => import('./Fees').then((module) => ({ default: module.Fees })));
const History = lazy(() => import('./History').then((module) => ({ default: module.History })));
export default () => { export default () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
@@ -45,60 +39,54 @@ export default () => {
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {}; const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
const { nativeTokenBalance } = useAccountBalance(); const { nativeTokenBalance } = useAccountBalance();
const { numTotalPositions, numTotalOpenOrders } = useSelector(getTradeInfoNumbers, shallowEqual) || {};
const numPositions = shortenNumberForDisplay(numTotalPositions);
const numOrders = shortenNumberForDisplay(numTotalOpenOrders);
const usdcBalance = freeCollateral?.current || 0; const usdcBalance = freeCollateral?.current || 0;
useDocumentTitle(stringGetter({ key: STRING_KEYS.PORTFOLIO })); useDocumentTitle(stringGetter({ key: STRING_KEYS.PORTFOLIO }));
const routesComponent = ( const routesComponent = (
<Suspense fallback={<LoadingSpace id="portfolio" />}> <Routes>
<Routes> <Route path={PortfolioRoute.Overview} element={<Overview />} />
<Route path={PortfolioRoute.Overview} element={<Overview />} /> <Route path={PortfolioRoute.Positions} element={<Positions />} />
<Route path={PortfolioRoute.Positions} element={<Positions />} /> <Route path={PortfolioRoute.Orders} element={<Orders />} />
<Route path={PortfolioRoute.Orders} element={<Orders />} /> <Route path={PortfolioRoute.Fees} element={<Fees />} />
<Route path={PortfolioRoute.Fees} element={<Fees />} /> <Route path={PortfolioRoute.History} element={<History />}>
<Route path={PortfolioRoute.History} element={<History />}> <Route index path="*" element={<Navigate to={HistoryRoute.Trades} />} />
<Route index path="*" element={<Navigate to={HistoryRoute.Trades} />} /> <Route
<Route path={HistoryRoute.Trades}
path={HistoryRoute.Trades} element={
element={ <FillsTable
<FillsTable columnKeys={
columnKeys={ isTablet
isTablet ? [
? [ FillsTableColumnKey.Time,
FillsTableColumnKey.Time, FillsTableColumnKey.TypeAmount,
FillsTableColumnKey.TypeAmount, FillsTableColumnKey.PriceFee,
FillsTableColumnKey.PriceFee, ]
] : [
: [ FillsTableColumnKey.Time,
FillsTableColumnKey.Time, FillsTableColumnKey.Market,
FillsTableColumnKey.Market, FillsTableColumnKey.Side,
FillsTableColumnKey.Side, FillsTableColumnKey.AmountPrice,
FillsTableColumnKey.AmountPrice, FillsTableColumnKey.TotalFee,
FillsTableColumnKey.TotalFee, FillsTableColumnKey.Type,
FillsTableColumnKey.Type, FillsTableColumnKey.Liquidity,
FillsTableColumnKey.Liquidity, ]
] }
} withOuterBorder={isNotTablet}
withOuterBorder={isNotTablet} />
/> }
} />
/> <Route
<Route path={HistoryRoute.Transfers}
path={HistoryRoute.Transfers} element={<TransferHistoryTable withOuterBorder={isNotTablet} />}
element={<TransferHistoryTable withOuterBorder={isNotTablet} />} />
/> <Route
<Route path={HistoryRoute.Payments}
path={HistoryRoute.Payments} element={<FundingPaymentsTable withOuterBorder={isNotTablet} />}
element={<FundingPaymentsTable withOuterBorder={isNotTablet} />} />
/> </Route>
</Route> <Route path="*" element={<Navigate to={PortfolioRoute.Overview} replace />} />
<Route path="*" element={<Navigate to={PortfolioRoute.Overview} replace />} /> </Routes>
</Routes>
</Suspense>
); );
return isTablet ? ( return isTablet ? (
@@ -125,28 +113,14 @@ export default () => {
}, },
{ {
value: PortfolioRoute.Positions, value: PortfolioRoute.Positions,
slotBefore: <Styled.Icon iconName={IconName.Positions} />, slotBefore: <Styled.Icon iconName={IconName.Cube} />,
label: ( label: stringGetter({ key: STRING_KEYS.POSITIONS }),
<>
{stringGetter({ key: STRING_KEYS.POSITIONS })}
{numPositions > 0 && (
<Tag type={TagType.Number}> {numPositions} </Tag>
)}
</>
),
href: PortfolioRoute.Positions, href: PortfolioRoute.Positions,
}, },
{ {
value: PortfolioRoute.Orders, value: PortfolioRoute.Orders,
slotBefore: <Styled.Icon iconName={IconName.OrderPending} />, slotBefore: <Styled.Icon iconName={IconName.OrderPending} />,
label: ( label: stringGetter({ key: STRING_KEYS.ORDERS }),
<>
{stringGetter({ key: STRING_KEYS.ORDERS })}
{numOrders > 0 && (
<Tag type={TagType.Number}> {numOrders} </Tag>
)}
</>
),
href: PortfolioRoute.Orders, href: PortfolioRoute.Orders,
}, },
{ {
@@ -217,7 +191,7 @@ Styled.SideBar = styled.div`
Styled.Footer = styled.div` Styled.Footer = styled.div`
${layoutMixins.row} ${layoutMixins.row}
flex-wrap: wrap; flex-wrap: wrap;
padding: 1rem; padding: 1rem;
gap: 0.5rem; gap: 0.5rem;
+10 -6
View File
@@ -32,14 +32,14 @@ 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={chainTokenLabel} /> <AssetIcon symbol={chainTokenLabel} />
{chainTokenLabel} {chainTokenLabel}
</Styled.Title> </Styled.Title>
<Styled.ActionButtons> <Styled.ReceiveAndTransferButtons>
{!canAccountTrade ? ( {!canAccountTrade ? (
<OnboardingTriggerButton size={ButtonSize.Small} /> <OnboardingTriggerButton size={ButtonSize.Small} />
) : ( ) : (
@@ -52,7 +52,7 @@ export const DYDXBalancePanel = () => {
{stringGetter({ key: STRING_KEYS.TRANSFER })} {stringGetter({ key: STRING_KEYS.TRANSFER })}
</Button> </Button>
)} )}
</Styled.ActionButtons> </Styled.ReceiveAndTransferButtons>
</Styled.Header> </Styled.Header>
} }
> >
@@ -108,16 +108,20 @@ 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; gap: 1rem;
padding: var(--panel-paddingY) var(--panel-paddingX) 0; padding: 1rem 1.5rem 0;
`; `;
Styled.Title = styled.h3` Styled.Title = styled.h3`
@@ -130,7 +134,7 @@ Styled.Title = styled.h3`
} }
`; `;
Styled.ActionButtons = styled(Toolbar)` Styled.ReceiveAndTransferButtons = styled(Toolbar)`
${layoutMixins.inlineRow} ${layoutMixins.inlineRow}
--stickyArea-topHeight: max-content; --stickyArea-topHeight: max-content;
gap: 0.5rem; gap: 0.5rem;
-291
View File
@@ -1,291 +0,0 @@
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { useQuery } from 'react-query';
import styled, { AnyStyledComponent } from 'styled-components';
import { STRING_KEYS } from '@/constants/localization';
import { ButtonAction } from '@/constants/buttons';
import { DialogTypes } from '@/constants/dialogs';
import breakpoints from '@/styles/breakpoints';
import { useAccounts, useBreakpoints, useStringGetter } from '@/hooks';
import { layoutMixins } from '@/styles/layoutMixins';
import { Panel } from '@/components/Panel';
import { Button } from '@/components/Button';
import { Output, OutputType } from '@/components/Output';
import { Icon, IconName } from '@/components/Icon';
import { Tag, TagSize } from '@/components/Tag';
import { markLaunchIncentivesSeen } from '@/state/configs';
import { openDialog } from '@/state/dialogs';
import { log } from '@/lib/telemetry';
const SEASON_NUMBER = 2;
export const LaunchIncentivesPanel = () => {
const { isNotTablet } = useBreakpoints();
const dispatch = useDispatch();
useEffect(() => {
dispatch(markLaunchIncentivesSeen());
}, []);
return isNotTablet ? (
<Styled.Panel slotHeader={<LaunchIncentivesTitle />} slotRight={<EstimatedRewards />}>
<LaunchIncentivesContent />
</Styled.Panel>
) : (
<Styled.Panel>
<Styled.Column>
<EstimatedRewards />
<LaunchIncentivesTitle />
<LaunchIncentivesContent />
</Styled.Column>
</Styled.Panel>
);
};
const LaunchIncentivesTitle = () => {
const stringGetter = useStringGetter();
return (
<Styled.Title>
{stringGetter({
key: STRING_KEYS.LAUNCH_INCENTIVES_TITLE,
params: {
FOR_V4: <Styled.ForV4>{stringGetter({ key: STRING_KEYS.FOR_V4 })}</Styled.ForV4>,
},
})}
<Styled.NewTag size={TagSize.Medium}>{stringGetter({ key: STRING_KEYS.NEW })}</Styled.NewTag>
</Styled.Title>
);
};
const EstimatedRewards = () => {
const stringGetter = useStringGetter();
const { dydxAddress } = useAccounts();
const { data, isLoading } = useQuery({
enabled: !!dydxAddress,
queryKey: `launch_incentives_rewards_${dydxAddress ?? ''}_${SEASON_NUMBER}`,
queryFn: async () => {
if (!dydxAddress) return undefined;
const resp = await fetch(
`https://cloud.chaoslabs.co/query/api/dydx/points/${dydxAddress}?n=${SEASON_NUMBER}`
);
return (await resp.json())?.incentivePoints;
},
onError: (error: Error) => log('LaunchIncentives/fetchPoints', error),
});
return (
<Styled.EstimatedRewardsCard>
<Styled.EstimatedRewardsCardContent>
<div>
<span>{stringGetter({ key: STRING_KEYS.ESTIMATED_REWARDS })}</span>
<Styled.Season>
{stringGetter({
key: STRING_KEYS.LAUNCH_INCENTIVES_SEASON_NUM,
params: { SEASON_NUMBER },
})}
</Styled.Season>
</div>
<Styled.Points>
<Output type={OutputType.Number} value={data} isLoading={isLoading} fractionDigits={2} />
{data !== undefined && stringGetter({ key: STRING_KEYS.POINTS })}
</Styled.Points>
</Styled.EstimatedRewardsCardContent>
<Styled.Image src="/rewards-stars.svg" />
</Styled.EstimatedRewardsCard>
);
};
const LaunchIncentivesContent = () => {
const stringGetter = useStringGetter();
const dispatch = useDispatch();
return (
<Styled.Column>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.LAUNCH_INCENTIVES_DESCRIPTION })}{' '}
</Styled.Description>
<Styled.ChaosLabsLogo src="/logos/chaos-labs.svg" />
<Styled.ButtonRow>
<Styled.AboutButton
action={ButtonAction.Base}
onClick={() => {
dispatch(
openDialog({
type: DialogTypes.ExternalLink,
dialogProps: { link: 'https://dydx.exchange/blog/v4-full-trading' },
})
);
}}
slotRight={<Styled.LinkOutIcon iconName={IconName.LinkOut} />}
>
{stringGetter({ key: STRING_KEYS.ABOUT })}
</Styled.AboutButton>
<Styled.Button
action={ButtonAction.Primary}
onClick={() => {
dispatch(
openDialog({
type: DialogTypes.ExternalLink,
dialogProps: { link: 'https://community.chaoslabs.xyz/dydx-v4/risk/leaderboard' },
})
);
}}
slotRight={<Styled.LinkOutIcon iconName={IconName.LinkOut} />}
slotLeft={<Icon iconName={IconName.Leaderboard} />}
>
{stringGetter({ key: STRING_KEYS.LEADERBOARD })}
</Styled.Button>
</Styled.ButtonRow>
</Styled.Column>
);
};
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Panel = styled(Panel)`
background-color: var(--color-layer-4);
width: 100%;
`;
Styled.ForV4 = styled.span`
color: var(--color-text-0);
`;
Styled.Title = styled.h3`
${layoutMixins.inlineRow}
font: var(--font-medium-book);
color: var(--color-text-2);
@media ${breakpoints.notTablet} {
padding: var(--panel-paddingY) var(--panel-paddingX) 0;
}
`;
Styled.Description = styled.div`
color: var(--color-text-0);
--link-color: var(--color-text-1);
a {
display: inline;
text-decoration: underline;
text-underline-offset: 0.25rem;
::before {
content: ' ';
}
}
`;
Styled.ButtonRow = styled.div`
${layoutMixins.inlineRow}
gap: 0.75rem;
margin-top: 0.5rem;
a:last-child {
--button-width: 100%;
}
`;
Styled.Button = styled(Button)`
--button-padding: 0 1rem;
`;
Styled.LinkOutIcon = styled(Icon)`
color: var(--color-text-1);
`;
Styled.AboutButton = styled(Styled.Button)`
--button-textColor: var(--color-text-2);
--button-backgroundColor: var(--color-layer-6);
--button-border: solid var(--border-width) var(--color-layer-7);
`;
Styled.Column = styled.div`
${layoutMixins.flexColumn}
gap: 0.5rem;
`;
Styled.EstimatedRewardsCard = styled.div`
${layoutMixins.spacedRow}
padding: 1rem 1.25rem;
min-width: 19rem;
height: calc(100% - calc(1.5rem * 2));
margin: 1.5rem;
background-color: var(--color-layer-5);
background-image: url('/dots-background.svg');
background-size: cover;
border-radius: 0.75rem;
border: solid var(--border-width) var(--color-layer-6);
color: var(--color-text-1);
@media ${breakpoints.tablet} {
margin: 0 0 0.5rem;
}
`;
Styled.EstimatedRewardsCardContent = styled.div`
${layoutMixins.flexColumn}
gap: 1rem;
height: 100%;
justify-content: space-between;
div {
${layoutMixins.flexColumn}
gap: 0.15rem;
font: var(--font-medium-book);
:first-child {
color: var(--color-text-2);
}
}
`;
Styled.BackgroundDots = styled.img`
position: absolute;
`;
Styled.Season = styled.span`
font: var(--font-small-book);
color: var(--color-text-1);
`;
Styled.Points = styled.span`
${layoutMixins.inlineRow}
gap: 0.25rem;
font: var(--font-large-book);
color: var(--color-text-0);
output {
color: var(--color-text-2);
}
`;
Styled.Image = styled.img`
position: relative;
float: right;
width: 5.25rem;
height: auto;
`;
Styled.ChaosLabsLogo = styled.img`
height: 1.25rem;
align-self: start;
`;
Styled.NewTag = styled(Tag)`
color: var(--color-accent);
background-color: var(--color-accent-faded);
`;
+5 -17
View File
@@ -26,7 +26,7 @@ import { MustBigNumber } from '@/lib/numbers';
const TOKEN_MIGRATION_LEARN_MORE_LINK = const TOKEN_MIGRATION_LEARN_MORE_LINK =
'https://www.dydx.foundation/blog/update-on-exploring-the-future-of-dydx'; 'https://www.dydx.foundation/blog/update-on-exploring-the-future-of-dydx';
export const MigratePanel = ({ className }: { className?: string }) => { export const MigratePanel = () => {
const { isNotTablet } = useBreakpoints(); const { isNotTablet } = useBreakpoints();
const stringGetter = useStringGetter(); const stringGetter = useStringGetter();
@@ -43,7 +43,6 @@ export const MigratePanel = ({ className }: { className?: string }) => {
return isNotTablet ? ( return isNotTablet ? (
<Styled.MigratePanel <Styled.MigratePanel
className={className}
slotHeader={<Styled.Title>{stringGetter({ key: STRING_KEYS.MIGRATE })}</Styled.Title>} slotHeader={<Styled.Title>{stringGetter({ key: STRING_KEYS.MIGRATE })}</Styled.Title>}
slotRight={ slotRight={
<Styled.MigrateAction> <Styled.MigrateAction>
@@ -73,7 +72,6 @@ export const MigratePanel = ({ className }: { className?: string }) => {
</Styled.MigratePanel> </Styled.MigratePanel>
) : ( ) : (
<Styled.MigratePanel <Styled.MigratePanel
className={className}
slotHeader={ slotHeader={
<Styled.MobileMigrateHeader> <Styled.MobileMigrateHeader>
<h3> <h3>
@@ -134,24 +132,21 @@ export const MigratePanel = ({ className }: { className?: string }) => {
const Styled: Record<string, AnyStyledComponent> = {}; const Styled: Record<string, AnyStyledComponent> = {};
Styled.MigratePanel = styled(Panel)` Styled.MigratePanel = styled(Panel)`
--panel-paddingX: 1.5rem;
width: 100%; width: 100%;
background-image: url('/dots-background.svg');
background-position: right;
background-repeat: no-repeat;
`; `;
Styled.Title = styled.h3` Styled.Title = styled.h3`
font: var(--font-medium-book); font: var(--font-medium-book);
color: var(--color-text-2); color: var(--color-text-2);
padding: var(--panel-paddingY) var(--panel-paddingX) 0; padding: 1rem 1.5rem 0;
`; `;
Styled.MigrateAction = styled.div` Styled.MigrateAction = styled.div`
${layoutMixins.flexEqualColumns} ${layoutMixins.flexEqualColumns}
align-items: center; align-items: center;
margin: 1rem; margin-right: 1rem;
gap: 1rem; gap: 1rem;
padding: 1rem; padding: 1rem;
width: 100%; width: 100%;
@@ -169,13 +164,6 @@ Styled.Token = styled(Output)`
Styled.Description = styled.div` Styled.Description = styled.div`
color: var(--color-text-0); color: var(--color-text-0);
--link-color: var(--color-text-1); --link-color: var(--color-text-1);
a {
display: inline;
::before {
content: ' ';
}
}
`; `;
Styled.Column = styled.div` Styled.Column = styled.div`
@@ -191,7 +179,7 @@ Styled.MobileMigrateHeader = styled.div`
font: var(--font-small-book); font: var(--font-small-book);
color: var(--color-text-0); color: var(--color-text-0);
padding: 1rem 1rem 0; padding: 1rem 1.5rem 0;
h3 { h3 {
${layoutMixins.inlineRow} ${layoutMixins.inlineRow}
-86
View File
@@ -1,86 +0,0 @@
import styled, { AnyStyledComponent } from 'styled-components';
import { breakpoints } from '@/styles';
import { STRING_KEYS } from '@/constants/localization';
import { layoutMixins } from '@/styles/layoutMixins';
import { useStringGetter } from '@/hooks';
import { Accordion } from '@/components/Accordion';
import { Link } from '@/components/Link';
import { Panel } from '@/components/Panel';
const REWARDS_LEARN_MORE_LINK = ''; // to be configured
export const RewardsHelpPanel = () => {
const stringGetter = useStringGetter();
return (
<Styled.HelpCard
slotHeader={
<Styled.Header>
<h3>{stringGetter({ key: STRING_KEYS.HELP })}</h3>
{REWARDS_LEARN_MORE_LINK && (
<Link withIcon href={REWARDS_LEARN_MORE_LINK}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
)}
</Styled.Header>
}
>
<Accordion
items={[
{
header: 'Who is eligible for trading rewards?',
content: 'All traders are eligible for trading rewards.',
},
{
header: 'How do trading rewards work?',
content:
'Immediately after each fill, trading rewards are sent directly to the traders dYdX Chain address, based on the amount of fees paid by the trader.',
},
{
header: 'How do I claim my rewards?',
content:
'Each block, trading rewards are automatically sent directly to the traders dYdX Chain address.',
},
]}
/>
</Styled.HelpCard>
);
};
const Styled: Record<string, AnyStyledComponent> = {};
Styled.HelpCard = styled(Panel)`
--panel-content-paddingX: 0;
--panel-content-paddingY: 0;
width: 100%;
height: max-content;
padding: 0;
gap: 0;
text-align: start;
`;
Styled.Header = styled.div`
${layoutMixins.spacedRow}
gap: 1ch;
padding: 1rem 1rem;
border-bottom: var(--border-width) solid var(--border-color);
font: var(--font-small-book);
@media ${breakpoints.notTablet} {
padding: 1.5rem 1.25rem;
}
h3 {
font: var(--font-medium-book);
color: var(--color-text-2);
}
`;
Styled.Link = styled(Link)`
display: inline-flex;
`;
+15 -63
View File
@@ -1,18 +1,15 @@
import styled, { AnyStyledComponent } from 'styled-components'; import styled, { AnyStyledComponent } from 'styled-components';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import { STRING_KEYS } from '@/constants/localization'; import { STRING_KEYS } from '@/constants/localization';
import { ButtonAction, ButtonSize } from '@/constants/buttons'; import { ButtonAction, ButtonSize } from '@/constants/buttons';
import { DialogTypes } from '@/constants/dialogs'; import { DialogTypes } from '@/constants/dialogs';
import { AppRoute } from '@/constants/routes';
import { useBreakpoints, useStringGetter, useURLConfigs } 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 { BackButton } from '@/components/BackButton';
import { Panel } from '@/components/Panel'; import { Panel } from '@/components/Panel';
import { IconName } from '@/components/Icon'; import { IconName } from '@/components/Icon';
import { IconButton } from '@/components/IconButton'; import { IconButton } from '@/components/IconButton';
@@ -22,15 +19,12 @@ import { openDialog } from '@/state/dialogs';
import { DYDXBalancePanel } from './DYDXBalancePanel'; import { DYDXBalancePanel } from './DYDXBalancePanel';
import { MigratePanel } from './MigratePanel'; import { MigratePanel } from './MigratePanel';
import { LaunchIncentivesPanel } from './LaunchIncentivesPanel';
import { RewardsHelpPanel } from './RewardsHelpPanel';
const RewardsPage = () => { export const RewardsPage = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const stringGetter = useStringGetter(); const stringGetter = useStringGetter();
const { governanceLearnMore, stakingLearnMore } = useURLConfigs(); const { governanceLearnMore, stakingLearnMore } = useURLConfigs();
const { isTablet, isNotTablet } = useBreakpoints(); const { isTablet, isNotTablet } = useBreakpoints();
const navigate = useNavigate();
const panelArrow = ( const panelArrow = (
<Styled.Arrow> <Styled.Arrow>
@@ -44,28 +38,12 @@ const RewardsPage = () => {
return ( return (
<Styled.Page> <Styled.Page>
{isTablet && ( {import.meta.env.VITE_V3_TOKEN_ADDRESS && <MigratePanel />}
<Styled.MobileHeader>
<BackButton onClick={() => navigate(AppRoute.Profile)} />
{stringGetter({ key: STRING_KEYS.TRADING_REWARDS })}
</Styled.MobileHeader>
)}
{import.meta.env.VITE_V3_TOKEN_ADDRESS && isNotTablet && <MigratePanel />}
{isTablet ? (
<LaunchIncentivesPanel />
) : (
<Styled.PanelRowIncentivesAndBalance>
<LaunchIncentivesPanel />
<DYDXBalancePanel />
</Styled.PanelRowIncentivesAndBalance>
)}
<Styled.PanelRow> <Styled.PanelRow>
{isTablet && <DYDXBalancePanel />}
<Styled.Panel <Styled.Panel
slotHeaderContent={ slotHeader={<Styled.Title>{stringGetter({ key: STRING_KEYS.GOVERNANCE })}</Styled.Title>}
<Styled.Title>{stringGetter({ key: STRING_KEYS.GOVERNANCE })}</Styled.Title>
}
slotRight={panelArrow} slotRight={panelArrow}
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))} onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
> >
@@ -78,9 +56,7 @@ const RewardsPage = () => {
</Styled.Panel> </Styled.Panel>
<Styled.Panel <Styled.Panel
slotHeaderContent={ slotHeader={<Styled.Title>{stringGetter({ key: STRING_KEYS.STAKING })}</Styled.Title>}
<Styled.Title>{stringGetter({ key: STRING_KEYS.STAKING })}</Styled.Title>
}
slotRight={panelArrow} slotRight={panelArrow}
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))} onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
> >
@@ -91,15 +67,13 @@ const RewardsPage = () => {
</Link> </Link>
</Styled.Description> </Styled.Description>
</Styled.Panel> </Styled.Panel>
</Styled.PanelRow>
<RewardsHelpPanel /> {isNotTablet && <DYDXBalancePanel />}
</Styled.PanelRow>
</Styled.Page> </Styled.Page>
); );
}; };
export default RewardsPage;
const Styled: Record<string, AnyStyledComponent> = {}; const Styled: Record<string, AnyStyledComponent> = {};
Styled.Page = styled.div` Styled.Page = styled.div`
@@ -109,69 +83,47 @@ Styled.Page = styled.div`
align-items: center; align-items: center;
> * { > * {
--content-max-width: 80rem; --content-max-width: 70rem;
max-width: min(calc(100vw - 4rem), var(--content-max-width)); max-width: min(calc(100vw - 4rem), var(--content-max-width));
} }
@media ${breakpoints.tablet} { @media ${breakpoints.tablet} {
--stickyArea-topHeight: var(--page-header-height-mobile); padding: 1.25rem;
padding: 0 1rem 1rem;
> * { > * {
max-width: calc(100vw - 2rem); max-width: calc(100vw - 2.5rem);
width: 100%; width: 100%;
} }
} }
`; `;
Styled.MobileHeader = styled.header`
${layoutMixins.contentSectionDetachedScrollable}
${layoutMixins.stickyHeader}
z-index: 2;
padding: 1.25rem 0;
margin-bottom: -1.5rem;
font: var(--font-large-medium);
color: var(--color-text-2);
background-color: var(--color-layer-2);
`;
Styled.Panel = styled(Panel)` Styled.Panel = styled(Panel)`
height: fit-content; --panel-paddingX: 1.5rem;
`; `;
Styled.Title = styled.h3` Styled.Title = styled.h3`
font: var(--font-medium-book); font: var(--font-medium-book);
color: var(--color-text-2); color: var(--color-text-2);
margin-bottom: -1rem; padding: 1rem 1.5rem 0;
`; `;
Styled.Description = styled.div` Styled.Description = styled.div`
color: var(--color-text-0); color: var(--color-text-0);
--link-color: var(--color-text-1); --link-color: var(--color-text-1);
a {
display: inline;
::before {
content: ' ';
}
}
`; `;
Styled.PanelRow = styled.div` Styled.PanelRow = styled.div`
${layoutMixins.gridEqualColumns} ${layoutMixins.gridEqualColumns}
gap: 1.5rem; gap: 1.5rem;
align-items: flex-start;
@media ${breakpoints.tablet} { @media ${breakpoints.tablet} {
grid-auto-flow: row; grid-auto-flow: row;
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
`; `;
Styled.PanelRowIncentivesAndBalance = styled(Styled.PanelRow)`
grid-template-columns: 2fr 1fr;
`;
Styled.IconButton = styled(IconButton)` Styled.IconButton = styled(IconButton)`
color: var(--color-text-0); color: var(--color-text-0);
--color-border: var(--color-layer-6); --color-border: var(--color-layer-6);
+1 -3
View File
@@ -25,7 +25,7 @@ import { useNetworks } from '@/views/menus/useNetworks';
import { SettingsHeader } from './SettingsHeader'; import { SettingsHeader } from './SettingsHeader';
import { ComingSoonSpace } from '@/components/ComingSoon'; import { ComingSoonSpace } from '@/components/ComingSoon';
const SettingsPage = () => { export const SettingsPage = () => {
const stringGetter = useStringGetter(); const stringGetter = useStringGetter();
const { pathname } = useLocation(); const { pathname } = useLocation();
const dispatch = useDispatch(); const dispatch = useDispatch();
@@ -105,5 +105,3 @@ const SettingsPage = () => {
</> </>
); );
}; };
export default SettingsPage;
+116 -130
View File
@@ -1,7 +1,8 @@
import { useMemo, useState } from 'react'; import { useState } from 'react';
import { shallowEqual, useSelector } from 'react-redux'; import { shallowEqual, useSelector } from 'react-redux';
import styled, { type AnyStyledComponent } from 'styled-components'; import styled, { type AnyStyledComponent } from 'styled-components';
import { AbacusOrderStatus } from '@/constants/abacus';
import { STRING_KEYS } from '@/constants/localization'; import { STRING_KEYS } from '@/constants/localization';
import { useBreakpoints, useStringGetter } from '@/hooks'; import { useBreakpoints, useStringGetter } from '@/hooks';
@@ -27,6 +28,7 @@ import {
getCurrentMarketTradeInfoNumbers, getCurrentMarketTradeInfoNumbers,
getHasUnseenFillUpdates, getHasUnseenFillUpdates,
getHasUnseenOrderUpdates, getHasUnseenOrderUpdates,
getLatestOrderStatus,
getTradeInfoNumbers, getTradeInfoNumbers,
} from '@/state/accountSelectors'; } from '@/state/accountSelectors';
@@ -80,141 +82,125 @@ export const HorizontalPanel = ({ isOpen = true, setIsOpen }: ElementProps) => {
showCurrentMarket ? numOpenOrders : numTotalOpenOrders showCurrentMarket ? numOpenOrders : numTotalOpenOrders
); );
const tabItems = useMemo( const tabItems = [
() => [ {
{ value: InfoSection.Position,
value: InfoSection.Position, label: stringGetter({
label: stringGetter({ key: showCurrentMarket ? STRING_KEYS.POSITION : STRING_KEYS.POSITIONS,
key: showCurrentMarket ? STRING_KEYS.POSITION : STRING_KEYS.POSITIONS, }),
}),
tag: showCurrentMarket ? null : shortenNumberForDisplay(numTotalPositions), tag: showCurrentMarket ? null : shortenNumberForDisplay(numTotalPositions),
content: showCurrentMarket ? ( content: showCurrentMarket ? (
<PositionInfo showNarrowVariation={isTablet} /> <PositionInfo showNarrowVariation={isTablet} />
) : ( ) : (
<PositionsTable <PositionsTable
columnKeys={ columnKeys={
isTablet isTablet
? [ ? [
PositionsTableColumnKey.Details, PositionsTableColumnKey.Details,
PositionsTableColumnKey.IndexEntry, PositionsTableColumnKey.IndexEntry,
PositionsTableColumnKey.PnL, PositionsTableColumnKey.PnL,
] ]
: [ : [
PositionsTableColumnKey.Market, PositionsTableColumnKey.Market,
PositionsTableColumnKey.Side, PositionsTableColumnKey.Side,
PositionsTableColumnKey.Size, PositionsTableColumnKey.Size,
PositionsTableColumnKey.Leverage, PositionsTableColumnKey.Leverage,
PositionsTableColumnKey.LiquidationAndOraclePrice, PositionsTableColumnKey.LiquidationAndOraclePrice,
PositionsTableColumnKey.UnrealizedPnl, PositionsTableColumnKey.UnrealizedPnl,
PositionsTableColumnKey.RealizedPnl, PositionsTableColumnKey.RealizedPnl,
PositionsTableColumnKey.AverageOpenAndClose, PositionsTableColumnKey.AverageOpenAndClose,
] ]
} }
onNavigate={() => setView(PanelView.CurrentMarket)} onNavigate={() => setView(PanelView.CurrentMarket)}
/> />
), ),
}, },
{ {
asChild: true, value: InfoSection.Orders,
value: InfoSection.Orders, label: stringGetter({ key: STRING_KEYS.ORDERS }),
label: stringGetter({ key: STRING_KEYS.ORDERS }),
slotRight: isWaitingForOrderToIndex ? ( slotRight: isWaitingForOrderToIndex ? (
<Styled.LoadingSpinner /> <Styled.LoadingSpinner />
) : ( ) : (
ordersTagNumber && ( ordersTagNumber && (
<Tag type={TagType.Number} isHighlighted={hasUnseenOrderUpdates}> <Tag type={TagType.Number} isHighlighted={hasUnseenOrderUpdates}>
{ordersTagNumber} {ordersTagNumber}
</Tag>
)
),
content: (
<OrdersTable
currentMarket={showCurrentMarket ? currentMarketId : undefined}
columnKeys={
isTablet
? [OrdersTableColumnKey.StatusFill, OrdersTableColumnKey.PriceType]
: [
!showCurrentMarket && OrdersTableColumnKey.Market,
OrdersTableColumnKey.Status,
OrdersTableColumnKey.Side,
OrdersTableColumnKey.AmountFill,
OrdersTableColumnKey.Price,
OrdersTableColumnKey.Trigger,
OrdersTableColumnKey.GoodTil,
!isAccountViewOnly && OrdersTableColumnKey.Actions,
].filter(isTruthy)
}
/>
),
},
{
asChild: true,
value: InfoSection.Fills,
label: stringGetter({ key: STRING_KEYS.FILLS }),
slotRight: fillsTagNumber && (
<Tag type={TagType.Number} isHighlighted={hasUnseenFillUpdates}>
{fillsTagNumber}
</Tag> </Tag>
), )
),
content: ( content: (
<FillsTable <OrdersTable
currentMarket={showCurrentMarket ? currentMarketId : undefined} currentMarket={showCurrentMarket ? currentMarketId : undefined}
columnKeys={ columnKeys={
isTablet isTablet
? [ ? [OrdersTableColumnKey.StatusFill, OrdersTableColumnKey.PriceType]
FillsTableColumnKey.Time, : [
FillsTableColumnKey.TypeAmount, !showCurrentMarket && OrdersTableColumnKey.Market,
FillsTableColumnKey.PriceFee, OrdersTableColumnKey.Status,
] OrdersTableColumnKey.Side,
: [ OrdersTableColumnKey.AmountFill,
!showCurrentMarket && FillsTableColumnKey.Market, OrdersTableColumnKey.Price,
FillsTableColumnKey.Time, OrdersTableColumnKey.Trigger,
FillsTableColumnKey.Type, OrdersTableColumnKey.GoodTil,
FillsTableColumnKey.Side, !isAccountViewOnly && OrdersTableColumnKey.Actions,
FillsTableColumnKey.AmountTag, ].filter(isTruthy)
FillsTableColumnKey.Price, }
FillsTableColumnKey.TotalFee, />
FillsTableColumnKey.Liquidity, ),
].filter(isTruthy) },
} {
columnWidths={{ value: InfoSection.Fills,
[FillsTableColumnKey.TypeAmount]: '100%', label: stringGetter({ key: STRING_KEYS.FILLS }),
}}
/>
),
},
// TODO - TRCL-1693 - re-enable when funding payments are supported
// {
// value: InfoSection.Payments,
// label: stringGetter({ key: STRING_KEYS.PAYMENTS }),
// tag: shortenNumberForDisplay( slotRight: fillsTagNumber && (
// showCurrentMarket ? numFundingPayments : numTotalFundingPayments <Tag type={TagType.Number} isHighlighted={hasUnseenFillUpdates}>
// ), {fillsTagNumber}
// content: ( </Tag>
// <FundingPaymentsTable currentMarket={showCurrentMarket ? currentMarket?.id : undefined} /> ),
// ),
// }, content: (
], <FillsTable
[ currentMarket={showCurrentMarket ? currentMarketId : undefined}
stringGetter, columnKeys={
currentMarketId, isTablet
showCurrentMarket, ? [
isTablet, FillsTableColumnKey.Time,
isWaitingForOrderToIndex, FillsTableColumnKey.TypeAmount,
isAccountViewOnly, FillsTableColumnKey.PriceFee,
ordersTagNumber, ]
fillsTagNumber, : [
hasUnseenFillUpdates, !showCurrentMarket && FillsTableColumnKey.Market,
hasUnseenOrderUpdates, FillsTableColumnKey.Time,
] FillsTableColumnKey.Type,
); FillsTableColumnKey.Side,
FillsTableColumnKey.AmountTag,
FillsTableColumnKey.Price,
FillsTableColumnKey.TotalFee,
FillsTableColumnKey.Liquidity,
].filter(isTruthy)
}
columnWidths={{
[FillsTableColumnKey.TypeAmount]: '100%',
}}
/>
),
},
// TODO - TRCL-1693 - re-enable when funding payments are supported
// {
// value: InfoSection.Payments,
// label: stringGetter({ key: STRING_KEYS.PAYMENTS }),
// tag: shortenNumberForDisplay(
// showCurrentMarket ? numFundingPayments : numTotalFundingPayments
// ),
// content: (
// <FundingPaymentsTable currentMarket={showCurrentMarket ? currentMarket?.id : undefined} />
// ),
// },
];
return isTablet ? ( return isTablet ? (
<MobileTabs defaultValue={InfoSection.Position} items={tabItems} withBorders={false} /> <MobileTabs defaultValue={InfoSection.Position} items={tabItems} withBorders={false} />
+1 -7
View File
@@ -7,12 +7,7 @@ import { layoutMixins } from '@/styles/layoutMixins';
import { TradeLayouts } from '@/constants/layout'; import { TradeLayouts } from '@/constants/layout';
import { import { useBreakpoints, useCurrentMarketId, usePageTitlePriceUpdates } from '@/hooks';
useBreakpoints,
useCurrentMarketId,
usePageTitlePriceUpdates,
useTradeFormInputs,
} from '@/hooks';
import { calculateCanAccountTrade } from '@/state/accountCalculators'; import { calculateCanAccountTrade } from '@/state/accountCalculators';
import { getSelectedTradeLayout } from '@/state/layoutSelectors'; import { getSelectedTradeLayout } from '@/state/layoutSelectors';
@@ -42,7 +37,6 @@ const TradePage = () => {
const [isHorizontalPanelOpen, setIsHorizontalPanelOpen] = useState(true); const [isHorizontalPanelOpen, setIsHorizontalPanelOpen] = useState(true);
usePageTitlePriceUpdates(); usePageTitlePriceUpdates();
useTradeFormInputs();
return isTablet ? ( return isTablet ? (
<Styled.TradeLayoutMobile> <Styled.TradeLayoutMobile>
+8 -1
View File
@@ -1,8 +1,10 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { SubaccountPosition } from '@/constants/abacus';
import { OnboardingState, OnboardingSteps } from '@/constants/account'; import { OnboardingState, OnboardingSteps } from '@/constants/account';
import { import {
getExistingOpenPositions,
getOnboardingGuards, getOnboardingGuards,
getOnboardingState, getOnboardingState,
getSubaccountId, getSubaccountId,
@@ -58,8 +60,13 @@ export const calculateIsAccountViewOnly = createSelector(
); );
/** /**
* @description calculate whether the subaccount has uncommitted positions * @description calculate whether the subaccount has open positions
*/ */
export const calculateHasOpenPositions = createSelector(
[getExistingOpenPositions],
(openPositions?: SubaccountPosition[]) => (openPositions?.length || 0) > 0
);
export const calculateHasUncommittedOrders = createSelector( export const calculateHasUncommittedOrders = createSelector(
[getUncommittedOrderClientIds], [getUncommittedOrderClientIds],
(uncommittedOrderClientIds: number[]) => uncommittedOrderClientIds.length > 0 (uncommittedOrderClientIds: number[]) => uncommittedOrderClientIds.length > 0
+5 -11
View File
@@ -2,7 +2,6 @@ import { OrderSide } from '@dydxprotocol/v4-client-js';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { import {
type AbacusOrderStatuses,
type SubaccountOrder, type SubaccountOrder,
type SubaccountFill, type SubaccountFill,
type SubaccountFundingPayment, type SubaccountFundingPayment,
@@ -44,6 +43,7 @@ export const getSubaccountBuyingPower = (state: RootState) => state.account.suba
export const getSubaccountEquity = (state: RootState) => state.account.subaccount?.equity; export const getSubaccountEquity = (state: RootState) => state.account.subaccount?.equity;
export const getSubaccountHistoricalPnl = (state: RootState) => state.account?.historicalPnl; export const getSubaccountHistoricalPnl = (state: RootState) => state.account?.historicalPnl;
/** /**
* @param state * @param state
* @returns list of a subaccount's open positions. Each item in the list is an open position in a different market. * @returns list of a subaccount's open positions. Each item in the list is an open position in a different market.
@@ -258,14 +258,6 @@ export const getCurrentMarketFundingPayments = createSelector(
!currentMarketId ? [] : marketFundingPayments[currentMarketId] !currentMarketId ? [] : marketFundingPayments[currentMarketId]
); );
/**
* @param state
* @returns boolean on whether an order status is considered open
*/
const isOpenOrderStatus = (status: AbacusOrderStatuses) => {
return status !== AbacusOrderStatus.filled && status !== AbacusOrderStatus.cancelled;
};
/** /**
* @param state * @param state
* @returns Total numbers of the subaccount's open positions, open orders and fills * @returns Total numbers of the subaccount's open positions, open orders and fills
@@ -274,7 +266,8 @@ export const getTradeInfoNumbers = createSelector(
[getExistingOpenPositions, getSubaccountOrders, getSubaccountFills, getSubaccountFundingPayments], [getExistingOpenPositions, getSubaccountOrders, getSubaccountFills, getSubaccountFundingPayments],
(positions, orders, fills, fundingPayments) => ({ (positions, orders, fills, fundingPayments) => ({
numTotalPositions: positions?.length, numTotalPositions: positions?.length,
numTotalOpenOrders: orders?.filter((order) => isOpenOrderStatus(order.status)).length, numTotalOpenOrders: orders?.filter((order) => order.status !== AbacusOrderStatus.cancelled)
.length,
numTotalFills: fills?.length, numTotalFills: fills?.length,
numTotalFundingPayments: fundingPayments?.length, numTotalFundingPayments: fundingPayments?.length,
}) })
@@ -288,7 +281,8 @@ export const getCurrentMarketTradeInfoNumbers = createSelector(
[getCurrentMarketOrders, getCurrentMarketFills, getCurrentMarketFundingPayments], [getCurrentMarketOrders, getCurrentMarketFills, getCurrentMarketFundingPayments],
(marketOrders, marketFills, marketFundingPayments) => { (marketOrders, marketFills, marketFundingPayments) => {
return { return {
numOpenOrders: marketOrders?.filter((order) => isOpenOrderStatus(order.status)).length, numOpenOrders: marketOrders?.filter((order) => order.status !== AbacusOrderStatus.cancelled)
.length,
numFills: marketFills?.length, numFills: marketFills?.length,
numFundingPayments: marketFundingPayments?.length, numFundingPayments: marketFundingPayments?.length,
}; };
+1 -10
View File
@@ -17,7 +17,6 @@ export interface ConfigsState {
feeTiers?: kollections.List<FeeTier>; feeTiers?: kollections.List<FeeTier>;
feeDiscounts?: FeeDiscount[]; feeDiscounts?: FeeDiscount[];
network?: NetworkConfigs; network?: NetworkConfigs;
hasSeenLaunchIncentives: boolean;
} }
const DOCUMENT_THEME_MAP = { const DOCUMENT_THEME_MAP = {
@@ -44,10 +43,6 @@ const initialState: ConfigsState = {
feeDiscounts: undefined, feeDiscounts: undefined,
feeTiers: undefined, feeTiers: undefined,
network: undefined, network: undefined,
hasSeenLaunchIncentives: getLocalStorage({
key: LocalStorageKey.HasSeenLaunchIncentives,
defaultValue: false,
}),
}; };
changeTheme(initialState.appTheme); changeTheme(initialState.appTheme);
@@ -65,11 +60,7 @@ export const configsSlice = createSlice({
...state, ...state,
...action.payload, ...action.payload,
}), }),
markLaunchIncentivesSeen: (state: ConfigsState) => {
setLocalStorage({ key: LocalStorageKey.HasSeenLaunchIncentives, value: true });
state.hasSeenLaunchIncentives = true;
},
}, },
}); });
export const { setAppTheme, setConfigs, markLaunchIncentivesSeen } = configsSlice.actions; export const { setAppTheme, setConfigs } = configsSlice.actions;
-3
View File
@@ -5,6 +5,3 @@ export const getAppTheme = (state: RootState) => state.configs.appTheme;
export const getFeeTiers = (state: RootState) => state.configs.feeTiers?.toArray(); export const getFeeTiers = (state: RootState) => state.configs.feeTiers?.toArray();
export const getFeeDiscounts = (state: RootState) => state.configs.feeDiscounts; export const getFeeDiscounts = (state: RootState) => state.configs.feeDiscounts;
export const getHasSeenLaunchIncentives = (state: RootState) =>
state.configs.hasSeenLaunchIncentives;
+2 -19
View File
@@ -1,5 +1,4 @@
import { createSlice, type PayloadAction } from '@reduxjs/toolkit'; import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
import assign from 'lodash/assign';
import type { import type {
InputError, InputError,
@@ -10,14 +9,9 @@ import type {
TransferInputs, TransferInputs,
} from '@/constants/abacus'; } from '@/constants/abacus';
import { CLEARED_SIZE_INPUTS, CLEARED_TRADE_INPUTS } from '@/constants/trade';
type TradeFormInputs = typeof CLEARED_TRADE_INPUTS & typeof CLEARED_SIZE_INPUTS;
export interface InputsState { export interface InputsState {
current?: Nullable<string>; current?: Nullable<string>;
inputErrors?: Nullable<InputError[]>; inputErrors?: Nullable<InputError[]>;
tradeFormInputs: TradeFormInputs;
tradeInputs?: Nullable<TradeInputs>; tradeInputs?: Nullable<TradeInputs>;
closePositionInputs?: Nullable<ClosePositionInputs>; closePositionInputs?: Nullable<ClosePositionInputs>;
transferInputs?: Nullable<TransferInputs>; transferInputs?: Nullable<TransferInputs>;
@@ -26,10 +20,6 @@ export interface InputsState {
const initialState: InputsState = { const initialState: InputsState = {
current: undefined, current: undefined,
inputErrors: undefined, inputErrors: undefined,
tradeFormInputs: {
...CLEARED_TRADE_INPUTS,
...CLEARED_SIZE_INPUTS,
},
tradeInputs: undefined, tradeInputs: undefined,
transferInputs: undefined, transferInputs: undefined,
}; };
@@ -47,17 +37,10 @@ export const inputsSlice = createSlice({
inputErrors: errors?.toArray(), inputErrors: errors?.toArray(),
tradeInputs: trade, tradeInputs: trade,
closePositionInputs: closePosition, closePositionInputs: closePosition,
transferInputs: { transferInputs: transfer,
...transfer,
isCctp: !!transfer?.isCctp,
} as Nullable<TransferInputs>,
}; };
}, },
setTradeFormInputs: (state, action: PayloadAction<Partial<TradeFormInputs>>) => {
state.tradeFormInputs = assign({}, state.tradeFormInputs, action.payload);
},
}, },
}); });
export const { setInputs, setTradeFormInputs } = inputsSlice.actions; export const { setInputs } = inputsSlice.actions;
-5
View File
@@ -120,8 +120,3 @@ export const useTradeFormData = () => {
shallowEqual shallowEqual
); );
}; };
/**
* @returns Tradeform Input states for display. Abacus inputs should track these values.
*/
export const getTradeFormInputs = (state: RootState) => state.inputs.tradeFormInputs;
+3 -2
View File
@@ -57,8 +57,9 @@ export default (store: any) => (next: any) => async (action: PayloadAction<any>)
} else if (globalThis.navigator?.language) { } else if (globalThis.navigator?.language) {
const browserLanguageBaseTag = globalThis.navigator.language.split('-')[0].toLowerCase(); const browserLanguageBaseTag = globalThis.navigator.language.split('-')[0].toLowerCase();
const locale = (SUPPORTED_BASE_TAGS_LOCALE_MAPPING[browserLanguageBaseTag] ?? const locale = SUPPORTED_BASE_TAGS_LOCALE_MAPPING[
SUPPORTED_BASE_TAGS_LOCALE_MAPPING[SupportedLocales.EN]) as SupportedLocales; browserLanguageBaseTag
] as SupportedLocales;
if (locale) { if (locale) {
store.dispatch(setSelectedLocale({ locale, isAutoDetect: true })); store.dispatch(setSelectedLocale({ locale, isAutoDetect: true }));
+1 -6
View File
@@ -26,12 +26,7 @@ export const calculateFundingRateHistory = createSelector(
return data.map(({ effectiveAtMilliseconds, rate }) => ({ return data.map(({ effectiveAtMilliseconds, rate }) => ({
time: effectiveAtMilliseconds, time: effectiveAtMilliseconds,
fundingRate: rate, fundingRate: rate,
direction: direction: rate < 0 ? FundingDirection.ToLong : FundingDirection.ToShort,
rate === 0
? FundingDirection.None
: rate < 0
? FundingDirection.ToLong
: FundingDirection.ToShort,
})); }));
} }
); );
-1
View File
@@ -116,7 +116,6 @@
--color-gradient-positive: hsla(158, 49%, 48%, 0.16); --color-gradient-positive: hsla(158, 49%, 48%, 0.16);
--color-gradient-negative: hsla(0, 100%, 66%, 0.16); --color-gradient-negative: hsla(0, 100%, 66%, 0.16);
--color-accent-faded: hsla(var(--theme-classic-hue-purple), 100%, 70%, 0.16);
--color-risk-low: var(--theme-classic-color-green); --color-risk-low: var(--theme-classic-color-green);
--color-risk-medium: var(--theme-classic-color-yellow); --color-risk-medium: var(--theme-classic-color-yellow);
-2
View File
@@ -151,8 +151,6 @@ export const formMixins: Record<
--form-input-paddingY: 0.5rem; --form-input-paddingY: 0.5rem;
--form-input-paddingX: 1rem; --form-input-paddingX: 1rem;
height: 100%;
label { label {
--label-textColor: var(--color-text-0); --label-textColor: var(--color-text-0);
} }

Some files were not shown because too many files have changed in this diff Show More