Compare commits

..
Author SHA1 Message Date
aforaleka 071cb25c04 pessimistic collat check in non-dev/staging envs
Signed-off-by: aforaleka <aforaleka@gmail.com>
2024-02-22 15:11:19 -05:00
moo-onthelawn e1d2a5eda4 Update env config to enable reduce only in testnet (#321)
* update flag

* update new env.json
2024-02-22 13:07:06 -05:00
moo-onthelawn 56be9ba9cc traced back to innerWindow error (#320) 2024-02-21 19:17:33 -05:00
Bill 859e7dde80 Add notification for season 3 incentives (#322)
* Add notification for season 3 incentives

* add type

* address comments
2024-02-21 16:04:56 -08:00
John Huang d9daf9f583 Feature/mob 193 install app dlg (#308)
* getOS and get meta from header

* Clean up

* Update localization

* Comments

* Rename URL variable

* MOB-193 PR

* PR
2024-02-21 12:52:11 -08:00
John Huang 5be9d2b1b2 TRCL-3553 Having the launch incentive api in env.json (#317) 2024-02-21 12:51:36 -08:00
Bill d2c5b7945b Remove CEX withdraw testflag (#316) 2024-02-21 09:50:11 -08:00
aleka fc5d8538fe bump abacus for new env config path usage (#314)
* bump abacus for new env config path usage

* bump abacus + localization for good til date
2024-02-20 22:42:18 -05:00
yujin512 fdc262f59f Update otherMarketExchangeConfig.json (#315)
* Update otherMarketExchangeConfig.json

add strk

* Update otherMarketExchangeConfig.json

remove huobi, add kraken

* Update otherMarketParameters.json

add strk to parameters

* add strk icon and metadata
2024-02-20 16:08:11 -05:00
31 changed files with 387 additions and 583 deletions
+2 -2
View File
@@ -40,9 +40,9 @@
"@cosmjs/proto-signing": "^0.32.1",
"@cosmjs/stargate": "^0.32.1",
"@cosmjs/tendermint-rpc": "^0.32.1",
"@dydxprotocol/v4-abacus": "^1.4.6",
"@dydxprotocol/v4-abacus": "^1.4.12",
"@dydxprotocol/v4-client-js": "^1.0.20",
"@dydxprotocol/v4-localization": "^1.1.31",
"@dydxprotocol/v4-localization": "^1.1.35",
"@ethersproject/providers": "^5.7.2",
"@js-joda/core": "^5.5.3",
"@radix-ui/react-accordion": "^1.1.2",
+12 -12
View File
@@ -1,5 +1,9 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
overrides:
follow-redirects: 1.15.3
@@ -26,14 +30,14 @@ dependencies:
specifier: ^0.32.1
version: 0.32.2
'@dydxprotocol/v4-abacus':
specifier: ^1.4.6
version: 1.4.6
specifier: ^1.4.12
version: 1.4.12
'@dydxprotocol/v4-client-js':
specifier: ^1.0.20
version: 1.0.20
'@dydxprotocol/v4-localization':
specifier: ^1.1.31
version: 1.1.31
specifier: ^1.1.35
version: 1.1.35
'@ethersproject/providers':
specifier: ^5.7.2
version: 5.7.2
@@ -1286,8 +1290,8 @@ packages:
resolution: {integrity: sha512-Gg5t+eR7vPJMAmhkFt6CZrzPd0EKpAslWwk5rFVYZpJsM8JG5KT9XQ99hgNM3Ov6ScNoIWbXkpX27F6A9cXR4Q==}
dev: false
/@dydxprotocol/v4-abacus@1.4.6:
resolution: {integrity: sha512-qYq+4TizcMMxYVXckn0LCucWBe5N9ZNtD1XnowCAuBUUifHSgMGvao5OeZIKMgNM/udSKOXLss4zLy6dH/G2SA==}
/@dydxprotocol/v4-abacus@1.4.12:
resolution: {integrity: sha512-dNQFaNrLTujyViMH2JEtf9Vn2ew2le+qTWexktK5h7AeADBbS9uxQknMIFhfwzGkbS1QqqszBT1plrDmQ+E6nQ==}
dev: false
/@dydxprotocol/v4-client-js@1.0.20:
@@ -1319,8 +1323,8 @@ packages:
- utf-8-validate
dev: false
/@dydxprotocol/v4-localization@1.1.31:
resolution: {integrity: sha512-plJVIgFAKq9/hA/gk5GgKgCQFsH3pNtDWfG/yHLDXyiGX0M0mMEi1bTNVs4podFVoHJu1nSL9YPFlpJ00FteGw==}
/@dydxprotocol/v4-localization@1.1.35:
resolution: {integrity: sha512-q5JFYoL/QanHXOtFqRa2owBZJibi1sMpSm3dAcxs9x0/xe8mo6fWcnbQfhl8k7g0/tv7PsBc+e3rbWD0EfvGiA==}
dev: false
/@dydxprotocol/v4-proto@4.0.0-dev.0:
@@ -16049,7 +16053,3 @@ packages:
/zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
dev: true
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
+31 -61
View File
@@ -98,8 +98,7 @@
"keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
},
"wallets": {
"walletconnect": {
@@ -127,8 +126,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-dev-2": {
@@ -184,8 +182,7 @@
"keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
},
"wallets": {
"walletconnect": {
@@ -213,8 +210,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-dev-4": {
@@ -271,8 +267,7 @@
"keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
},
"wallets": {
"walletconnect": {
@@ -300,8 +295,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-dev-5": {
@@ -357,8 +351,7 @@
"keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
},
"wallets": {
"walletconnect": {
@@ -386,8 +379,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-staging": {
@@ -445,8 +437,7 @@
"keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
},
"wallets": {
"walletconnect": {
@@ -474,8 +465,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-staging-forced-update": {
@@ -524,8 +514,7 @@
"community": "https://discord.com/invite/dydx",
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
"blogs": "https://www.dydx.foundation/blog",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals"
},
"wallets": {
"walletconnect": {
@@ -560,8 +549,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-staging-west": {
@@ -619,8 +607,7 @@
"keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
},
"wallets": {
"walletconnect": {
@@ -648,8 +635,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet": {
@@ -711,8 +697,7 @@
"keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
},
"wallets": {
"walletconnect": {
@@ -740,8 +725,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet-dydx": {
@@ -800,8 +784,7 @@
"keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
},
"wallets": {
"walletconnect": {
@@ -829,8 +812,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet-nodefleet": {
@@ -889,8 +871,7 @@
"keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
},
"wallets": {
"walletconnect": {
@@ -918,8 +899,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet-kingnodes": {
@@ -978,8 +958,7 @@
"keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
},
"wallets": {
"walletconnect": {
@@ -1007,8 +986,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet-liquify": {
@@ -1067,8 +1045,7 @@
"keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet"
},
"wallets": {
"walletconnect": {
@@ -1096,8 +1073,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet-polkachu": {
@@ -1147,8 +1123,7 @@
"community": "https://discord.com/invite/dydx",
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
"blogs": "https://www.dydx.foundation/blog",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals"
},
"wallets": {
"walletconnect": {
@@ -1176,8 +1151,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet-bware": {
@@ -1236,8 +1210,7 @@
"keplrDashboard": "https://testnet.keplr.app/",
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnmore": "https://help.dydx.exchange",
"walletLearnmore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"walletLearnmore": "https://www.dydx.academy/video/defi-wallet"
},
"wallets": {
"walletconnect": {
@@ -1265,8 +1238,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true
}
},
"dydxprotocol-mainnet": {
@@ -1325,8 +1297,7 @@
"keplrDashboard": "[HTTP link to keplr dashboard, can be null]",
"strideZoneApp": "[HTTP link to stride zone app, can be null]",
"accountExportLearnMore": "[HTTP link to account export learn more, can be null]",
"walletLearnMore": "[HTTP link to wallet learn more, can be null]",
"withdrawalGateLearnMore": "[HTTP link to withdrawal gate learn more, can be null]"
"walletLearnMore": "[HTTP link to wallet learn more, can be null]"
},
"wallets": {
"walletconnect": {
@@ -1354,9 +1325,8 @@
}
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": false
"reduceOnlySupported": false
}
}
}
}
}
+7
View File
@@ -428,6 +428,13 @@
"whitepaperLink": "https://solana.com/solana-whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/solana/"
},
"STRK-USD": {
"name": "Starknet",
"tags": ["Layer 2"],
"websiteLink": "https://www.starknet.io/en",
"whitepaperLink": "https://docs.starknet.io/documentation/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/starknet-token/"
},
"STX-USD": {
"name": "Stacks",
"tags": ["Layer 2"],
@@ -513,6 +513,14 @@
{ "exchangeName": "Okx", "ticker": "SOL-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "SOL_USDT", "adjustByMarket": "USDT-USD" }
],
"STRK": [
{ "exchangeName": "Binance", "ticker": "STRKUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "STRKUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "STRKUSD" },
{ "exchangeName": "Kucoin", "ticker": "STRK-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "STRK-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Gate", "ticker": "STRK_USDT", "adjustByMarket": "USDT-USD" }
],
"STX": [
{ "exchangeName": "Binance", "ticker": "STXUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "STXUSDT", "adjustByMarket": "USDT-USD" },
+17
View File
@@ -968,6 +968,23 @@
"minOrderSize": 1000000,
"quantumConversionExponent": -9
},
{
"baseAsset": "STRK",
"referencePrice": 2.05,
"numOracles": 6,
"liquidityTier": 2,
"assetName": "Starknet",
"p": 0.0,
"atomicResolution": -6.0,
"minExchanges": 3,
"minPriceChangePpm": 4000,
"priceExponent": -9.0,
"stepBaseQuantum": 1000000,
"ticksizeExponent": -3,
"subticksPerTick": 1000000,
"minOrderSize": 1000000,
"quantumConversionExponent": -9
},
{
"baseAsset": "STX",
"referencePrice": 1.5144048703611412,
+26 -26
View File
@@ -72,7 +72,7 @@
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"launchIncentive": "https://cloud.chaoslabs.co/"
},
"dydx-testnet-4": {
"tos": "https://dydx.exchange/v4-terms",
@@ -94,7 +94,7 @@
"strideZoneApp": "https://testnet.stride.zone",
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
"withdrawalGateLearnMore": "https://help.dydx.exchange"
"launchIncentive": "https://cloud.chaoslabs.co/"
},
"[mainnet chain id]": {
"tos": "[HTTP link to TOS]",
@@ -116,7 +116,7 @@
"strideZoneApp": "[HTTP link to stride zone app, can be null]",
"accountExportLearnMore": "[HTTP link to account export learn more, can be null]",
"walletLearnMore": "[HTTP link to wallet learn more, can be null]",
"withdrawalGateLearnMore": "[HTTP link to withdrawal gate learn more, can be null]"
"launchIncentive": "[HTTP link to launch incentive host, can be null]"
}
},
"wallets": {
@@ -262,7 +262,7 @@
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-dev-2": {
@@ -288,7 +288,7 @@
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-dev-4": {
@@ -315,7 +315,7 @@
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-dev-5": {
@@ -341,7 +341,7 @@
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-staging": {
@@ -368,7 +368,7 @@
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-staging-forced-update": {
@@ -402,7 +402,7 @@
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-staging-west": {
@@ -429,7 +429,7 @@
},
"featureFlags": {
"reduceOnlySupported": true,
"withdrawalSafetyEnabled": true
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-testnet": {
@@ -459,8 +459,8 @@
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-testnet-dydx": {
@@ -486,8 +486,8 @@
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-testnet-nodefleet": {
@@ -513,8 +513,8 @@
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-testnet-kingnodes": {
@@ -540,8 +540,8 @@
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-testnet-liquify": {
@@ -567,8 +567,8 @@
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-testnet-polkachu": {
@@ -594,8 +594,8 @@
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-testnet-bware": {
@@ -621,8 +621,8 @@
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": true
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-mainnet": {
@@ -649,8 +649,8 @@
},
"featureFlags": {
"reduceOnlySupported": false,
"withdrawalSafetyEnabled": false
"usePessimisticCollateralCheck": true
}
}
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+1 -7
View File
@@ -7,12 +7,7 @@ type ElementProps = {
onClick?: () => void;
};
type StyleProps = {
className?: string;
};
export const BackButton = ({
className,
onClick = () => {
// @ts-ignore
const navigation = globalThis.navigation;
@@ -26,9 +21,8 @@ export const BackButton = ({
navigation.navigate('/', { replace: true });
}
},
}: ElementProps & StyleProps) => (
}: ElementProps) => (
<IconButton
className={className}
onClick={onClick}
iconName={IconName.ChevronLeft}
size={ButtonSize.Small}
+18 -78
View File
@@ -47,7 +47,6 @@ type StyleProps = {
hasHeaderBorder?: boolean;
children?: React.ReactNode;
className?: string;
stacked?: boolean;
withAnimation?: boolean;
};
@@ -82,7 +81,6 @@ export const Dialog = ({
slotTrigger,
slotHeaderInner,
slotFooter,
stacked,
withClose = true,
placement = DialogPlacement.Default,
portalContainer,
@@ -111,48 +109,27 @@ export const Dialog = ({
e.preventDefault();
}
}}
$stacked={stacked}
$withAnimation={withAnimation}
>
{stacked ? (
<Styled.StackedHeaderTopRow $withBorder={hasHeaderBorder}>
{onBack && <Styled.BackButton onClick={onBack} />}
<Styled.Header $withBorder={hasHeaderBorder}>
<Styled.HeaderTopRow>
{onBack && <BackButton onClick={onBack} />}
{slotIcon}
{!preventClose && withClose && (
<Styled.Close ref={closeButtonRef} $absolute={stacked}>
<Icon iconName={IconName.Close} />
</Styled.Close>
)}
{slotIcon && <Styled.Icon>{slotIcon}</Styled.Icon>}
{title && <Styled.Title>{title}</Styled.Title>}
{description && <Styled.Description>{description}</Styled.Description>}
{!preventClose && withClose && (
<Styled.Close ref={closeButtonRef}>
<Icon iconName={IconName.Close} />
</Styled.Close>
)}
</Styled.HeaderTopRow>
{slotHeaderInner}
</Styled.StackedHeaderTopRow>
) : (
<Styled.Header $withBorder={hasHeaderBorder}>
<Styled.HeaderTopRow>
{onBack && <BackButton onClick={onBack} />}
{description && <Styled.Description>{description}</Styled.Description>}
{slotIcon && <Styled.Icon>{slotIcon}</Styled.Icon>}
{title && <Styled.Title>{title}</Styled.Title>}
{!preventClose && withClose && (
<Styled.Close ref={closeButtonRef}>
<Icon iconName={IconName.Close} />
</Styled.Close>
)}
</Styled.HeaderTopRow>
{description && <Styled.Description>{description}</Styled.Description>}
{slotHeaderInner}
</Styled.Header>
)}
{slotHeaderInner}
</Styled.Header>
<Styled.Content>{children}</Styled.Content>
@@ -196,11 +173,7 @@ Styled.Overlay = styled(Overlay)`
}
`;
Styled.Container = styled(Content)<{
placement: DialogPlacement;
$stacked?: boolean;
$withAnimation?: boolean;
}>`
Styled.Container = styled(Content)<{ placement: DialogPlacement; $withAnimation?: boolean }>`
/* Params */
--dialog-inset: 1rem;
--dialog-width: 30rem;
@@ -380,13 +353,6 @@ Styled.Container = styled(Content)<{
bottom: 0;
`,
}[placement])}
${({ $stacked }) =>
$stacked &&
css`
justify-content: center;
text-align: center;
`}
`;
Styled.Header = styled.header<{ $withBorder: boolean }>`
@@ -413,21 +379,9 @@ Styled.HeaderTopRow = styled.div`
gap: var(--dialog-title-gap);
`;
Styled.StackedHeaderTopRow = styled.div<{ $withBorder: boolean }>`
${layoutMixins.flexColumn}
align-items: center;
justify-content: center;
padding: var(--dialog-header-paddingTop) var(--dialog-header-paddingLeft)
var(--dialog-header-paddingBottom) var(--dialog-header-paddingRight);
border-top-left-radius: inherit;
border-top-right-radius: inherit;
${({ $withBorder }) =>
$withBorder &&
css`
${layoutMixins.withOuterBorder};
background: var(--dialog-backgroundColor);
`};
Styled.HeaderTopRow = styled.div`
${layoutMixins.row}
gap: var(--dialog-title-gap);
`;
Styled.Content = styled.div`
@@ -458,7 +412,7 @@ Styled.Icon = styled.div`
line-height: 1;
`;
Styled.Close = styled(Close)<{ $absolute?: boolean }>`
Styled.Close = styled(Close)`
width: 0.7813rem;
height: 0.7813rem;
@@ -484,14 +438,6 @@ Styled.Close = styled(Close)<{ $absolute?: boolean }>`
color: var(--color-text-2);
}
${({ $absolute }) =>
$absolute &&
css`
position: absolute;
right: var(--dialog-header-paddingRight);
top: var(--dialog-header-paddingTop);
`}
@media ${breakpoints.tablet} {
width: 1rem;
height: 1rem;
@@ -499,12 +445,6 @@ Styled.Close = styled(Close)<{ $absolute?: boolean }>`
}
`;
Styled.BackButton = styled(BackButton)`
position: absolute;
left: var(--dialog-header-paddingLeft);
top: var(--dialog-header-paddingTop);
`;
Styled.Title = styled(Title)`
flex: 1;
+9
View File
@@ -81,6 +81,9 @@ export enum AnalyticsEvent {
TradePlaceOrderConfirmed = 'TradePlaceOrderConfirmed',
TradeCancelOrder = 'TradeCancelOrder',
TradeCancelOrderConfirmed = 'TradeCancelOrderConfirmed',
// Notification
NotificationAction = 'NotificationAction',
}
export type AnalyticsEventData<T extends AnalyticsEvent> =
@@ -180,6 +183,12 @@ export type AnalyticsEventData<T extends AnalyticsEvent> =
/** URL/IP of node the order was sent to */
validatorUrl: string;
}
: // Notifcation
T extends AnalyticsEvent.NotificationAction
? {
type: string;
id: string;
}
: never;
export const DEFAULT_TRANSACTION_MEMO = 'dYdX Frontend (web)';
+4 -4
View File
@@ -9,11 +9,9 @@ export enum DialogTypes {
FillDetails = 'FillDetails',
Help = 'Help',
ExternalNavKeplr = 'ExternalNavKeplr',
ManageFunds = 'ManageFunds',
MnemonicExport = 'MnemonicExport',
MobileSignIn = 'MobileSignIn',
NewMarketAgreement = 'NewMarketAgreement',
NewMarketMessageDetails = 'NewMarketMessageDetails',
MobileDownload = 'MobileDownload',
Onboarding = 'Onboarding',
OrderDetails = 'OrderDetails',
Preferences = 'Preferences',
@@ -23,7 +21,9 @@ export enum DialogTypes {
Trade = 'Trade',
Transfer = 'Transfer',
Withdraw = 'Withdraw',
WithdrawalGated = 'WithdrawalGated',
ManageFunds = 'ManageFunds',
NewMarketMessageDetails = 'NewMarketMessageDetails',
NewMarketAgreement = 'NewMarketAgreement',
}
export enum TradeBoxDialogTypes {
+5
View File
@@ -143,6 +143,11 @@ export type TransferNotifcation = {
isExchange?: boolean;
};
export enum ReleaseUpdateNotificationIds {
RewardsAndFullTradingLive = 'rewards-and-full-trading-live',
IncentivesS3 = 'incentives-s3',
}
/**
* @description Struct to store whether a NotificationType should be triggered
*/
-4
View File
@@ -7,7 +7,6 @@ import { useDebounce } from './useDebounce';
import { useInterval } from './useInterval';
import { useDocumentTitle } from './useDocumentTitle';
import { useDydxClient } from './useDydxClient';
import { useEnvFeatures } from './useEnvFeatures';
import { useGovernanceVariables } from './useGovernanceVariables';
import { useAccountBalance } from './useAccountBalance';
import { useAccounts } from './useAccounts';
@@ -27,7 +26,6 @@ import { useStringGetter } from './useStringGetter';
import { useSubaccount } from './useSubaccount';
import { useTradeFormInputs } from './useTradeFormInputs';
import { useURLConfigs } from './useURLConfigs';
import { useWithdrawalInfo } from './useWithdrawalInfo';
export {
useApiState,
@@ -38,7 +36,6 @@ export {
useDebounce,
useDocumentTitle,
useDydxClient,
useEnvFeatures,
useGovernanceVariables,
useAccountBalance,
useAccounts,
@@ -59,5 +56,4 @@ export {
useSubaccount,
useTradeFormInputs,
useURLConfigs,
useWithdrawalInfo,
};
+9 -7
View File
@@ -57,13 +57,15 @@ export const useChartLines = ({
useEffect(() => {
if (tvWidget && isChartReady) {
tvWidget.onChartReady(() => {
tvWidget.chart().dataReady(() => {
if (showOrderLines) {
drawOrderLines();
drawPositionLine();
} else {
deleteChartLines();
}
tvWidget.headerReady().then(() => {
tvWidget.chart().dataReady(() => {
if (showOrderLines) {
drawOrderLines();
drawPositionLine();
} else {
deleteChartLines();
}
});
});
});
}
-13
View File
@@ -251,17 +251,6 @@ const useDydxClientContext = () => {
[compositeClient]
);
const getWithdrawalAndTransferGatingStatus = useCallback(async () => {
return await compositeClient?.validatorClient.get.GetWithdrawalAndTransferGatingStatus();
}, [compositeClient]);
const getWithdrawalCapacityByDenom = useCallback(
async ({ denom }: { denom: string }) => {
return await compositeClient?.validatorClient.get.getWithdrawalCapacityByDenom(denom);
},
[compositeClient]
);
return {
// Client initialization
connect: setNetworkConfig,
@@ -278,7 +267,5 @@ const useDydxClientContext = () => {
requestAllGovernanceProposals,
getCandlesForDatafeed,
screenAddresses,
getWithdrawalAndTransferGatingStatus,
getWithdrawalCapacityByDenom,
};
};
-15
View File
@@ -1,15 +0,0 @@
import { useSelector } from 'react-redux';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { getSelectedNetwork } from '@/state/appSelectors';
export interface EnvironmentFeatures {
reduceOnlySupported: boolean;
withdrawalSafetyEnabled: boolean;
}
export const useEnvFeatures = (): EnvironmentFeatures => {
const selectedNetwork = useSelector(getSelectedNetwork);
return ENVIRONMENT_CONFIG_MAP[selectedNetwork].featureFlags;
};
+37 -6
View File
@@ -5,7 +5,7 @@ import { isEqual, groupBy } from 'lodash';
import { useNavigate } from 'react-router-dom';
import { DialogTypes } from '@/constants/dialogs';
import { AppRoute } from '@/constants/routes';
import { AppRoute, TokenRoute } from '@/constants/routes';
import { DydxChainAsset } from '@/constants/wallets';
import {
@@ -20,9 +20,10 @@ import {
NotificationType,
DEFAULT_TOAST_AUTO_CLOSE_MS,
TransferNotificationTypes,
ReleaseUpdateNotificationIds,
} from '@/constants/notifications';
import { useStringGetter } from '@/hooks';
import { useStringGetter, useTokenConfigs } from '@/hooks';
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
import { AssetIcon } from '@/components/AssetIcon';
@@ -238,13 +239,16 @@ export const notificationTypes: NotificationTypeConfig[] = [
{
type: NotificationType.ReleaseUpdates,
useTrigger: ({ trigger }) => {
const { chainTokenLabel } = useTokenConfigs();
const stringGetter = useStringGetter();
const expirationDate = new Date('2024-03-08T23:59:59');
const currentDate = new Date();
useEffect(() => {
trigger(
'rewards-and-full-trading-live',
ReleaseUpdateNotificationIds.RewardsAndFullTradingLive,
{
icon: <AssetIcon symbol="DYDX" />,
icon: <AssetIcon symbol={chainTokenLabel} />,
title: stringGetter({ key: 'NOTIFICATIONS.RELEASE_REWARDS_AND_FULL_TRADING.TITLE' }),
body: stringGetter({
key: 'NOTIFICATIONS.RELEASE_REWARDS_AND_FULL_TRADING.BODY',
@@ -270,14 +274,41 @@ export const notificationTypes: NotificationTypeConfig[] = [
},
}),
toastSensitivity: 'foreground',
groupKey: NotificationType.ReleaseUpdates,
groupKey: ReleaseUpdateNotificationIds.RewardsAndFullTradingLive,
},
[]
);
if (currentDate <= expirationDate) {
trigger(
ReleaseUpdateNotificationIds.IncentivesS3,
{
icon: <AssetIcon symbol={chainTokenLabel} />,
title: stringGetter({ key: 'NOTIFICATIONS.INCENTIVES_SEASON_BEGUN.TITLE' }),
body: stringGetter({
key: 'NOTIFICATIONS.INCENTIVES_SEASON_BEGUN.BODY',
params: {
SEASON_NUMBER: '3',
PREV_SEASON_NUMBER: '1',
DYDX_AMOUNT: '34',
USDC_AMOUNT: '100',
},
}),
toastSensitivity: 'foreground',
groupKey: ReleaseUpdateNotificationIds.IncentivesS3,
},
[]
);
}
}, [stringGetter]);
},
useNotificationAction: () => {
return () => {};
const { chainTokenLabel } = useTokenConfigs();
const navigate = useNavigate();
return (notificationId: string) => {
if (notificationId === ReleaseUpdateNotificationIds.IncentivesS3) {
navigate(`${chainTokenLabel}/${TokenRoute.TradingRewards}`);
}
};
},
},
];
+8 -3
View File
@@ -1,5 +1,6 @@
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { AnalyticsEvent } from '@/constants/analytics';
import { LOCAL_STORAGE_VERSIONS, LocalStorageKey } from '@/constants/localStorage';
import {
type Notification,
@@ -13,7 +14,8 @@ import {
import { useLocalStorage } from './useLocalStorage';
import { notificationTypes } from './useNotificationTypes';
import { renderSvgToDataUrl } from '../lib/renderSvgToDataUrl';
import { track } from '@/lib/analytics';
import { renderSvgToDataUrl } from '@/lib/renderSvgToDataUrl';
type NotificationsContextType = ReturnType<typeof useNotificationsContext>;
@@ -48,6 +50,7 @@ const useNotificationsContext = () => {
defaultValue: {
[NotificationType.AbacusGenerated]: true,
[NotificationType.SquidTransfer]: true,
[NotificationType.ReleaseUpdates]: true,
version: LOCAL_STORAGE_VERSIONS[LocalStorageKey.NotificationPreferences],
},
});
@@ -176,8 +179,10 @@ const useNotificationsContext = () => {
)
);
const onNotificationAction = async (notification: Notification) =>
await actions[notification.type]?.(notification.id);
const onNotificationAction = async (notification: Notification) => {
track(AnalyticsEvent.NotificationAction, { type: notification.type, id: notification.id });
return await actions[notification.type]?.(notification.id);
};
// Push notifications
const [hasEnabledPush, setHasEnabledPush] = useLocalStorage({
-2
View File
@@ -27,7 +27,6 @@ export interface LinksConfigs {
strideZoneApp?: string;
accountExportLearnMore?: string;
walletLearnMore?: string;
withdrawalGateLearnMore?: string;
}
export const useURLConfigs = (): LinksConfigs => {
@@ -55,6 +54,5 @@ export const useURLConfigs = (): LinksConfigs => {
strideZoneApp: linksConfigs.strideZoneApp || FALLBACK_URL,
accountExportLearnMore: linksConfigs.accountExportLearnMore || FALLBACK_URL,
walletLearnMore: linksConfigs.walletLearnMore || FALLBACK_URL,
withdrawalGateLearnMore: linksConfigs.withdrawalGateLearnMore || FALLBACK_URL,
};
};
-131
View File
@@ -1,131 +0,0 @@
import { useEffect, useMemo } from 'react';
import { useQuery } from 'react-query';
import BigNumber from 'bignumber.js';
import { encodeJson } from '@dydxprotocol/v4-client-js';
import { ByteArrayEncoding } from '@dydxprotocol/v4-client-js/build/src/lib/helpers';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { DialogTypes } from '@/constants/dialogs';
import { isMainnet } from '@/constants/networks';
import { useEnvFeatures } from './useEnvFeatures';
import { getApiState } from '@/state/appSelectors';
import { closeDialog, openDialog } from '@/state/dialogs';
import { getSelectedLocale } from '@/state/localizationSelectors';
import { formatRelativeTime } from '@/lib/dateTime';
import { BIG_NUMBERS, MustBigNumber } from '@/lib/numbers';
import { log } from '@/lib/telemetry';
import { useDydxClient } from './useDydxClient';
import { useTokenConfigs } from './useTokenConfigs';
const BLOCK_TIME = isMainnet ? 1_000 : 1_500;
export const useWithdrawalInfo = ({
transferType,
}: {
transferType: 'withdrawal' | 'transfer';
}) => {
const { getWithdrawalAndTransferGatingStatus, getWithdrawalCapacityByDenom } = useDydxClient();
const { usdcDenom, usdcDecimals } = useTokenConfigs();
const apiState = useSelector(getApiState, shallowEqual);
const { height } = apiState || {};
const selectedLocale = useSelector(getSelectedLocale);
const dispatch = useDispatch();
const { withdrawalSafetyEnabled } = useEnvFeatures();
const { data: usdcWithdrawalCapacity } = useQuery({
enabled: withdrawalSafetyEnabled,
queryKey: 'usdcWithdrawalCapacity',
queryFn: async () => {
try {
const response = await getWithdrawalCapacityByDenom({ denom: usdcDenom });
return JSON.parse(encodeJson(response, ByteArrayEncoding.BIGINT));
} catch (error) {
log('useWithdrawalInfo/getWithdrawalCapacityByDenom', error);
}
},
refetchInterval: 60_000,
staleTime: 60_000,
});
const { data: withdrawalAndTransferGatingStatus } = useQuery({
enabled: withdrawalSafetyEnabled,
queryKey: 'withdrawalTransferGateStatus',
queryFn: async () => {
try {
return await getWithdrawalAndTransferGatingStatus();
} catch (error) {
log('useWithdrawalInfo/getWithdrawalAndTransferGatingStatus', error);
}
},
refetchInterval: 60_000,
staleTime: 60_000,
});
const capacity = useMemo(() => {
const capacityList = usdcWithdrawalCapacity?.limiterCapacityList;
if (!capacityList || capacityList.length < 2) {
if (!withdrawalSafetyEnabled) {
return BigNumber(Infinity);
}
return BIG_NUMBERS.ZERO;
}
const [{ capacity: daily }, { capacity: weekly }] = capacityList;
const dailyBN = MustBigNumber(daily);
const weeklyBN = MustBigNumber(weekly);
return BigNumber.minimum(dailyBN, weeklyBN).div(10 ** usdcDecimals);
}, [usdcDecimals, usdcWithdrawalCapacity]);
const withdrawalAndTransferGatingStatusValue = useMemo(() => {
const { withdrawalsAndTransfersUnblockedAtBlock } = withdrawalAndTransferGatingStatus ?? {};
if (
height &&
withdrawalsAndTransfersUnblockedAtBlock &&
height < withdrawalsAndTransfersUnblockedAtBlock &&
withdrawalSafetyEnabled
) {
return {
estimatedUnblockTime: formatRelativeTime(
Date.now() + (withdrawalsAndTransfersUnblockedAtBlock - height) * BLOCK_TIME,
{
locale: selectedLocale,
largestUnit: 'day',
}
),
isGated: true,
};
}
return {
estimatedUnblockTime: null,
isGated: false,
};
}, [height, withdrawalAndTransferGatingStatus, withdrawalSafetyEnabled]);
useEffect(() => {
if (
withdrawalAndTransferGatingStatusValue.isGated &&
withdrawalAndTransferGatingStatusValue.estimatedUnblockTime &&
withdrawalSafetyEnabled
) {
dispatch(closeDialog());
dispatch(
openDialog({
type: DialogTypes.WithdrawalGated,
dialogProps: {
transferType,
estimatedUnblockTime: withdrawalAndTransferGatingStatusValue.estimatedUnblockTime,
},
})
);
}
}, [transferType, withdrawalAndTransferGatingStatusValue.isGated, withdrawalSafetyEnabled]);
return {
usdcWithdrawalCapacity: capacity,
withdrawalAndTransferGatingStatus,
};
};
+7 -7
View File
@@ -11,27 +11,27 @@ import { DepositDialog } from '@/views/dialogs/DepositDialog';
import { DisconnectDialog } from '@/views/dialogs/DisconnectDialog';
import { DisplaySettingsDialog } from '@/views/dialogs/DisplaySettingsDialog';
import { ExchangeOfflineDialog } from '@/views/dialogs/ExchangeOfflineDialog';
import { ExternalNavStrideDialog } from '@/views/dialogs/ExternalNavStrideDialog';
import { HelpDialog } from '@/views/dialogs/HelpDialog';
import { ExternalLinkDialog } from '@/views/dialogs/ExternalLinkDialog';
import { ExternalNavKeplrDialog } from '@/views/dialogs/ExternalNavKeplrDialog';
import { ManageFundsDialog } from '@/views/dialogs/ManageFundsDialog';
import { MnemonicExportDialog } from '@/views/dialogs/MnemonicExportDialog';
import { MobileSignInDialog } from '@/views/dialogs/MobileSignInDialog';
import { NewMarketAgreementDialog } from '@/views/dialogs/NewMarketAgreementDialog';
import { NewMarketMessageDetailsDialog } from '@/views/dialogs/NewMarketMessageDetailsDialog';
import { OnboardingDialog } from '@/views/dialogs/OnboardingDialog';
import { PreferencesDialog } from '@/views/dialogs/PreferencesDialog';
import { RateLimitDialog } from '@/views/dialogs/RateLimitDialog';
import { RestrictedGeoDialog } from '@/views/dialogs/RestrictedGeoDialog';
import { RestrictedWalletDialog } from '@/views/dialogs/RestrictedWalletDialog';
import { TradeDialog } from '@/views/dialogs/TradeDialog';
import { TransferDialog } from '@/views/dialogs/TransferDialog';
import { RestrictedWalletDialog } from '@/views/dialogs/RestrictedWalletDialog';
import { WithdrawDialog } from '@/views/dialogs/WithdrawDialog';
import { WithdrawalGateDialog } from '@/views/dialogs/WithdrawalGateDialog';
import { ManageFundsDialog } from '@/views/dialogs/ManageFundsDialog';
import { OrderDetailsDialog } from '@/views/dialogs/DetailsDialog/OrderDetailsDialog';
import { FillDetailsDialog } from '@/views/dialogs/DetailsDialog/FillDetailsDialog';
import { NewMarketMessageDetailsDialog } from '@/views/dialogs/NewMarketMessageDetailsDialog';
import { NewMarketAgreementDialog } from '@/views/dialogs/NewMarketAgreementDialog';
import { ExternalNavStrideDialog } from '@/views/dialogs/ExternalNavStrideDialog';
import { MobileDownloadDialog } from '@/views/dialogs/MobileDownloadDialog';
export const DialogManager = () => {
const dispatch = useDispatch();
@@ -64,6 +64,7 @@ export const DialogManager = () => {
[DialogTypes.ExternalNavStride]: <ExternalNavStrideDialog {...modalProps} />,
[DialogTypes.MnemonicExport]: <MnemonicExportDialog {...modalProps} />,
[DialogTypes.MobileSignIn]: <MobileSignInDialog {...modalProps} />,
[DialogTypes.MobileDownload]: <MobileDownloadDialog {...modalProps} />,
[DialogTypes.Onboarding]: <OnboardingDialog {...modalProps} />,
[DialogTypes.OrderDetails]: <OrderDetailsDialog {...modalProps} />,
[DialogTypes.Preferences]: <PreferencesDialog {...modalProps} />,
@@ -73,7 +74,6 @@ export const DialogManager = () => {
[DialogTypes.Trade]: <TradeDialog {...modalProps} />,
[DialogTypes.Transfer]: <TransferDialog {...modalProps} />,
[DialogTypes.Withdraw]: <WithdrawDialog {...modalProps} />,
[DialogTypes.WithdrawalGated]: <WithdrawalGateDialog {...modalProps} />,
[DialogTypes.ManageFunds]: <ManageFundsDialog {...modalProps} />,
[DialogTypes.NewMarketMessageDetails]: <NewMarketMessageDetailsDialog {...modalProps} />,
[DialogTypes.NewMarketAgreement]: <NewMarketAgreementDialog {...modalProps} />,
-4
View File
@@ -26,10 +26,6 @@ class TestFlags {
get showTradingRewards() {
return !!this.queryParams.tradingrewards;
}
get showCexWithdrawal() {
return !!this.queryParams.cexwithdrawal;
}
}
export const testFlags = new TestFlags();
-5
View File
@@ -1,5 +0,0 @@
import { ThemeColorBase } from '@/constants/styles/colors';
declare module 'styled-components' {
export interface DefaultTheme extends ThemeColorBase {}
}
+140
View File
@@ -0,0 +1,140 @@
import styled, { AnyStyledComponent, css } from 'styled-components';
import { layoutMixins } from '@/styles/layoutMixins';
import { Dialog } from '@/components/Dialog';
import { QrCode } from '@/components/QrCode';
import { useStringGetter } from '@/hooks';
import { STRING_KEYS } from '@/constants/localization';
type ElementProps = {
setIsOpen: (open: boolean) => void;
};
/*
When/if deployer deploys the web app with smartbanner, "smartbanner:button-url-apple" and/or
"smartbanner:button-url-google" <meta> are set.
This implementation assumes "smartbanner:button-url-apple" and "smartbanner:button-url-google"
are set to the same value with onelink or other redirect URL.
Since there is no way for the desktop web app to know what mobile device the user is using,
we should give a onelink URL which redirects to either iOS or Android app store depending on
the mobile device used to scan the link.
*/
// for testing only
// export const mobileAppUrl = "http://example.com";
let mobileAppUrl: string | undefined | null = undefined;
export const getMobileAppUrl = () => {
if (!mobileAppUrl) {
mobileAppUrl =
// for testing to verify <meta> is retrieved by name, QR code should show "@dYdX" as value
// document.querySelector('meta[name="twitter:creator"]')?.getAttribute('content') ??
document.querySelector('meta[name="smartbanner:button-url-apple"]')?.getAttribute('content') ??
document.querySelector('meta[name="smartbanner:button-url-google"]')?.getAttribute('content');
}
return mobileAppUrl;
}
const MobileQrCode = ({
url,
}: {
url: string;
}) => {
return (
<Styled.QrCodeContainer isShowing={true}>
<QrCode hasLogo size={432} value={url} />
</Styled.QrCodeContainer>
);
};
/*
MobileDownloadDialog should only been shown on desktop when mobileAppUrl has value. That's controlled by AccountMenu.tsx.
*/
export const MobileDownloadDialog = ({ setIsOpen }: ElementProps) => {
const stringGetter = useStringGetter();
const content = (
<MobileQrCode url={mobileAppUrl!} />
);
return (
<Dialog isOpen setIsOpen={setIsOpen} title={
stringGetter({ key: STRING_KEYS.DOWNLOAD_MOBILE_APP })
}>
<Styled.Content>{content}</Styled.Content>
</Dialog>
);
};
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Content = styled.div`
${layoutMixins.column}
gap: 1rem;
strong {
font-weight: 900;
color: var(--color-text-2);
}
footer {
${layoutMixins.row}
justify-content: space-between;
svg {
width: auto;
}
}
`;
Styled.WaitingSpan = styled.span`
strong {
color: var(--color-warning);
}
`;
Styled.QrCodeContainer = styled.figure<{ isShowing: boolean }>`
${layoutMixins.stack}
overflow: hidden;
border-radius: 0.75em;
cursor: pointer;
transition: 0.2s;
&:hover {
filter: brightness(var(--hover-filter-base));
}
> * {
position: relative;
transition: 0.16s;
}
> :first-child {
pointer-events: none;
${({ isShowing }) =>
!isShowing &&
css`
filter: blur(1rem) brightness(1.4);
will-change: filter;
`}
}
> span {
place-self: center;
font-size: 1.4em;
color: var(--color-text-2);
${({ isShowing }) =>
isShowing &&
css`
opacity: 0;
`}
}
`;
-101
View File
@@ -1,101 +0,0 @@
import styled, { AnyStyledComponent } from 'styled-components';
import { ButtonAction, ButtonType } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { useStringGetter, useURLConfigs } from '@/hooks';
import { LinkOutIcon } from '@/icons';
import { layoutMixins } from '@/styles/layoutMixins';
import { Button } from '@/components/Button';
import { Dialog } from '@/components/Dialog';
import { Icon, IconName } from '@/components/Icon';
type ElementProps = {
setIsOpen: (open: boolean) => void;
transferType: 'withdrawal' | 'transfer';
estimatedUnblockTime?: string | null;
};
export const WithdrawalGateDialog = ({
setIsOpen,
estimatedUnblockTime,
transferType,
}: ElementProps) => {
const stringGetter = useStringGetter();
const { withdrawalGateLearnMore } = useURLConfigs();
return (
<Dialog
isOpen
stacked
setIsOpen={setIsOpen}
title={
{
withdrawal: stringGetter({ key: STRING_KEYS.WITHDRAWALS_PAUSED }),
transfer: stringGetter({ key: STRING_KEYS.TRANSFERS_PAUSED }),
}[transferType]
}
slotIcon={
<Styled.IconContainer>
<Styled.Icon iconName={IconName.Warning} />
</Styled.IconContainer>
}
slotFooter={
<Styled.ButtonRow>
<Button
type={ButtonType.Link}
action={ButtonAction.Secondary}
href={withdrawalGateLearnMore}
>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
<LinkOutIcon />
</Button>
<Button action={ButtonAction.Primary} onClick={() => setIsOpen(false)}>
{stringGetter({ key: STRING_KEYS.CLOSE })}
</Button>
</Styled.ButtonRow>
}
>
<Styled.Content>
{stringGetter({
key: STRING_KEYS.WITHDRAWALS_PAUSED_DESC,
params: {
ESTIMATED_DURATION: estimatedUnblockTime,
},
})}
</Styled.Content>
</Dialog>
);
};
const Styled: Record<string, AnyStyledComponent> = {};
Styled.IconContainer = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 4.5rem;
height: 4.5rem;
border-radius: 50%;
min-width: 4.5rem;
min-height: 4.5rem;
background-color: var(--color-gradient-warning);
`;
Styled.Icon = styled(Icon)`
color: var(--color-warning);
font-size: 2.5rem;
margin-bottom: 0.125rem;
`;
Styled.Content = styled.div`
${layoutMixins.column}
gap: 1rem;
`;
Styled.ButtonRow = styled.div`
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
`;
@@ -63,12 +63,11 @@ export const SourceSelectMenu = ({
return (
<SearchSelectMenu
items={[
exchangeItems.length > 0 &&
(testFlags.showCexWithdrawal || type === TransferType.deposit) && {
group: 'exchanges',
groupLabel: stringGetter({ key: STRING_KEYS.EXCHANGES }),
items: exchangeItems,
},
exchangeItems.length > 0 && {
group: 'exchanges',
groupLabel: stringGetter({ key: STRING_KEYS.EXCHANGES }),
items: exchangeItems,
},
chainItems.length > 0 && {
group: 'chains',
groupLabel: stringGetter({ key: STRING_KEYS.CHAINS }),
@@ -17,7 +17,6 @@ import {
MAX_PRICE_IMPACT,
MIN_CCTP_TRANSFER_AMOUNT,
NumberSign,
TOKEN_DECIMALS,
} from '@/constants/numbers';
import {
@@ -28,8 +27,6 @@ import {
useSelectedNetwork,
useStringGetter,
useSubaccount,
useTokenConfigs,
useWithdrawalInfo,
} from '@/hooks';
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
@@ -88,8 +85,6 @@ export const WithdrawForm = () => {
const [withdrawAmount, setWithdrawAmount] = useState('');
const [slippage, setSlippage] = useState(isCctp ? 0 : 0.01); // 0.1% slippage
const debouncedAmount = useDebounce<string>(withdrawAmount, 500);
const { usdcLabel } = useTokenConfigs();
const { usdcWithdrawalCapacity } = useWithdrawalInfo({ transferType: 'withdrawal' });
const isValidAddress = toAddress && isAddress(toAddress);
@@ -326,102 +321,61 @@ export const WithdrawForm = () => {
const { sanctionedAddresses } = useRestrictions();
const { alertType, errorMessage } = useMemo(() => {
const errorMessage = useMemo(() => {
if (error) {
return {
errorMessage: error,
};
return error;
}
if (routeErrors) {
return {
errorMessage: routeErrorMessage
? stringGetter({
key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
params: { ERROR_MESSAGE: routeErrorMessage },
})
: stringGetter({ key: STRING_KEYS.SOMETHING_WENT_WRONG }),
};
return routeErrorMessage
? stringGetter({
key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
params: { ERROR_MESSAGE: routeErrorMessage },
})
: stringGetter({ key: STRING_KEYS.SOMETHING_WENT_WRONG });
}
if (!toAddress) {
return {
alertType: AlertType.Warning,
errorMessage: stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_ADDRESS }),
};
}
if (!toAddress) return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_ADDRESS });
if (sanctionedAddresses.has(toAddress))
return {
errorMessage: stringGetter({
key: STRING_KEYS.TRANSFER_INVALID_DYDX_ADDRESS,
}),
};
return stringGetter({
key: STRING_KEYS.TRANSFER_INVALID_DYDX_ADDRESS,
});
if (debouncedAmountBN) {
if (!chainIdStr && !exchange) {
return {
errorMessage: stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_CHAIN }),
};
return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_CHAIN });
} else if (!toToken) {
return {
errorMessage: stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_ASSET }),
};
return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_ASSET });
}
}
if (debouncedAmountBN.gt(MustBigNumber(freeCollateralBN))) {
return {
errorMessage: stringGetter({ key: STRING_KEYS.WITHDRAW_MORE_THAN_FREE }),
};
if (MustBigNumber(debouncedAmountBN).gt(MustBigNumber(freeCollateralBN))) {
return stringGetter({ key: STRING_KEYS.WITHDRAW_MORE_THAN_FREE });
}
if (isCctp) {
if (debouncedAmountBN.gte(MAX_CCTP_TRANSFER_AMOUNT)) {
return {
errorMessage: stringGetter({
key: STRING_KEYS.MAX_CCTP_TRANSFER_LIMIT_EXCEEDED,
params: {
MAX_CCTP_TRANSFER_AMOUNT: MAX_CCTP_TRANSFER_AMOUNT,
},
}),
};
if (MustBigNumber(debouncedAmountBN).gte(MAX_CCTP_TRANSFER_AMOUNT)) {
return stringGetter({
key: STRING_KEYS.MAX_CCTP_TRANSFER_LIMIT_EXCEEDED,
params: {
MAX_CCTP_TRANSFER_AMOUNT: MAX_CCTP_TRANSFER_AMOUNT,
},
});
}
if (
!debouncedAmountBN.isZero() &&
MustBigNumber(debouncedAmountBN).lte(MIN_CCTP_TRANSFER_AMOUNT)
) {
return {
errorMessage: 'Amount must be greater than 10 USDC',
};
return 'Amount must be greater than 10 USDC';
}
}
if (isMainnet && MustBigNumber(summary?.aggregatePriceImpact).gte(MAX_PRICE_IMPACT)) {
return { errorMessage: stringGetter({ key: STRING_KEYS.PRICE_IMPACT_TOO_HIGH }) };
return stringGetter({ key: STRING_KEYS.PRICE_IMPACT_TOO_HIGH });
}
// Withdrawal Safety
if (usdcWithdrawalCapacity.gt(0) && debouncedAmountBN.gt(usdcWithdrawalCapacity)) {
return {
alertType: AlertType.Warning,
errorMessage: stringGetter({
key: STRING_KEYS.WITHDRAWAL_LIMIT_OVER,
params: {
USDC_LIMIT: (
<span>
{usdcWithdrawalCapacity.toFormat(TOKEN_DECIMALS)}
<Styled.Tag>{usdcLabel}</Styled.Tag>
</span>
),
},
}),
};
}
return {
errorMessage: undefined,
};
return undefined;
}, [
error,
routeErrors,
@@ -434,7 +388,6 @@ export const WithdrawForm = () => {
sanctionedAddresses,
stringGetter,
summary,
usdcWithdrawalCapacity,
]);
const isInvalidNobleAddress = Boolean(
@@ -495,11 +448,7 @@ export const WithdrawForm = () => {
}
/>
</Styled.WithDetailsReceipt>
{errorMessage && (
<Styled.AlertMessage type={alertType ?? AlertType.Error}>
{errorMessage}
</Styled.AlertMessage>
)}
{errorMessage && <AlertMessage type={AlertType.Error}>{errorMessage}</AlertMessage>}
<Styled.Footer>
<WithdrawButtonAndReceipt
isDisabled={isDisabled}
@@ -516,10 +465,6 @@ export const WithdrawForm = () => {
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Tag = styled(Tag)`
margin-left: 0.5ch;
`;
Styled.DiffOutput = styled(DiffOutput)`
--diffOutput-valueWithDiff-fontSize: 1em;
`;
@@ -539,10 +484,6 @@ Styled.DestinationRow = styled.div`
gap: 1rem;
`;
Styled.AlertMessage = styled(AlertMessage)`
display: inline;
`;
Styled.WithDetailsReceipt = styled(WithDetailsReceipt)`
--withReceipt-backgroundColor: var(--color-layer-2);
`;
-2
View File
@@ -20,7 +20,6 @@ import {
useStringGetter,
useSubaccount,
useTokenConfigs,
useWithdrawalInfo,
} from '@/hooks';
import { formMixins } from '@/styles/formMixins';
@@ -65,7 +64,6 @@ export const TransferForm = ({
const { nativeTokenBalance, usdcBalance } = useAccountBalance();
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const { tokensConfigs, usdcLabel, chainTokenLabel } = useTokenConfigs();
useWithdrawalInfo({ transferType: 'transfer' });
const {
address: recipientAddress,
+13
View File
@@ -40,6 +40,7 @@ import { getAppTheme } from '@/state/configsSelectors';
import { isTruthy } from '@/lib/isTruthy';
import { truncateAddress } from '@/lib/wallet';
import { MustBigNumber } from '@/lib/numbers';
import { getMobileAppUrl } from '../dialogs/MobileDownloadDialog';
export const AccountMenu = () => {
const stringGetter = useStringGetter();
@@ -189,6 +190,18 @@ export const AccountMenu = () => {
label: stringGetter({ key: STRING_KEYS.DISPLAY_SETTINGS }),
onSelect: () => dispatch(openDialog({ type: DialogTypes.DisplaySettings })),
},
...(getMobileAppUrl()
? [
{
value: 'MobileDownload',
icon: <Icon iconName={IconName.Qr} />,
label: stringGetter({ key: STRING_KEYS.DOWNLOAD_MOBILE_APP }),
onSelect: () => {
dispatch(openDialog({ type: DialogTypes.MobileDownload }));
},
},
]
: []),
...(onboardingState === OnboardingState.AccountConnected && hdKey
? [
{
+1 -1
View File
@@ -22,6 +22,6 @@
"@/*": ["src/*"]
}
},
"include": ["src", "scripts", "styled.d.ts"],
"include": ["src", "scripts"],
"references": [{ "path": "./tsconfig.node.json" }]
}