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
Bill 7f947804bd Enable CCTP onboarding for avalanche, optimism (#310)
* Enable CCTP for arbitrum avalanche optimism

* Enable CCTP onboarding for arbitrum, avalanche, optimism

* remove arb
2024-02-19 20:18:57 -08:00
aleka 6620a70a5d fix parsing error and surface tx broadcast error (#313)
* fix parsing error and surface tx broadcast error

* fix network as chain id
2024-02-19 22:06:13 -05:00
Bill bff779631b Cex withdraw (#301)
* Coinbase withdrawal and deposit UI

* analytics

* packages bumps

* address comments

* address comments

* add test flag
2024-02-16 17:56:06 -08:00
yujin512 b115bf33a0 Update markets.json (#311)
update ORDI asset name
2024-02-16 10:54:13 -08:00
aleka b544b8202b fetch chaos labs latest season (#309)
* fetch chaos labs latest season

* safer access
2024-02-16 11:09:48 -05:00
yujin512 ad6f99ffdf add icons and metadata (#305)
* add icons

* Update otherMarketParameters.json

update numOracles for markets with robust DEX oracles (not currently queryable)

* Update otherMarketParameters.json

update numOracles for markets with robust DEX oracles

* update asset name to match cmc

* Update otherMarketParameters.json

* add icons for other markets

* fix url and market name
2024-02-16 09:44:08 -05:00
Bill a7bd6a3ee8 host amplitude script ourselves (#307)
* host amplitude script ourselves

* update sha
2024-02-15 15:45:44 -08:00
aleka c92f218493 bump abacus + use new env config format (#298)
* bump abacus + use new env config format

* use new config path

* bump abacus to 1.4.5

* util function for getting mintscan link
2024-02-15 13:38:05 -05:00
moo-onthelawn b09fe9ebb1 fix bug (#304) 2024-02-14 15:19:37 -08:00
Bill 1c28505ec0 Set minimum for CCTP withdraws (#306) 2024-02-14 14:59:04 -08:00
moo-onthelawn 5531e21c76 change text color (#302) 2024-02-14 14:29:38 -05:00
John Huang 4ebeb21841 MOB-231 Refactor env.json to env2.json (#303)
* MOB-231 Refactor env.json to env2.json

* Move to v1/env.json

* dydx-testnet-4
2024-02-14 13:37:51 -05:00
83 changed files with 1531 additions and 260 deletions
+1
View File
@@ -1 +1,2 @@
node_modules/
public/
+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.2",
"@dydxprotocol/v4-abacus": "^1.4.12",
"@dydxprotocol/v4-client-js": "^1.0.20",
"@dydxprotocol/v4-localization": "^1.1.30",
"@dydxprotocol/v4-localization": "^1.1.35",
"@ethersproject/providers": "^5.7.2",
"@js-joda/core": "^5.5.3",
"@radix-ui/react-accordion": "^1.1.2",
+8 -8
View File
@@ -30,14 +30,14 @@ dependencies:
specifier: ^0.32.1
version: 0.32.2
'@dydxprotocol/v4-abacus':
specifier: ^1.4.2
version: 1.4.2
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.30
version: 1.1.30
specifier: ^1.1.35
version: 1.1.35
'@ethersproject/providers':
specifier: ^5.7.2
version: 5.7.2
@@ -1290,8 +1290,8 @@ packages:
resolution: {integrity: sha512-Gg5t+eR7vPJMAmhkFt6CZrzPd0EKpAslWwk5rFVYZpJsM8JG5KT9XQ99hgNM3Ov6ScNoIWbXkpX27F6A9cXR4Q==}
dev: false
/@dydxprotocol/v4-abacus@1.4.2:
resolution: {integrity: sha512-+hugk0RulMwMthR2xCMYXohcC3sEYqVW/lmiq0RUuHZ9yrjmgy48xl0aZUmXGUYXyoiHXPS4AULhRKHQ4OOLwg==}
/@dydxprotocol/v4-abacus@1.4.12:
resolution: {integrity: sha512-dNQFaNrLTujyViMH2JEtf9Vn2ew2le+qTWexktK5h7AeADBbS9uxQknMIFhfwzGkbS1QqqszBT1plrDmQ+E6nQ==}
dev: false
/@dydxprotocol/v4-client-js@1.0.20:
@@ -1323,8 +1323,8 @@ packages:
- utf-8-validate
dev: false
/@dydxprotocol/v4-localization@1.1.30:
resolution: {integrity: sha512-TZfWWRSOxcjLHs972wlJVVHkE7+DVqAUnGZSs24HYHsPtUkPhZiNXMOA2Vk9YddQxumhM79xIRH0cmJSe5DDUg==}
/@dydxprotocol/v4-localization@1.1.35:
resolution: {integrity: sha512-q5JFYoL/QanHXOtFqRa2owBZJibi1sMpSm3dAcxs9x0/xe8mo6fWcnbQfhl8k7g0/tv7PsBc+e3rbWD0EfvGiA==}
dev: false
/@dydxprotocol/v4-proto@4.0.0-dev.0:
+21 -11
View File
@@ -1,12 +1,22 @@
[
{
"chainId": "1",
"tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "Ethereum"
},
{
"chainId": "5",
"tokenAddress": "0x07865c6E87B9F70255377e024ace6630C1Eaa37F",
"name": "Ethereum Goerli"
}
]
{
"chainId": "1",
"tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "Ethereum"
},
{
"chainId": "5",
"tokenAddress": "0x07865c6E87B9F70255377e024ace6630C1Eaa37F",
"name": "Ethereum Goerli"
},
{
"chainId": "43114",
"tokenAddress": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
"name": "Avalanche"
},
{
"chainId": "10",
"tokenAddress": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
"name": "optimism"
}
]
+8 -8
View File
@@ -725,7 +725,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet-dydx": {
@@ -812,7 +812,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet-nodefleet": {
@@ -899,7 +899,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet-kingnodes": {
@@ -986,7 +986,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet-liquify": {
@@ -1073,7 +1073,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet-polkachu": {
@@ -1151,7 +1151,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false
"reduceOnlySupported": true
}
},
"dydxprotocol-testnet-bware": {
@@ -1238,7 +1238,7 @@
}
},
"featureFlags": {
"reduceOnlySupported": false
"reduceOnlySupported": true
}
},
"dydxprotocol-mainnet": {
@@ -1329,4 +1329,4 @@
}
}
}
}
}
+162 -1
View File
@@ -20,6 +20,13 @@
"whitepaperLink": "https://why.cardano.org/en/introduction/motivation/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/cardano/"
},
"AGIX-USD": {
"name": "SingularityNET",
"tags": ["AI"],
"websiteLink": "https://public.singularitynet.io/whitepaper.pdf",
"whitepaperLink": "https://public.singularitynet.io/whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/singularitynet/"
},
"ALGO-USD": {
"name": "Algorand",
"tags": ["Layer 1"],
@@ -78,7 +85,7 @@
},
"BLUR-USD": {
"name": "Blur",
"tags": [],
"tags": ["NFT"],
"websiteLink": "https://blur.io/",
"whitepaperLink": "https://docs.blur.foundation/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/blur-token/"
@@ -91,6 +98,13 @@
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/bnb/"
},
"CHZ-USD": {
"name": "Chiliz",
"tags": ["Layer 1"],
"websiteLink": "https://www.chiliz.com/",
"whitepaperLink": "https://www.chiliz.com/docs/litepaper-v1.1-20230703.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/chiliz/"
},
"CELO-USD": {
"name": "Celo",
"tags": [],
@@ -147,6 +161,13 @@
"whitepaperLink": "https://cdn.enjin.io/downloads/whitepapers/enjin-coin/en.pdf/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/enjin-coin/"
},
"ENS-USD": {
"name": "Ethereum Name Service",
"tags": [],
"websiteLink": "https://coinmarketcap.com/currencies/ethereum-name-service/",
"whitepaperLink": "https://docs.ens.domains/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/ethereum-name-service/"
},
"EOS-USD": {
"name": "EOS",
"tags": ["Layer 1"],
@@ -170,6 +191,13 @@
"displayStepSize": "0.001",
"displayTickSize": "0.1"
},
"FET-USD": {
"name": "Fetch.ai",
"tags": ["AI"],
"websiteLink": "https://fetch.ai/",
"whitepaperLink": "https://www.dropbox.com/s/gxptsecwdl3jjtn/David%20Minarsch%20-%202021-04-26%2010.34.17%20-%20paper_21_finalversion.pdf?e=1&dl=0",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/fetch/"
},
"FIL-USD": {
"name": "Filecoin",
"tags": ["Layer 1"],
@@ -177,6 +205,34 @@
"whitepaperLink": "https://filecoin.io/filecoin.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/filecoin/"
},
"FTM-USD": {
"name": "Fantom",
"tags": [],
"websiteLink": "https://fantom.foundation/",
"whitepaperLink": "https://fantom.foundation/_next/static/media/wp_fantom_v1.6.39329cdc5d0ee59684cbc6f228516383.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/fantom/"
},
"GALA-USD": {
"name": "Gala",
"tags": ["Gaming", "Layer 1"],
"websiteLink": "https://gala.com/",
"whitepaperLink": "https://galahackathon.com/v1.0.0/pdf/sdk-documentation.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/gala/"
},
"GMT-USD": {
"name": "GMT",
"tags": ["Gaming"],
"websiteLink": "https://stepn.com/",
"whitepaperLink/": "https://whitepaper.stepn.com/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/green-metaverse-token/"
},
"GRT-USD": {
"name": "The Graph",
"tags": [],
"websiteLink": "https://thegraph.com/",
"whitepaperLink/": "https://github.com/graphprotocol/research/blob/master/papers/whitepaper/the-graph-whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/the-graph/"
},
"HNT-USD": {
"name": "Helium",
"tags": ["Layer 1"],
@@ -184,6 +240,13 @@
"whitepaperLink": "http://whitepaper.helium.com",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/helium/"
},
"HBAR-USD": {
"name": "Hedera",
"tags": [],
"websiteLink": "https://hedera.com/",
"whitepaperLink/": "https://files.hedera.com/hh_whitepaper_v2.2-20230918.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/hedera/"
},
"ICP-USD": {
"name": "Internet Computer",
"tags": ["Layer 1"],
@@ -191,6 +254,27 @@
"whitepaperLink": "https://dfinity.org/whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/internet-computer/"
},
"IMX-USD": {
"name": "Immutable X",
"tags": ["Gaming", "Layer 2", "NFT"],
"websiteLink": "https://www.immutable.com/",
"whitepaperLink": "https://assets.website-files.com/646557ee455c3e16e4a9bcb3/6499367de527dd82ab7475a3_Immutable%20Whitepaper%20Update%202023%20(3).pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/immutable-x/"
},
"INJ-USD": {
"name": "Injective",
"tags": ["Layer 1", "Defi"],
"websiteLink": "https://injective.com/",
"whitepaperLink": "https://docs.injective.network/intro/01_overview.html",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/injective/"
},
"JTO-USD": {
"name": "Jito",
"tags": ["Defi"],
"websiteLink": "https://www.jito.network/",
"whitepaperLink": "https://github.com/jito-foundation",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/jito/"
},
"JUP-USD": {
"name": "Jupiter",
"tags": ["Defi"],
@@ -198,6 +282,13 @@
"whitepaperLink": "https://station.jup.ag/blog/green-paper",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/jupiter-ag/"
},
"KAVA-USD": {
"name": "Kava",
"tags": ["Layer 1"],
"websiteLink": "https://www.kava.io/",
"whitepaperLink": "https://docsend.com/view/gwbwpc3",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/kava/"
},
"LDO-USD": {
"name": "Lido DAO",
"tags": ["Defi"],
@@ -219,6 +310,20 @@
"whitepaperLink": "https://litecoin.info/index.php/Main_Page",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/litecoin/"
},
"MANA-USD": {
"name": "Decentraland",
"tags": ["AR/VR"],
"websiteLink": "https://decentraland.org/",
"whitepaperLink": "https://decentraland.org/whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/decentraland/"
},
"MASK-USD": {
"name": "Mask Network",
"tags": [],
"websiteLink": "https://mask.io/",
"whitepaperLink": "https://masknetwork.medium.com/introducing-mask-network-maskbook-the-future-of-the-internet-5a973d874edd",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/mask-network/"
},
"MATIC-USD": {
"name": "Polygon",
"tags": ["Layer 2"],
@@ -226,6 +331,13 @@
"whitepaperLink": "https://polygon.technology/lightpaper-polygon.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/polygon/"
},
"MINA-USD": {
"name": "Mina",
"tags": ["Layer 1"],
"websiteLink": "https://minaprotocol.com/",
"whitepaperLink": "https://docs.minaprotocol.com/assets/economicsWhitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/mina/"
},
"MKR-USD": {
"name": "Maker",
"tags": ["Governance"],
@@ -240,6 +352,13 @@
"whitepaperLink": "https://near.org/papers/the-official-near-white-paper/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/near-protocol/"
},
"ORDI-USD": {
"name": "Ordinals",
"tags": ["NFT"],
"websiteLink": "https://ordinals.com/",
"whitepaperLink": "https://rodarmor.com/blog/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/ordi/"
},
"OP-USD": {
"name": "Optimism",
"tags": [],
@@ -253,6 +372,20 @@
"websiteLink": "https://www.pepe.vip/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/pepe/"
},
"PYTH-USD": {
"name": "Pyth Network",
"tags": [],
"websiteLink": "https://pyth.network/",
"whitepaperLink": "https://pyth.network/whitepaper_v2.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/pyth-network/"
},
"RNDR-USD": {
"name": "Render Token",
"tags": ["AI"],
"websiteLink": "https://rendernetwork.com/",
"whitepaperLink": "https://renderfoundation.com/whitepaper",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/render/"
},
"RUNE-USD": {
"name": "THORChain",
"tags": ["Layer 1"],
@@ -260,6 +393,13 @@
"whitepaperLink": "https://whitepaper.io/document/709/thorchain-whitepaper",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/thorchain/"
},
"SAND-USD": {
"name": "The Sandbox",
"tags": ["Gaming"],
"websiteLink": "https://www.sandbox.game/en/",
"whitepaperLink": "https://installers.sandbox.game/The_Sandbox_Whitepaper_2020.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/the-sandbox/"
},
"SEI-USD": {
"name": "Sei",
"tags": ["Layer 1", "Defi"],
@@ -288,6 +428,20 @@
"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"],
"websiteLink": "https://www.stacks.co/",
"whitepaperLink": "https://gaia.blockstack.org/hub/1AxyPunHHAHiEffXWESKfbvmBpGQv138Fp/stacks.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/stacks/"
},
"SUI-USD": {
"name": "Sui",
"tags": ["Layer 1"],
@@ -337,6 +491,13 @@
"whitepaperLink": "https://whitepaper.worldcoin.org/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/worldcoin-org/"
},
"WOO-USD": {
"name": "WOO Network",
"tags": ["Defi"],
"websiteLink": "https://woo.org/",
"whitepaperLink": "https://woo.org/Litepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/wootrade/"
},
"XLM-USD": {
"name": "Stellar",
"tags": ["Layer 1"],
@@ -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" },
+29 -12
View File
@@ -274,7 +274,7 @@
{
"baseAsset": "CRV",
"referencePrice": 0.48346754113361784,
"numOracles": 5,
"numOracles": 6,
"liquidityTier": 2,
"assetName": "Curve DAO Token",
"p": -1.0,
@@ -325,7 +325,7 @@
{
"baseAsset": "DYM",
"referencePrice": 5.544949130771594,
"numOracles": 5,
"numOracles": 6,
"liquidityTier": 2,
"assetName": "Dymension",
"p": 0.0,
@@ -412,7 +412,7 @@
"referencePrice": 0.5560893147613742,
"numOracles": 6,
"liquidityTier": 2,
"assetName": "Fetch AI",
"assetName": "Fetch.ai",
"p": -1.0,
"atomicResolution": -5.0,
"minExchanges": 3,
@@ -480,7 +480,7 @@
"referencePrice": 0.20404992804891367,
"numOracles": 6,
"liquidityTier": 2,
"assetName": "STEPN",
"assetName": "GMT",
"p": -1.0,
"atomicResolution": -5.0,
"minExchanges": 3,
@@ -514,7 +514,7 @@
"referencePrice": 0.07686278766140874,
"numOracles": 6,
"liquidityTier": 2,
"assetName": "Hedera Hashgraph",
"assetName": "Hedera",
"p": -2.0,
"atomicResolution": -4.0,
"minExchanges": 3,
@@ -565,7 +565,7 @@
"referencePrice": 33.427379051845875,
"numOracles": 7,
"liquidityTier": 2,
"assetName": "Injective Protocol",
"assetName": "Injective",
"p": 1.0,
"atomicResolution": -7.0,
"minExchanges": 3,
@@ -597,7 +597,7 @@
{
"baseAsset": "JUP",
"referencePrice": 0.4339790660244292,
"numOracles": 5,
"numOracles": 6,
"liquidityTier": 2,
"assetName": "Jupiter",
"p": -1.0,
@@ -750,7 +750,7 @@
{
"baseAsset": "MKR",
"referencePrice": 1943.1865605831852,
"numOracles": 5,
"numOracles": 6,
"liquidityTier": 2,
"assetName": "Maker",
"p": 3.0,
@@ -869,7 +869,7 @@
{
"baseAsset": "RUNE",
"referencePrice": 3.7264809096406806,
"numOracles": 5,
"numOracles": 6,
"liquidityTier": 2,
"assetName": "Thorchain",
"p": 0.0,
@@ -888,7 +888,7 @@
"referencePrice": 0.37297439115035663,
"numOracles": 6,
"liquidityTier": 2,
"assetName": "SAND",
"assetName": "The Sandbox",
"p": -1.0,
"atomicResolution": -5.0,
"minExchanges": 3,
@@ -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,
@@ -1073,9 +1090,9 @@
{
"baseAsset": "WOO",
"referencePrice": 0.2944897275608197,
"numOracles": 5,
"numOracles": 6,
"liquidityTier": 2,
"assetName": "Wootrade Network",
"assetName": "WOO Network",
"p": -1.0,
"atomicResolution": -5.0,
"minExchanges": 3,
+656
View File
@@ -0,0 +1,656 @@
{
"apps": {
"ios": {
"scheme": "dydx-t-v4"
}
},
"tokens": {
"dydxprotocol-testnet": {
"chain": {
"name": "Dv4TNT",
"denom": "adv4tnt",
"decimals": 18,
"image": "/currencies/dydx.png"
},
"usdc": {
"name": "USDC",
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
"gasDenom": "uusdc",
"decimals": 6,
"image": "/currencies/usdc.png"
}
},
"dydx-testnet-4": {
"chain": {
"name": "Dv4TNT",
"denom": "adv4tnt",
"decimals": 18,
"image": "/currencies/dydx.png"
},
"usdc": {
"name": "USDC",
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
"gasDenom": "uusdc",
"decimals": 6,
"image": "/currencies/usdc.png"
}
},
"[mainnet chain id]": {
"comment": "Change according to mainnet release",
"chain": {
"name": "TokenName",
"denom": "tokenDenom",
"decimals": 18,
"image": "/currencies/dydx.png"
},
"usdc": {
"name": "USDC",
"denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
"gasDenom": "uusdc",
"decimals": 6,
"image": "/currencies/usdc.png"
}
}
},
"links": {
"dydxprotocol-testnet": {
"tos": "https://dydx.exchange/v4-terms",
"privacy": "https://dydx.exchange/privacy",
"statusPage": "https://status.v4testnet.dydx.exchange/",
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
"blogs": "https://www.dydx.foundation/blog",
"foundation": "https://www.dydx.foundation",
"help": "https://help.dydx.exchange/",
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
"documentation": "https://docs.dydx.exchange/",
"community": "https://discord.com/invite/dydx",
"governanceLearnMore": "https://help.dydx.exchange",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange",
"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",
"launchIncentive": "https://cloud.chaoslabs.co/"
},
"dydx-testnet-4": {
"tos": "https://dydx.exchange/v4-terms",
"privacy": "https://dydx.exchange/privacy",
"statusPage": "https://status.v4testnet.dydx.exchange/",
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
"documentation": "https://docs.dydx.exchange/",
"community": "https://discord.com/invite/dydx",
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
"blogs": "https://www.dydx.foundation/blog",
"foundation": "https://www.dydx.foundation",
"help": "https://help.dydx.exchange/",
"reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders",
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
"governanceLearnMore": "https://help.dydx.exchange",
"newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals",
"stakingLearnMore": "https://help.dydx.exchange",
"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",
"launchIncentive": "https://cloud.chaoslabs.co/"
},
"[mainnet chain id]": {
"tos": "[HTTP link to TOS]",
"privacy": "[HTTP link to Privacy Policy]",
"statusPage": "[HTTP link to status page]",
"mintscan": "[HTTP link to Mintscan, with {tx_hash} placeholder]",
"mintscanBase": "[HTTP link to TOS mintscan base url]",
"feedback": "[HTTP link to feedback form, can be null]",
"blogs": "[HTTP link to blogs, can be null]",
"foundation": "[HTTP link to foundation, can be null]",
"reduceOnlyLearnMore": "[HTTP link to reduce-only learn more, can be null]",
"documentation": "[HTTP link to documentation, can be null]",
"community": "[HTTP link to community, can be null]",
"help": "[HTTP link to help page, can be null]",
"governanceLearnMore": "[HTTP link to governance learn more, can be null]",
"newMarketProposalLearnMore": "[HTTP link to new market proposal learn more, can be null]",
"stakingLearnMore": "[HTTP link to staking learn more, can be null]",
"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]",
"launchIncentive": "[HTTP link to launch incentive host, can be null]"
}
},
"wallets": {
"dydxprotocol-testnet": {
"walletconnect": {
"client": {
"name": "dYdX v4",
"description": "dYdX v4 App",
"iconUrl": "/logos/dydx-x.png"
},
"v2": {
"projectId": "47559b2ec96c09aed9ff2cb54a31ab0e"
}
},
"walletSegue": {
"callbackUrl": "/walletsegue"
},
"images": "/wallets/",
"signTypedDataAction": "dYdX Chain Onboarding",
"signTypedDataDomainName": "dYdX Chain"
},
"dydx-testnet-4": {
"walletconnect": {
"client": {
"name": "dYdX v4",
"description": "dYdX v4 App",
"iconUrl": "/logos/dydx-x.png"
},
"v2": {
"projectId": "47559b2ec96c09aed9ff2cb54a31ab0e"
}
},
"walletSegue": {
"callbackUrl": "/walletsegue"
},
"images": "/wallets/",
"signTypedDataAction": "dYdX Chain Onboarding",
"signTypedDataDomainName": "dYdX Chain"
},
"[mainnet chain id]": {
"walletconnect": {
"client": {
"name": "[Name of the app]",
"description": "[Description of the app]",
"iconUrl": "[Relative URL of the icon URL]"
},
"v2": {
"projectId": "[Project ID]"
}
},
"walletSegue": {
"callbackUrl": "[Relative callback URL for WalletSegue, should match apple-app-site-association]"
},
"images": "[Relative URL for wallet images]",
"signTypedDataAction": "dYdX Chain Onboarding",
"signTypedDataDomainName": "dYdX Chain"
}
},
"governance": {
"dydxprotocol-testnet": {
"newMarketProposal": {
"initialDepositAmount": 10000000,
"delayBlocks": 900,
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
}
},
"dydx-testnet-4": {
"newMarketProposal": {
"initialDepositAmount": 10000000,
"delayBlocks": 900,
"newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing"
}
},
"[mainnet chain id]": {
"newMarketProposal": {
"initialDepositAmount": 0,
"delayBlocks": 0,
"newMarketsMethodology": "[URL to spreadsheet or document that explains methodology]"
}
}
},
"deployments": {
"MAINNET": {
"environments": [
"dydxprotocol-mainnet"
],
"default": "dydxprotocol-mainnet"
},
"TESTFLIGHT": {
"environments": [
"dydxprotocol-mainnet",
"dydxprotocol-testnet"
],
"default": "dydxprotocol-mainnet"
},
"TESTNET": {
"environments": [
"dydxprotocol-testnet"
],
"default": "dydxprotocol-testnet"
},
"DEV": {
"environments": [
"dydxprotocol-dev",
"dydxprotocol-dev-2",
"dydxprotocol-dev-4",
"dydxprotocol-dev-5",
"dydxprotocol-staging",
"dydxprotocol-staging-west",
"dydxprotocol-testnet",
"dydxprotocol-testnet-dydx",
"dydxprotocol-testnet-nodefleet",
"dydxprotocol-testnet-kingnodes",
"dydxprotocol-testnet-liquify",
"dydxprotocol-testnet-polkachu",
"dydxprotocol-testnet-bware"
],
"default": "dydxprotocol-testnet"
}
},
"environments": {
"dydxprotocol-dev": {
"name": "v4 Dev",
"ethereumChainId": "11155111",
"dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4dev.dydx.exchange",
"socket": "wss://indexer.v4dev.dydx.exchange"
}
],
"validators": [
"https://validator.v4dev.dydx.exchange"
],
"0xsquid": "https://testnet.api.0xsquid.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4dev.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-dev-2": {
"name": "v4 Dev 2",
"ethereumChainId": "11155111",
"dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "http://dev2-indexer-apne1-lb-public-2076363889.ap-northeast-1.elb.amazonaws.com",
"socket": "ws://dev2-indexer-apne1-lb-public-2076363889.ap-northeast-1.elb.amazonaws.com"
}
],
"validators": [
"http://54.92.118.111"
],
"0xsquid": "https://testnet.api.0xsquid.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-dev-4": {
"name": "v4 Dev 4",
"ethereumChainId": "11155111",
"dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4dev4.dydx.exchange",
"socket": "wss://indexer.v4dev4.dydx.exchange"
}
],
"validators": [
"https://validator.v4dev4.dydx.exchange"
],
"0xsquid": "https://testnet.api.0xsquid.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4dev4.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-dev-5": {
"name": "v4 Dev 5",
"ethereumChainId": "11155111",
"dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "http://dev5-indexer-apne1-lb-public-1721328151.ap-northeast-1.elb.amazonaws.com",
"socket": "ws://dev5-indexer-apne1-lb-public-1721328151.ap-northeast-1.elb.amazonaws.com"
}
],
"validators": [
"http://18.223.78.50"
],
"0xsquid": "https://testnet.api.0xsquid.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-staging": {
"name": "v4 Staging",
"ethereumChainId": "11155111",
"dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4staging.dydx.exchange",
"socket": "wss://indexer.v4staging.dydx.exchange"
}
],
"faucet": "https://faucet.v4staging.dydx.exchange",
"validators": [
"https://validator.v4staging.dydx.exchange"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-staging-forced-update": {
"name": "v4 Staging Forced Update",
"ethereumChainId": "11155111",
"dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4staging.dydx.exchange",
"socket": "wss://indexer.v4staging.dydx.exchange"
}
],
"faucet": "https://faucet.v4staging.dydx.exchange",
"validators": [
"https://validator.v4staging.dydx.exchange"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
},
"apps": {
"ios": {
"minimalVersion": "1.0",
"build": 40000,
"url": "https://apps.apple.com/app/dydx/id1564787350"
}
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-staging-west": {
"name": "v4 Staging West",
"ethereumChainId": "11155111",
"dydxChainId": "dydxprotocol-testnet",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4staging.dydx.exchange",
"socket": "wss://indexer.v4staging.dydx.exchange"
}
],
"faucet": "https://faucet.v4staging.dydx.exchange",
"validators": [
"https://validator-uswest1.v4staging.dydx.exchange"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": false
}
},
"dydxprotocol-testnet": {
"name": "v4 Public Testnet",
"ethereumChainId": "11155111",
"dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4testnet.dydx.exchange",
"socket": "wss://indexer.v4testnet.dydx.exchange"
}
],
"validators": [
"https://dydx-testnet-full-rpc.public.blastapi.io/",
"https://dydx-testnet-rpc.polkachu.com/",
"https://dydx-testnet.nodefleet.org",
"https://test-dydx.kingnodes.com",
"https://dydx-rpc.liquify.com/api=8878132/dydx"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-testnet-dydx": {
"name": "v4 Public Testnet/dYdX",
"ethereumChainId": "11155111",
"dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4testnet.dydx.exchange",
"socket": "wss://indexer.v4testnet.dydx.exchange"
}
],
"validators": [
"https://validator.v4testnet.dydx.exchange"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-testnet-nodefleet": {
"name": "v4 Public Testnet/nodefleet",
"ethereumChainId": "11155111",
"dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4testnet.dydx.exchange",
"socket": "wss://indexer.v4testnet.dydx.exchange"
}
],
"validators": [
"https://dydx-testnet.nodefleet.org"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-testnet-kingnodes": {
"name": "v4 Public Testnet/KingNodes",
"ethereumChainId": "11155111",
"dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4testnet.dydx.exchange",
"socket": "wss://indexer.v4testnet.dydx.exchange"
}
],
"validators": [
"https://test-dydx.kingnodes.com"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-testnet-liquify": {
"name": "v4 Public Testnet/Liquify",
"ethereumChainId": "11155111",
"dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4testnet.dydx.exchange",
"socket": "wss://indexer.v4testnet.dydx.exchange"
}
],
"validators": [
"https://dydx-rpc.liquify.com/api=8878132/dydx"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-testnet-polkachu": {
"name": "v4 Public Testnet/Polkahcu",
"ethereumChainId": "11155111",
"dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4testnet.dydx.exchange",
"socket": "wss://indexer.v4testnet.dydx.exchange"
}
],
"validators": [
"https://dydx-testnet-rpc.polkachu.com/"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-testnet-bware": {
"name": "v4 Public Testnet/BWare",
"ethereumChainId": "11155111",
"dydxChainId": "dydx-testnet-4",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "dYdX-api",
"isMainNet": false,
"endpoints": {
"indexers": [
{
"api": "https://indexer.v4testnet.dydx.exchange",
"socket": "wss://indexer.v4testnet.dydx.exchange"
}
],
"validators": [
"https://dydx-testnet-full-rpc.public.blastapi.io/"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"featureFlags": {
"reduceOnlySupported": true,
"usePessimisticCollateralCheck": true
}
},
"dydxprotocol-mainnet": {
"name": "v4",
"ethereumChainId": "1",
"dydxChainId": "[mainnet chain id]",
"chainName": "dYdX Chain",
"chainLogo": "/dydx-chain.png",
"squidIntegratorId": "[mainnet squid integrator id]",
"isMainNet": true,
"endpoints": {
"indexers": [
{
"api": "[REST endpoint]",
"socket": "[Websocket endpoint]"
}
],
"validators": [
"[Validator endpoint 1",
"[Validator endpoint n]"
],
"0xsquid": "[0xSquid endpoint for mainnet]",
"nobleValidator": "[noble validator endpoint for mainnet]"
},
"featureFlags": {
"reduceOnlySupported": false,
"usePessimisticCollateralCheck": true
}
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -14,7 +14,7 @@ if (AMPLITUDE_API_KEY) {
const html = await fs.readFile(htmlFilePath, 'utf-8');
const amplitudeCdnScript = `<script type="text/javascript">
!function(){"use strict";!function(e,t){var n=e.amplitude||{_q:[],_iq:{}};if(n.invoked)e.console&&console.error&&console.error("Amplitude snippet has been loaded.");else{var r=function(e,t){e.prototype[t]=function(){return this._q.push({name:t,args:Array.prototype.slice.call(arguments,0)}),this}},s=function(e,t,n){return function(r){e._q.push({name:t,args:Array.prototype.slice.call(n,0),resolve:r})}},o=function(e,t,n){e[t]=function(){if(n)return{promise:new Promise(s(e,t,Array.prototype.slice.call(arguments)))}}},i=function(e){for(var t=0;t<m.length;t++)o(e,m[t],!1);for(var n=0;n<g.length;n++)o(e,g[n],!0)};n.invoked=!0;var u=t.createElement("script");u.type="text/javascript",u.integrity="sha384-x0ik2D45ZDEEEpYpEuDpmj05fY91P7EOZkgdKmq4dKL/ZAVcufJ+nULFtGn0HIZE",u.crossOrigin="anonymous",u.async=!0,u.src="https://cdn.amplitude.com/libs/analytics-browser-2.0.0-min.js.gz",u.onload=function(){e.amplitude.runQueuedFunctions||console.log("[Amplitude] Error: could not load SDK")};var a=t.getElementsByTagName("script")[0];a.parentNode.insertBefore(u,a);for(var c=function(){return this._q=[],this},p=["add","append","clearAll","prepend","set","setOnce","unset","preInsert","postInsert","remove","getUserProperties"],l=0;l<p.length;l++)r(c,p[l]);n.Identify=c;for(var d=function(){return this._q=[],this},f=["getEventProperties","setProductId","setQuantity","setPrice","setRevenue","setRevenueType","setEventProperties"],v=0;v<f.length;v++)r(d,f[v]);n.Revenue=d;var m=["getDeviceId","setDeviceId","getSessionId","setSessionId","getUserId","setUserId","setOptOut","setTransport","reset","extendSession"],g=["init","add","remove","track","logEvent","identify","groupIdentify","setGroup","revenue","flush"];i(n),n.createInstance=function(e){return n._iq[e]={_q:[]},i(n._iq[e]),n._iq[e]},e.amplitude=n}}(window,document)}();
!function(){"use strict";!function(e,t){var n=e.amplitude||{_q:[],_iq:{}};if(n.invoked)e.console&&console.error&&console.error("Amplitude snippet has been loaded.");else{var r=function(e,t){e.prototype[t]=function(){return this._q.push({name:t,args:Array.prototype.slice.call(arguments,0)}),this}},s=function(e,t,n){return function(r){e._q.push({name:t,args:Array.prototype.slice.call(n,0),resolve:r})}},o=function(e,t,n){e[t]=function(){if(n)return{promise:new Promise(s(e,t,Array.prototype.slice.call(arguments)))}}},i=function(e){for(var t=0;t<m.length;t++)o(e,m[t],!1);for(var n=0;n<g.length;n++)o(e,g[n],!0)};n.invoked=!0;var u=t.createElement("script");u.type="text/javascript",u.integrity="sha384-BVo5ZjsjH373rWbcjz9Qjb2L6BgLwLADcZtZZPu3nMl8+7LPDhi1NcUEf0Ate41Y",u.crossOrigin="anonymous",u.async=!0,u.src="/libs/amplitude-analytics-browser-2.0.0-min.js",u.onload=function(){e.amplitude.runQueuedFunctions||console.log("[Amplitude] Error: could not load SDK")};var a=t.getElementsByTagName("script")[0];a.parentNode.insertBefore(u,a);for(var c=function(){return this._q=[],this},p=["add","append","clearAll","prepend","set","setOnce","unset","preInsert","postInsert","remove","getUserProperties"],l=0;l<p.length;l++)r(c,p[l]);n.Identify=c;for(var d=function(){return this._q=[],this},f=["getEventProperties","setProductId","setQuantity","setPrice","setRevenue","setRevenueType","setEventProperties"],v=0;v<f.length;v++)r(d,f[v]);n.Revenue=d;var m=["getDeviceId","setDeviceId","getSessionId","setSessionId","getUserId","setUserId","setOptOut","setTransport","reset","extendSession"],g=["init","add","remove","track","logEvent","identify","groupIdentify","setGroup","revenue","flush"];i(n),n.createInstance=function(e){return n._iq[e]={_q:[]},i(n._iq[e]),n._iq[e]},e.amplitude=n}}(window,document)}();
</script>
`;
+22
View File
@@ -8,6 +8,7 @@ const assetIcons = {
'1INCH': '/currencies/1inch.png',
AAVE: '/currencies/aave.png',
ADA: '/currencies/ada.png',
AGIX: '/currencies/agix.png',
ALGO: '/currencies/algo.png',
APE: '/currencies/ape.png',
APT: '/currencies/apt.png',
@@ -20,6 +21,7 @@ const assetIcons = {
BONK: '/currencies/bonk.png',
BTC: '/currencies/btc.png',
CELO: '/currencies/celo.png',
CHZ: '/currencies/chz.png',
COMP: '/currencies/comp.png',
CRV: '/currencies/crv.png',
DAI: '/currencies/dai.png',
@@ -28,25 +30,44 @@ const assetIcons = {
DYDX: '/currencies/dydx.png',
DYM: '/currencies/dym.png',
ENJ: '/currencies/enj.png',
ENS: '/currencies/ens.png',
EOS: '/currencies/eos.png',
ETC: '/currencies/etc.png',
ETH: '/currencies/eth.png',
FET: '/currencies/fet.png',
FIL: '/currencies/fil.png',
FTM: '/currencies/ftm.png',
GALA: "/currencies/gala.png",
GMT: "/currencies/gmt.png",
GRT: "/currencies/grt.png",
HBAR: "/currencies/hbar.png",
ICP: '/currencies/icp.png',
IMX: '/currencies/imx.png',
INJ: '/currencies/inj.png',
JTO: '/currencies/jto.png',
JUP: '/currencies/jup.png',
KAVA: '/currencies/kava.png',
LDO: '/currencies/ldo.png',
LINK: '/currencies/link.png',
LTC: '/currencies/ltc.png',
MANA: '/currencies/mana.png',
MATIC: '/currencies/matic.png',
MASK: '/currencies/mask.png',
MINA: '/currencies/mina.png',
MKR: '/currencies/mkr.png',
NEAR: '/currencies/near.png',
ORDI: "/currencies/ordi.png",
OP: '/currencies/op.png',
PEPE: '/currencies/pepe.png',
PYTH: '/currencies/pyth.png',
RNDR: '/currencies/rndr.png',
RUNE: '/currencies/rune.png',
SAND: '/currencies/sand.png',
SEI: '/currencies/sei.png',
SHIB: '/currencies/shib.png',
SNX: '/currencies/snx.png',
SOL: '/currencies/sol.png',
STX: '/currencies/stx.png',
SUI: '/currencies/sui.png',
SUSHI: '/currencies/sushi.png',
TIA: '/currencies/tia.png',
@@ -57,6 +78,7 @@ const assetIcons = {
USDT: '/currencies/usdt.png',
WBTC: '/currencies/wbtc.png',
WETH: '/currencies/weth.png',
WOO: '/currencies/woo.png',
WLD: '/currencies/wld.png',
XLM: '/currencies/xlm.png',
XMR: '/currencies/xmr.png',
+5 -3
View File
@@ -39,7 +39,7 @@ export const SearchSelectMenu = ({
disabled,
label,
items,
withSearch,
withSearch = true,
withReceiptItems,
}: SearchSelectMenuProps) => {
const [open, setOpen] = useState(false);
@@ -77,6 +77,7 @@ export const SearchSelectMenu = ({
withSearch={withSearch}
onItemSelected={() => setOpen(false)}
withStickyLayout
$withSearch={withSearch}
/>
</Styled.Popover>
</Styled.WithDetailsReceipt>
@@ -127,7 +128,7 @@ Styled.Popover = styled(Popover)`
box-shadow: none;
`;
Styled.ComboboxMenu = styled(ComboboxMenu)`
Styled.ComboboxMenu = styled(ComboboxMenu)<{ $withSearch?: boolean }>`
${layoutMixins.withInnerHorizontalBorders}
--comboboxMenu-backgroundColor: var(--color-layer-4);
@@ -140,7 +141,8 @@ Styled.ComboboxMenu = styled(ComboboxMenu)`
--comboboxMenu-item-checked-textColor: var(--color-text-2);
--comboboxMenu-item-highlighted-textColor: var(--color-text-2);
--stickyArea1-topHeight: var(--form-input-height);
--stickyArea1-topHeight: ${({ $withSearch }) =>
!$withSearch ? '0' : 'var(--form-input-height)'};
input:focus-visible {
outline: none;
+5
View File
@@ -33,4 +33,9 @@ TagStory.argTypes = {
control: { type: 'select' },
defaultValue: undefined,
},
isHighlighted: {
options: [true, false],
control: { type: 'select' },
defaultValue: false,
},
};
+1
View File
@@ -76,5 +76,6 @@ export const Tag = styled.span<StyleProps>`
isHighlighted &&
css`
background-color: var(--color-accent);
color: var(--color-text-button);
`}
`;
+8 -1
View File
@@ -1,4 +1,4 @@
import { type ReactNode, useState } from 'react';
import { type ReactNode, useState, useEffect } from 'react';
import { ButtonAction, ButtonState } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
@@ -8,6 +8,7 @@ import { Button, type ButtonStateConfig, type ButtonProps } from '@/components/B
type ElementProps = {
timeoutInSeconds: number;
onTimeOut?: () => void;
slotFinal?: ReactNode;
} & ButtonProps;
@@ -16,6 +17,7 @@ export type TimeoutButtonProps = ElementProps;
export const TimeoutButton = ({
children,
timeoutInSeconds,
onTimeOut,
slotFinal,
...otherProps
}: TimeoutButtonProps) => {
@@ -25,6 +27,11 @@ export const TimeoutButton = ({
const secondsLeft = Math.max(0, (timeoutDeadline - now) / 1000);
useEffect(() => {
if (secondsLeft > 0) return;
onTimeOut?.();
}, [secondsLeft]);
if (slotFinal && secondsLeft <= 0) return slotFinal;
return (
+19 -2
View File
@@ -81,6 +81,9 @@ export enum AnalyticsEvent {
TradePlaceOrderConfirmed = 'TradePlaceOrderConfirmed',
TradeCancelOrder = 'TradeCancelOrder',
TradeCancelOrderConfirmed = 'TradeCancelOrderConfirmed',
// Notification
NotificationAction = 'NotificationAction',
}
export type AnalyticsEventData<T extends AnalyticsEvent> =
@@ -144,9 +147,17 @@ export type AnalyticsEventData<T extends AnalyticsEvent> =
validatorUrl: string;
}
: T extends AnalyticsEvent.TransferDeposit
? {}
? {
chainId?: string;
tokenAddress?: string;
tokenSymbol?: string;
}
: T extends AnalyticsEvent.TransferWithdraw
? {}
? {
chainId?: string;
tokenAddress?: string;
tokenSymbol?: string;
}
: // Trading
T extends AnalyticsEvent.TradeOrderTypeSelected
? {
@@ -172,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)';
+1
View File
@@ -11,6 +11,7 @@ export enum DialogTypes {
ExternalNavKeplr = 'ExternalNavKeplr',
MnemonicExport = 'MnemonicExport',
MobileSignIn = 'MobileSignIn',
MobileDownload = 'MobileDownload',
Onboarding = 'Onboarding',
OrderDetails = 'OrderDetails',
Preferences = 'Preferences',
+6 -1
View File
@@ -1,4 +1,4 @@
import environments from '../../public/configs/env.json';
import environments from '../../public/configs/v1/env.json';
const CURRENT_MODE = ({
production: 'MAINNET',
@@ -14,5 +14,10 @@ export const isDev = CURRENT_MODE === 'DEV';
export const AVAILABLE_ENVIRONMENTS = environments.deployments[CURRENT_MODE];
export const CURRENT_ABACUS_DEPLOYMENT = CURRENT_MODE;
export const ENVIRONMENT_CONFIG_MAP = environments.environments;
export const TOKEN_CONFIG_MAP = environments.tokens;
export const LINKS_CONFIG_MAP = environments.links;
export const WALLETS_CONFIG_MAP = environments.wallets;
export const GOVERNANCE_CONFIG_MAP = environments.governance;
export type DydxNetwork = keyof typeof ENVIRONMENT_CONFIG_MAP;
export type DydxChainId = keyof typeof TOKEN_CONFIG_MAP;
export const DEFAULT_APP_ENVIRONMENT = AVAILABLE_ENVIRONMENTS.default as DydxNetwork;
+6
View File
@@ -140,8 +140,14 @@ export type TransferNotifcation = {
isCctp?: boolean;
errorCount?: number;
status?: StatusResponse;
isExchange?: boolean;
};
export enum ReleaseUpdateNotificationIds {
RewardsAndFullTradingLive = 'rewards-and-full-trading-live',
IncentivesS3 = 'incentives-s3',
}
/**
* @description Struct to store whether a NotificationType should be triggered
*/
+1
View File
@@ -22,4 +22,5 @@ export enum NumberSign {
// Deposit/Withdraw
export const MAX_CCTP_TRANSFER_AMOUNT = 1_000_000;
export const MIN_CCTP_TRANSFER_AMOUNT = 10;
export const MAX_PRICE_IMPACT = 0.02; // 2%
+4 -4
View File
@@ -24,7 +24,7 @@ import {
import { isMetaMask } from '@/lib/wallet/providers';
import { DydxNetwork, ENVIRONMENT_CONFIG_MAP } from './networks';
import { DydxChainId, WALLETS_CONFIG_MAP } from './networks';
// Wallet connection types
@@ -291,17 +291,17 @@ export const COSMOS_DERIVATION_PATH = "m/44'/118'/0'/0/0";
/**
* @description typed data to sign for dYdX Chain onboarding
*/
export const getSignTypedData = (selectedNetwork: DydxNetwork) =>
export const getSignTypedData = (selectedDydxChainId: DydxChainId) =>
({
primaryType: 'dYdX',
domain: {
name: ENVIRONMENT_CONFIG_MAP[selectedNetwork].wallets.signTypedDataDomainName,
name: WALLETS_CONFIG_MAP[selectedDydxChainId].signTypedDataDomainName,
},
types: {
dYdX: [{ name: 'action', type: 'string' }],
},
message: {
action: ENVIRONMENT_CONFIG_MAP[selectedNetwork].wallets.signTypedDataAction,
action: WALLETS_CONFIG_MAP[selectedDydxChainId].signTypedDataAction,
},
} as const);
+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();
}
});
});
});
}
@@ -27,19 +27,26 @@ export const useChartMarketAndResolution = ({
const dispatch = useDispatch();
const currentMarketId: string = useSelector(getCurrentMarketId) || DEFAULT_MARKETID;
const selectedResolution: string =
useSelector(getSelectedResolutionForMarket(currentMarketId)) || DEFAULT_RESOLUTION;
const chart = isWidgetReady ? tvWidget?.chart() : undefined;
const chartResolution = chart?.resolution?.();
/**
* @description Hook to handle changing markets - intentionally should avoid triggering on change of resolutions.
*/
useEffect(() => {
if (currentMarketId && isWidgetReady) {
const resolution = savedResolution || selectedResolution;
tvWidget?.setSymbol(currentMarketId, resolution as ResolutionString, () => {});
}
}, [currentMarketId, isWidgetReady, savedResolution, selectedResolution]);
}, [currentMarketId, isWidgetReady]);
/**
* @description Hook to handle changing chart resolution
*/
useEffect(() => {
if (chartResolution) {
if (chartResolution !== selectedResolution) {
+8 -8
View File
@@ -18,14 +18,13 @@ import type { ResolutionString } from 'public/tradingview/charting_library';
import type { ConnectNetworkEvent, NetworkConfig } from '@/constants/abacus';
import { DEFAULT_TRANSACTION_MEMO } from '@/constants/analytics';
import { type Candle, RESOLUTION_MAP } from '@/constants/candles';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { DydxChainAsset } from '@/constants/wallets';
import { getSelectedNetwork } from '@/state/appSelectors';
import { log } from '@/lib/telemetry';
import { useRestrictions } from './useRestrictions';
import { useTokenConfigs } from './useTokenConfigs';
type DydxContextType = ReturnType<typeof useDydxClientContext>;
const DydxContext = createContext<DydxContextType>({} as DydxContextType);
@@ -41,7 +40,8 @@ const useDydxClientContext = () => {
// ------ Network ------ //
const selectedNetwork = useSelector(getSelectedNetwork);
const tokensConfigs = ENVIRONMENT_CONFIG_MAP[selectedNetwork].tokens;
const { usdcDenom, usdcDecimals, usdcGasDenom, chainTokenDenom, chainTokenDecimals } =
useTokenConfigs();
const [networkConfig, setNetworkConfig] = useState<NetworkConfig>();
@@ -75,11 +75,11 @@ const useDydxClientContext = () => {
networkConfig.validatorUrl,
networkConfig.chainId,
{
USDC_DENOM: tokensConfigs[DydxChainAsset.USDC].denom,
USDC_DECIMALS: tokensConfigs[DydxChainAsset.USDC].decimals,
USDC_GAS_DENOM: tokensConfigs[DydxChainAsset.USDC].gasDenom,
CHAINTOKEN_DENOM: tokensConfigs[DydxChainAsset.CHAINTOKEN].denom,
CHAINTOKEN_DECIMALS: tokensConfigs[DydxChainAsset.CHAINTOKEN].decimals,
USDC_DENOM: usdcDenom,
USDC_DECIMALS: usdcDecimals,
USDC_GAS_DENOM: usdcGasDenom,
CHAINTOKEN_DENOM: chainTokenDenom,
CHAINTOKEN_DECIMALS: chainTokenDecimals,
},
{
broadcastPollIntervalMs: 3_000,
+7 -4
View File
@@ -1,5 +1,8 @@
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { useSelectedNetwork } from '@/hooks';
import { useSelector } from 'react-redux';
import { GOVERNANCE_CONFIG_MAP } from '@/constants/networks';
import { getSelectedDydxChainId } from '@/state/appSelectors';
export interface GovernanceVariables {
newMarketProposal: {
@@ -10,7 +13,7 @@ export interface GovernanceVariables {
}
export const useGovernanceVariables = (): GovernanceVariables => {
const { selectedNetwork } = useSelectedNetwork();
const governanceVars = ENVIRONMENT_CONFIG_MAP[selectedNetwork].governance as GovernanceVariables;
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const governanceVars = GOVERNANCE_CONFIG_MAP[selectedDydxChainId] as GovernanceVariables;
return governanceVars;
};
+15 -9
View File
@@ -82,24 +82,30 @@ const useLocalNotificationsContext = () => {
isCctp,
errorCount,
status: currentStatus,
isExchange,
} = 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);
const hasErrors =
// @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
!!currentStatus?.errors ||
(currentStatus?.error && Object.keys(currentStatus.error).length !== 0);
if (
!isExchange &&
!hasErrors &&
(!currentStatus?.squidTransactionStatus ||
currentStatus?.squidTransactionStatus === 'ongoing')
) {
try {
const status = await fetchSquidStatus({
transactionId: txHash,
toChainId,
fromChainId,
}, isCctp);
const status = await fetchSquidStatus(
{
transactionId: txHash,
toChainId,
fromChainId,
},
isCctp
);
if (status) {
transferNotification.status = status;
+43 -11
View File
@@ -5,8 +5,7 @@ import { isEqual, groupBy } from 'lodash';
import { useNavigate } from 'react-router-dom';
import { DialogTypes } from '@/constants/dialogs';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { AppRoute } from '@/constants/routes';
import { AppRoute, TokenRoute } from '@/constants/routes';
import { DydxChainAsset } from '@/constants/wallets';
import {
@@ -21,9 +20,10 @@ import {
NotificationType,
DEFAULT_TOAST_AUTO_CLOSE_MS,
TransferNotificationTypes,
ReleaseUpdateNotificationIds,
} from '@/constants/notifications';
import { useSelectedNetwork, useStringGetter } from '@/hooks';
import { useStringGetter, useTokenConfigs } from '@/hooks';
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
import { AssetIcon } from '@/components/AssetIcon';
@@ -36,6 +36,7 @@ import { getSubaccountFills, getSubaccountOrders } from '@/state/accountSelector
import { openDialog } from '@/state/dialogs';
import { getAbacusNotifications } from '@/state/notificationsSelectors';
import { getMarketIds } from '@/state/perpetualsSelectors';
import { getSelectedDydxChainId } from '@/state/appSelectors';
import { formatSeconds } from '@/lib/timeUtils';
@@ -175,16 +176,17 @@ export const notificationTypes: NotificationTypeConfig[] = [
useTrigger: ({ trigger }) => {
const stringGetter = useStringGetter();
const { transferNotifications } = useLocalNotifications();
const { selectedNetwork } = useSelectedNetwork();
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
useEffect(() => {
for (const transfer of transferNotifications) {
const { fromChainId, status, txHash, toAmount, type } = transfer;
const isFinished = Boolean(status) && status?.squidTransactionStatus !== 'ongoing';
const { fromChainId, status, txHash, toAmount, type, isExchange } = transfer;
const isFinished =
(Boolean(status) && status?.squidTransactionStatus !== 'ongoing') || isExchange;
const icon = <Icon iconName={isFinished ? IconName.Transfer : IconName.Clock} />;
const transferType =
type ?? fromChainId === ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId
type ?? fromChainId === selectedDydxChainId
? TransferNotificationTypes.Withdrawal
: TransferNotificationTypes.Deposit;
@@ -237,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',
@@ -269,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({
+1 -1
View File
@@ -2,7 +2,7 @@ import { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { LocalStorageKey } from '@/constants/localStorage';
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork, ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork } from '@/constants/networks';
import { useAccounts, useLocalStorage } from '@/hooks';
+1 -1
View File
@@ -28,7 +28,7 @@ import { setSubaccount, setHistoricalPnl, removeUncommittedOrderClientId } from
import { getBalances } from '@/state/accountSelectors';
import abacusStateManager from '@/lib/abacus';
import { hashFromTx } from '@/lib/hashfromTx';
import { hashFromTx } from '@/lib/txUtils';
import { log } from '@/lib/telemetry';
import { useAccounts } from './useAccounts';
+14 -10
View File
@@ -1,7 +1,9 @@
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { useSelector } from 'react-redux';
import { TOKEN_CONFIG_MAP } from '@/constants/networks';
import { DydxChainAsset } from '@/constants/wallets';
import { useSelectedNetwork } from '@/hooks';
import { getSelectedDydxChainId } from '@/state/appSelectors';
export const useTokenConfigs = (): {
tokensConfigs: {
@@ -10,31 +12,33 @@ export const useTokenConfigs = (): {
name: string;
decimals: number;
gasDenom?: string;
},
};
[DydxChainAsset.CHAINTOKEN]: {
denom: string;
name: string;
decimals: number;
gasDenom?: string;
},
};
};
usdcDenom: string;
usdcDecimals: number;
usdcGasDenom: string;
usdcLabel: string;
chainTokenDenom: string;
chainTokenDecimals: number;
chainTokenLabel: string;
} => {
const { selectedNetwork } = useSelectedNetwork();
const tokensConfigs = ENVIRONMENT_CONFIG_MAP[selectedNetwork].tokens;
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const tokensConfigs = TOKEN_CONFIG_MAP[selectedDydxChainId];
return {
return {
tokensConfigs,
usdcDenom: tokensConfigs[DydxChainAsset.USDC].denom,
usdcDecimals: tokensConfigs[DydxChainAsset.USDC].decimals,
usdcDenom: tokensConfigs[DydxChainAsset.USDC].denom,
usdcDecimals: tokensConfigs[DydxChainAsset.USDC].decimals,
usdcGasDenom: tokensConfigs[DydxChainAsset.USDC].gasDenom,
usdcLabel: tokensConfigs[DydxChainAsset.USDC].name,
chainTokenDenom: tokensConfigs[DydxChainAsset.CHAINTOKEN].denom,
chainTokenDecimals: tokensConfigs[DydxChainAsset.CHAINTOKEN].decimals,
chainTokenDecimals: tokensConfigs[DydxChainAsset.CHAINTOKEN].decimals,
chainTokenLabel: tokensConfigs[DydxChainAsset.CHAINTOKEN].name,
};
};
+8 -4
View File
@@ -1,12 +1,15 @@
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { useSelector } from 'react-redux';
import { useSelectedNetwork } from '@/hooks';
import { LINKS_CONFIG_MAP } from '@/constants/networks';
import { getSelectedDydxChainId } from '@/state/appSelectors';
const FALLBACK_URL = 'https://help.dydx.exchange/';
export interface LinksConfigs {
tos: string;
privacy: string;
statusPage: string;
mintscan: string;
mintscanBase: string;
feedback?: string;
@@ -27,12 +30,13 @@ export interface LinksConfigs {
}
export const useURLConfigs = (): LinksConfigs => {
const { selectedNetwork } = useSelectedNetwork();
const linksConfigs = ENVIRONMENT_CONFIG_MAP[selectedNetwork].links as LinksConfigs;
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const linksConfigs = LINKS_CONFIG_MAP[selectedDydxChainId] as LinksConfigs;
return {
tos: linksConfigs.tos,
privacy: linksConfigs.privacy,
statusPage: linksConfigs.statusPage,
mintscan: linksConfigs.mintscan,
mintscanBase: linksConfigs.mintscanBase,
feedback: linksConfigs.feedback || FALLBACK_URL,
+4 -4
View File
@@ -4,7 +4,7 @@ import { useSelector } from 'react-redux';
import { EvmDerivedAddresses } from '@/constants/account';
import { STRING_KEYS } from '@/constants/localization';
import { LocalStorageKey } from '@/constants/localStorage';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { ENVIRONMENT_CONFIG_MAP, WALLETS_CONFIG_MAP } from '@/constants/networks';
import {
type DydxAddress,
@@ -32,7 +32,7 @@ import {
WalletType as CosmosWalletType,
} from 'graz';
import { getSelectedNetwork } from '@/state/appSelectors';
import { getSelectedDydxChainId } from '@/state/appSelectors';
import { resolveWagmiConnector } from '@/lib/wagmi';
import { getWalletConnection, parseWalletError } from '@/lib/wallet';
@@ -91,8 +91,8 @@ export const useWalletConnection = () => {
// Wallet connection
const selectedNetwork = useSelector(getSelectedNetwork);
const walletConnectConfig = ENVIRONMENT_CONFIG_MAP[selectedNetwork].wallets.walletconnect;
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const walletConnectConfig = WALLETS_CONFIG_MAP[selectedDydxChainId].walletconnect;
const wagmiConnector = useMemo(
() =>
walletType && walletConnectionType
+2
View File
@@ -31,6 +31,7 @@ import { FillDetailsDialog } from '@/views/dialogs/DetailsDialog/FillDetailsDial
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();
@@ -63,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} />,
+3 -4
View File
@@ -3,9 +3,9 @@ import styled, { type AnyStyledComponent, css } from 'styled-components';
import { AbacusApiStatus } from '@/constants/abacus';
import { ButtonSize, ButtonType } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { ENVIRONMENT_CONFIG_MAP, isDev } from '@/constants/networks';
import { isDev } from '@/constants/networks';
import { useApiState, useSelectedNetwork, useStringGetter } from '@/hooks';
import { useApiState, useStringGetter, useURLConfigs } from '@/hooks';
import { ChatIcon, LinkOutIcon } from '@/icons';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -28,8 +28,7 @@ enum ExchangeStatus {
export const FooterDesktop = () => {
const stringGetter = useStringGetter();
const { height, indexerHeight, status, statusErrorMessage } = useApiState();
const { selectedNetwork } = useSelectedNetwork();
const { statusPage } = ENVIRONMENT_CONFIG_MAP[selectedNetwork].links;
const { statusPage } = useURLConfigs();
const { exchangeStatus, label } =
!status || status === AbacusApiStatus.NORMAL
+7 -6
View File
@@ -34,7 +34,7 @@ import {
import { DEFAULT_TRANSACTION_MEMO } from '@/constants/analytics';
import { DialogTypes } from '@/constants/dialogs';
import { UNCOMMITTED_ORDER_TIMEOUT_MS } from '@/constants/trade';
import { ENVIRONMENT_CONFIG_MAP, DydxNetwork, isTestnet } from '@/constants/networks';
import { DydxChainId, isTestnet } from '@/constants/networks';
import { RootStore } from '@/state/_store';
import { addUncommittedOrderClientId, removeUncommittedOrderClientId } from '@/state/account';
@@ -43,7 +43,11 @@ import { openDialog } from '@/state/dialogs';
import { StatefulOrderError } from '../errors';
import { bytesToBigInt } from '../numbers';
import { log } from '../telemetry';
import { hashFromTx } from '../hashfromTx';
import { hashFromTx, getMintscanTxLink } from '../txUtils';
(BigInt.prototype as any).toJSON = function () {
return this.toString();
};
class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
private compositeClient: CompositeClient | undefined;
@@ -238,9 +242,7 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
if (isTestnet) {
console.log(
`${ENVIRONMENT_CONFIG_MAP[
this.compositeClient.network.getString() as DydxNetwork
]?.links?.mintscan?.replace('{tx_hash}', hash.toString())}`
getMintscanTxLink(this.compositeClient.network.getString() as DydxChainId, hash)
);
} else console.log(`txHash: ${hash}`);
@@ -536,7 +538,6 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
const result = await this.cctpWithdraw(params);
callback(result);
break;
break;
}
default: {
break;
+19
View File
@@ -25,3 +25,22 @@ export function convertBech32Address({
}): string {
return toBech32(bech32Prefix, fromHex(toHex(fromBech32(address).data)));
}
/**
* Validates a Cosmos address with a specific prefix.
* @param {string} address The Cosmos address to validate.
* @param {string} prefix The expected prefix for the address.
* @returns {boolean} True if the address is valid and matches the prefix, false otherwise.
*/
export function validateCosmosAddress(address: string, prefix: string) {
try {
// Decode the address to verify its structure and prefix
const { prefix: decodedPrefix } = fromBech32(address);
// Check if the decoded address has the expected prefix
return decodedPrefix === prefix;
} catch (error) {
// If decoding fails, the address is not valid
return false;
}
}
-3
View File
@@ -1,3 +0,0 @@
export const hashFromTx = (
txHash: string | Uint8Array
): string => `0x${Buffer.from(txHash).toString('hex')}`;
+2 -2
View File
@@ -1,4 +1,4 @@
import { type DydxNetwork, ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { type DydxNetwork, ENVIRONMENT_CONFIG_MAP, type DydxChainId } from '@/constants/networks';
export const validateAgainstAvailableEnvironments = (value: DydxNetwork) =>
Object.keys(ENVIRONMENT_CONFIG_MAP).includes(value);
Object.keys(ENVIRONMENT_CONFIG_MAP).includes(value);
+3 -3
View File
@@ -31,13 +31,13 @@ export const fetchSquidStatus = async (
const response = await fetch(url, {
headers: {
"x-integrator-id": integratorId || 'dYdX-api'
'x-integrator-id': integratorId || 'dYdX-api',
},
});
if (!response.ok) {
const error = await response.json();
throw new Error(error);
throw error;
}
return response.json();
@@ -45,4 +45,4 @@ export const fetchSquidStatus = async (
export const getNobleChainId = () => {
return isMainnet ? 'noble-1' : 'grand-1';
}
};
+2 -2
View File
@@ -19,10 +19,10 @@ class TestFlags {
return !!this.queryParams.displayinitializingmarkets;
}
get addressOverride():string {
get addressOverride(): string {
return this.queryParams.address;
}
get showTradingRewards() {
return !!this.queryParams.tradingrewards;
}
+7
View File
@@ -0,0 +1,7 @@
import { DydxChainId, LINKS_CONFIG_MAP } from '@/constants/networks';
export const hashFromTx = (txHash: string | Uint8Array): string =>
`0x${Buffer.from(txHash).toString('hex')}`;
export const getMintscanTxLink = (dydxChainId: DydxChainId, txHash: string): string =>
`${LINKS_CONFIG_MAP[dydxChainId]?.mintscan?.replace('{tx_hash}', txHash.toString())}`;
@@ -26,8 +26,6 @@ import { openDialog } from '@/state/dialogs';
import { log } from '@/lib/telemetry';
const SEASON_NUMBER = 2;
export const LaunchIncentivesPanel = ({ className }: { className?: string }) => {
const { isNotTablet } = useBreakpoints();
const dispatch = useDispatch();
@@ -74,14 +72,38 @@ const EstimatedRewards = () => {
const stringGetter = useStringGetter();
const { dydxAddress } = useAccounts();
const { data: seasonNumber } = useQuery({
queryKey: 'chaos_labs_season_number',
queryFn: async () => {
const resp = await fetch('https://cloud.chaoslabs.co/query/ccar-perpetuals', {
method: 'POST',
headers: {
'apollographql-client-name': 'dydx-v4',
'content-type': 'application/json',
protocol: 'dydx-v4',
},
body: JSON.stringify({
operationName: 'TradingSeasons',
variables: {},
query: `query TradingSeasons {
tradingSeasons {
label
}
}`,
}),
});
const seasons = (await resp.json())?.data?.tradingSeasons;
return seasons && seasons.length > 0 ? seasons[seasons.length - 1].label : undefined;
},
onError: (error: Error) => log('LaunchIncentives/fetchSeasonNumber', error),
});
const { data, isLoading } = useQuery({
enabled: !!dydxAddress,
queryKey: `launch_incentives_rewards_${dydxAddress ?? ''}_${SEASON_NUMBER}`,
queryKey: `launch_incentives_rewards_${dydxAddress ?? ''}`,
queryFn: async () => {
if (!dydxAddress) return undefined;
const resp = await fetch(
`https://cloud.chaoslabs.co/query/api/dydx/points/${dydxAddress}?n=${SEASON_NUMBER}`
);
const resp = await fetch(`https://cloud.chaoslabs.co/query/api/dydx/points/${dydxAddress}`);
return (await resp.json())?.incentivePoints;
},
onError: (error: Error) => log('LaunchIncentives/fetchPoints', error),
@@ -92,12 +114,14 @@ const EstimatedRewards = () => {
<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>
{seasonNumber !== undefined && (
<Styled.Season>
{stringGetter({
key: STRING_KEYS.LAUNCH_INCENTIVES_SEASON_NUM,
params: { SEASON_NUMBER: seasonNumber },
})}
</Styled.Season>
)}
</div>
<Styled.Points>
+4
View File
@@ -1,4 +1,8 @@
import { DydxChainId, ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import type { RootState } from './_store';
export const getApiState = (state: RootState) => state.app.apiState;
export const getSelectedNetwork = (state: RootState) => state.app.selectedNetwork;
export const getSelectedDydxChainId = (state: RootState) =>
ENVIRONMENT_CONFIG_MAP[state.app.selectedNetwork].dydxChainId as DydxChainId;
+1 -3
View File
@@ -13,8 +13,6 @@ export const DepositDialog = ({ setIsOpen }: ElementProps) => {
const stringGetter = useStringGetter();
const { isMobile } = useBreakpoints();
const closeDialog = () => setIsOpen?.(false);
return (
<Dialog
isOpen
@@ -22,7 +20,7 @@ export const DepositDialog = ({ setIsOpen }: ElementProps) => {
title={stringGetter({ key: STRING_KEYS.DEPOSIT })}
placement={isMobile ? DialogPlacement.FullScreen : DialogPlacement.Default}
>
<DepositDialogContent onDeposit={closeDialog} />
<DepositDialogContent />
</Dialog>
);
};
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
import styled, { type AnyStyledComponent } from 'styled-components';
import { TransferInputField, TransferType } from '@/constants/abacus';
import { AnalyticsEvent } from '@/constants/analytics';
import { isMainnet } from '@/constants/networks';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -9,6 +10,7 @@ import { DepositForm } from '@/views/forms/AccountManagementForms/DepositForm';
import { TestnetDepositForm } from '@/views/forms/AccountManagementForms/TestnetDepositForm';
import abacusStateManager from '@/lib/abacus';
import { track } from '@/lib/analytics';
type ElementProps = {
onDeposit?: () => void;
@@ -34,9 +36,19 @@ export const DepositDialogContent = ({ onDeposit }: ElementProps) => {
return (
<Styled.Content>
{isMainnet || !showFaucet ? (
<DepositForm onDeposit={onDeposit} />
<DepositForm
onDeposit={(event) => {
track(AnalyticsEvent.TransferDeposit, event);
onDeposit?.();
}}
/>
) : (
<TestnetDepositForm onDeposit={onDeposit} />
<TestnetDepositForm
onDeposit={() => {
track(AnalyticsEvent.TransferFaucet);
onDeposit?.();
}}
/>
)}
{!isMainnet && (
<Styled.TextToggle onClick={() => setShowFaucet(!showFaucet)}>
+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;
`}
}
`;
+2 -2
View File
@@ -105,8 +105,8 @@ export const OnboardingDialog = ({ setIsOpen }: ElementProps) => {
<Styled.Content>
{isMainnet ? (
<DepositForm
onDeposit={() => {
track(AnalyticsEvent.TransferDeposit);
onDeposit={(event) => {
track(AnalyticsEvent.TransferDeposit, event);
}}
/>
) : (
@@ -25,7 +25,7 @@ import { Switch } from '@/components/Switch';
import { WithReceipt } from '@/components/WithReceipt';
import { WithTooltip } from '@/components/WithTooltip';
import { getSelectedNetwork } from '@/state/appSelectors';
import { getSelectedNetwork, getSelectedDydxChainId } from '@/state/appSelectors';
import { track } from '@/lib/analytics';
import { isTruthy } from '@/lib/isTruthy';
@@ -98,7 +98,8 @@ export const GenerateKeys = ({
EvmDerivedAccountStatus.Derived,
].includes(status);
const signTypedData = getSignTypedData(selectedNetwork);
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const signTypedData = getSignTypedData(selectedDydxChainId);
const { signTypedDataAsync } = useSignTypedData({
...signTypedData,
domain: {
@@ -7,10 +7,11 @@ import { Abi, parseUnits } from 'viem';
import erc20 from '@/abi/erc20.json';
import erc20_usdt from '@/abi/erc20_usdt.json';
import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus';
import { AnalyticsEvent, AnalyticsEventData } from '@/constants/analytics';
import { AlertType } from '@/constants/alerts';
import { ButtonSize } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { ENVIRONMENT_CONFIG_MAP, isMainnet } from '@/constants/networks';
import { isMainnet } from '@/constants/networks';
import { MAX_CCTP_TRANSFER_AMOUNT, MAX_PRICE_IMPACT, NumberSign } from '@/constants/numbers';
import type { EvmAddress } from '@/constants/wallets';
@@ -32,6 +33,7 @@ import { OutputType } from '@/components/Output';
import { Tag } from '@/components/Tag';
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
import { getSelectedDydxChainId } from '@/state/appSelectors';
import { getTransferInputs } from '@/state/inputsSelectors';
import abacusStateManager from '@/lib/abacus';
@@ -47,7 +49,7 @@ import { DepositButtonAndReceipt } from './DepositForm/DepositButtonAndReceipt';
import { NobleDeposit } from '../NobleDeposit';
type DepositFormProps = {
onDeposit?: () => void;
onDeposit?: (event?: AnalyticsEventData<AnalyticsEvent.TransferDeposit>) => void;
onError?: () => void;
};
@@ -56,7 +58,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
const [error, setError] = useState<Error | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [requireUserActionInWallet, setRequireUserActionInWallet] = useState(false);
const { selectedNetwork } = useSelectedNetwork();
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const { evmAddress, signerWagmi, publicClientWagmi, nobleAddress } = useAccounts();
@@ -131,7 +133,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
if (error) onError?.();
}, [error]);
const onSelectChain = useCallback((name: string, type: 'chain' | 'exchange') => {
const onSelectNetwork = useCallback((name: string, type: 'chain' | 'exchange') => {
if (name) {
abacusStateManager.clearTransferInputValues();
setFromAmount('');
@@ -257,14 +259,10 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
};
const txHash = await signerWagmi.sendTransaction(tx);
onDeposit?.();
if (txHash) {
addTransferNotification({
txHash: txHash,
toChainId: !isCctp
? ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId
: getNobleChainId(),
toChainId: !isCctp ? selectedDydxChainId : getNobleChainId(),
fromChainId: chainIdStr || undefined,
toAmount: summary?.usdcSize || undefined,
triggeredAt: Date.now(),
@@ -272,6 +270,12 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
});
abacusStateManager.clearTransferInputValues();
setFromAmount('');
onDeposit?.({
chainId: chainIdStr || undefined,
tokenAddress: sourceToken?.address || undefined,
tokenSymbol: sourceToken?.symbol || undefined,
});
}
} catch (error) {
log('DepositForm/onSubmit', error);
@@ -280,7 +284,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
setIsLoading(false);
}
},
[requestPayload, signerWagmi, chainId]
[requestPayload, signerWagmi, chainId, sourceToken, sourceChain]
);
const amountInputReceipt = [
@@ -379,7 +383,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
<SourceSelectMenu
selectedChain={chainIdStr || undefined}
selectedExchange={exchange || undefined}
onSelect={onSelectChain}
onSelect={onSelectNetwork}
/>
{exchange && nobleAddress ? (
<NobleDeposit />
@@ -14,6 +14,7 @@ import { popoverMixins } from '@/styles/popoverMixins';
import { getTransferInputs } from '@/state/inputsSelectors';
import { isTruthy } from '@/lib/isTruthy';
import { testFlags } from '@/lib/testFlags';
type ElementProps = {
label?: string;
@@ -17,9 +17,10 @@ import { getTransferInputs } from '@/state/inputsSelectors';
type ElementProps = {
selectedToken?: TransferInputTokenResource;
onSelectToken: (token: TransferInputTokenResource) => void;
isExchange?: boolean;
};
export const TokenSelectMenu = ({ selectedToken, onSelectToken }: ElementProps) => {
export const TokenSelectMenu = ({ selectedToken, onSelectToken, isExchange }: ElementProps) => {
const stringGetter = useStringGetter();
const { type, depositOptions, withdrawalOptions, resources } =
useSelector(getTransferInputs, shallowEqual) || {};
@@ -47,19 +48,24 @@ export const TokenSelectMenu = ({ selectedToken, onSelectToken }: ElementProps)
},
]}
label={stringGetter({ key: STRING_KEYS.ASSET })}
withReceiptItems={[
{
key: 'swap',
label: stringGetter({ key: STRING_KEYS.SWAP }),
value: selectedToken && (
<>
<Tag>{type === TransferType.deposit ? selectedToken?.symbol : 'USDC'}</Tag>
<DiffArrow />
<Tag>{type === TransferType.deposit ? 'USDC' : selectedToken?.symbol}</Tag>
</>
),
},
]}
withSearch={!isExchange}
withReceiptItems={
!isExchange
? [
{
key: 'swap',
label: stringGetter({ key: STRING_KEYS.SWAP }),
value: selectedToken && (
<>
<Tag>{type === TransferType.deposit ? selectedToken?.symbol : 'USDC'}</Tag>
<DiffArrow />
<Tag>{type === TransferType.deposit ? 'USDC' : selectedToken?.symbol}</Tag>
</>
),
},
]
: undefined
}
>
<Styled.AssetRow>
{selectedToken ? (
@@ -7,11 +7,17 @@ import { isAddress } from 'viem';
import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus';
import { AlertType } from '@/constants/alerts';
import { AnalyticsEvent } from '@/constants/analytics';
import { ButtonSize } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { ENVIRONMENT_CONFIG_MAP, isMainnet } from '@/constants/networks';
import { isMainnet } from '@/constants/networks';
import { TransferNotificationTypes } from '@/constants/notifications';
import { MAX_CCTP_TRANSFER_AMOUNT, MAX_PRICE_IMPACT, NumberSign } from '@/constants/numbers';
import {
MAX_CCTP_TRANSFER_AMOUNT,
MAX_PRICE_IMPACT,
MIN_CCTP_TRANSFER_AMOUNT,
NumberSign,
} from '@/constants/numbers';
import {
useAccounts,
@@ -40,6 +46,7 @@ import { Icon, IconName } from '@/components/Icon';
import { SourceSelectMenu } from '@/views/forms/AccountManagementForms/SourceSelectMenu';
import { getSelectedDydxChainId } from '@/state/appSelectors';
import { getSubaccount } from '@/state/accountSelectors';
import { getTransferInputs } from '@/state/inputsSelectors';
@@ -49,12 +56,14 @@ import { getNobleChainId } from '@/lib/squid';
import { TokenSelectMenu } from './TokenSelectMenu';
import { WithdrawButtonAndReceipt } from './WithdrawForm/WithdrawButtonAndReceipt';
import { validateCosmosAddress } from '@/lib/addressUtils';
import { track } from '@/lib/analytics';
export const WithdrawForm = () => {
const stringGetter = useStringGetter();
const [error, setError] = useState<string>();
const [isLoading, setIsLoading] = useState(false);
const { selectedNetwork } = useSelectedNetwork();
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const { sendSquidWithdraw } = useSubaccount();
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
@@ -62,6 +71,7 @@ export const WithdrawForm = () => {
const {
requestPayload,
token,
exchange,
chain: chainIdStr,
address: toAddress,
resources,
@@ -173,20 +183,27 @@ export const WithdrawForm = () => {
requestPayload.data,
isCctp
);
if (txHash) {
const nobleChainId = getNobleChainId();
const toChainId = Boolean(exchange) ? nobleChainId : chainIdStr || undefined;
if (txHash && toChainId) {
addTransferNotification({
txHash: txHash,
type: TransferNotificationTypes.Withdrawal,
fromChainId: !isCctp
? ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId
: getNobleChainId(),
toChainId: chainIdStr || undefined,
fromChainId: !isCctp ? selectedDydxChainId : nobleChainId,
toChainId,
toAmount: debouncedAmountBN.toNumber(),
triggeredAt: Date.now(),
isCctp,
isExchange: Boolean(exchange),
});
abacusStateManager.clearTransferInputValues();
setWithdrawAmount('');
track(AnalyticsEvent.TransferWithdraw, {
chainId: toChainId,
tokenAddress: toToken?.address || undefined,
tokenSymbol: toToken?.symbol || undefined,
});
}
}
} catch (error) {
@@ -209,7 +226,17 @@ export const WithdrawForm = () => {
setIsLoading(false);
}
},
[requestPayload, debouncedAmountBN, chainIdStr, toAddress, screenAddresses, stringGetter]
[
requestPayload,
debouncedAmountBN,
chainIdStr,
toAddress,
selectedDydxChainId,
exchange,
toToken,
screenAddresses,
stringGetter,
]
);
const onChangeAddress = useCallback((e: ChangeEvent<HTMLInputElement>) => {
@@ -242,13 +269,20 @@ export const WithdrawForm = () => {
setWithdrawAmount(freeCollateralBN.toString());
}, [freeCollateralBN, setWithdrawAmount]);
const onSelectChain = useCallback((chain: string) => {
if (chain) {
abacusStateManager.setTransferValue({
field: TransferInputField.chain,
value: chain,
});
const onSelectNetwork = useCallback((name: string, type: 'chain' | 'exchange') => {
if (name) {
setWithdrawAmount('');
if (type === 'chain') {
abacusStateManager.setTransferValue({
field: TransferInputField.chain,
value: name,
});
} else {
abacusStateManager.setTransferValue({
field: TransferInputField.exchange,
value: name,
});
}
}
}, []);
@@ -309,7 +343,7 @@ export const WithdrawForm = () => {
});
if (debouncedAmountBN) {
if (!chainIdStr) {
if (!chainIdStr && !exchange) {
return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_CHAIN });
} else if (!toToken) {
return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_ASSET });
@@ -329,6 +363,12 @@ export const WithdrawForm = () => {
},
});
}
if (
!debouncedAmountBN.isZero() &&
MustBigNumber(debouncedAmountBN).lte(MIN_CCTP_TRANSFER_AMOUNT)
) {
return 'Amount must be greater than 10 USDC';
}
}
if (isMainnet && MustBigNumber(summary?.aggregatePriceImpact).gte(MAX_PRICE_IMPACT)) {
@@ -350,14 +390,19 @@ export const WithdrawForm = () => {
summary,
]);
const isInvalidNobleAddress = Boolean(
exchange && toAddress && !validateCosmosAddress(toAddress, 'noble')
);
const isDisabled =
!!errorMessage ||
!toToken ||
!chainIdStr ||
(!chainIdStr && !exchange) ||
!toAddress ||
debouncedAmountBN.isNaN() ||
debouncedAmountBN.isZero() ||
isLoading;
isLoading ||
isInvalidNobleAddress;
return (
<Styled.Form onSubmit={onSubmit}>
@@ -375,12 +420,21 @@ export const WithdrawForm = () => {
}
/>
<SourceSelectMenu
label={stringGetter({ key: STRING_KEYS.NETWORK })}
selectedExchange={exchange || undefined}
selectedChain={chainIdStr || undefined}
onSelect={onSelectChain}
onSelect={onSelectNetwork}
/>
</Styled.DestinationRow>
<TokenSelectMenu selectedToken={toToken || undefined} onSelectToken={onSelectToken} />
{isInvalidNobleAddress && (
<AlertMessage type={AlertType.Error}>
{stringGetter({ key: STRING_KEYS.NOBLE_ADDRESS_VALIDATION })}
</AlertMessage>
)}
<TokenSelectMenu
selectedToken={toToken || undefined}
onSelectToken={onSelectToken}
isExchange={Boolean(exchange)}
/>
<Styled.WithDetailsReceipt side="bottom" detailItems={amountInputReceipt}>
<FormInput
type={InputType.Number}
@@ -27,6 +27,8 @@ import { calculateCanAccountTrade } from '@/state/accountCalculators';
import { getSubaccount } from '@/state/accountSelectors';
import { getTransferInputs } from '@/state/inputsSelectors';
import { isTruthy } from '@/lib/isTruthy';
import { SlippageEditor } from '../SlippageEditor';
type ElementProps = {
@@ -55,7 +57,7 @@ export const WithdrawButtonAndReceipt = ({
const stringGetter = useStringGetter();
const { leverage } = useSelector(getSubaccount, shallowEqual) || {};
const { summary, requestPayload } = useSelector(getTransferInputs, shallowEqual) || {};
const { summary, requestPayload, exchange } = useSelector(getTransferInputs, shallowEqual) || {};
const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual);
const { usdcLabel } = useTokenConfigs();
@@ -92,7 +94,7 @@ export const WithdrawButtonAndReceipt = ({
value: <Output type={OutputType.Fiat} value={totalFees} />,
subitems: feeSubitems,
},
{
!exchange && {
key: 'exchange-rate',
label: <span>{stringGetter({ key: STRING_KEYS.EXCHANGE_RATE })}</span>,
value: withdrawToken && typeof summary?.exchangeRate === 'number' && (
@@ -133,7 +135,9 @@ export const WithdrawButtonAndReceipt = ({
{withdrawToken && <Tag>{withdrawToken?.symbol}</Tag>}
</span>
),
value: <Output type={OutputType.Asset} value={summary?.toAmount} fractionDigits={TOKEN_DECIMALS} />,
value: (
<Output type={OutputType.Asset} value={summary?.toAmount} fractionDigits={TOKEN_DECIMALS} />
),
subitems: [
{
key: 'minimum-amount-received',
@@ -144,13 +148,17 @@ export const WithdrawButtonAndReceipt = ({
</span>
),
value: (
<Output type={OutputType.Asset} value={summary?.toAmountMin} fractionDigits={TOKEN_DECIMALS} />
<Output
type={OutputType.Asset}
value={summary?.toAmountMin}
fractionDigits={TOKEN_DECIMALS}
/>
),
tooltip: 'minimum-amount-received',
},
],
},
{
!exchange && {
key: 'slippage',
label: <span>{stringGetter({ key: STRING_KEYS.MAX_SLIPPAGE })}</span>,
value: (
@@ -175,7 +183,7 @@ export const WithdrawButtonAndReceipt = ({
/>
),
},
];
].filter(isTruthy);
const isFormValid = !isDisabled && !isEditingSlippage;
+25 -31
View File
@@ -1,5 +1,5 @@
import { useState } from 'react';
import styled, { type AnyStyledComponent } from 'styled-components';
import styled, { type AnyStyledComponent, css } from 'styled-components';
import { OpacityToken } from '@/constants/styles/base';
import { STRING_KEYS } from '@/constants/localization';
@@ -10,7 +10,6 @@ import { useAccounts, useStringGetter } from '@/hooks';
import { CopyButton } from '@/components/CopyButton';
import { QrCode } from '@/components/QrCode';
import { Checkbox } from '@/components/Checkbox';
import { Icon, IconName } from '@/components/Icon';
import { TimeoutButton } from '@/components/TimeoutButton';
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
import { WithReceipt } from '@/components/WithReceipt';
@@ -19,6 +18,7 @@ import { generateFadedColorVariant } from '@/lib/styles';
export const NobleDeposit = () => {
const [hasAcknowledged, setHasAcknowledged] = useState(false);
const [hasTimedout, setHasTimedout] = useState(false);
const stringGetter = useStringGetter();
const { nobleAddress } = useAccounts();
@@ -30,23 +30,21 @@ export const NobleDeposit = () => {
{
key: 'nobleAddress',
label: stringGetter({ key: STRING_KEYS.NOBLE_ADDRESS }),
value: nobleAddress,
value:
hasAcknowledged && hasTimedout
? nobleAddress
: stringGetter({ key: STRING_KEYS.ACKNOWLEDGE_TO_REVEAL }),
},
]}
>
<Styled.QrCodeContainer>
<Styled.QrCode size={432} value={nobleAddress || ''} />
</Styled.QrCodeContainer>
<Styled.QrCode
hasLogo
size={432}
value={nobleAddress || ''}
blurred={!hasAcknowledged || !hasTimedout}
/>
</WithDetailsReceipt>
<Styled.WaitingSpan>
<Styled.CautionIconContainer>
<Icon iconName={IconName.CautionCircleStroked} />
</Styled.CautionIconContainer>
<p>{stringGetter({ key: STRING_KEYS.NOBLE_WARNING })}</p>
</Styled.WaitingSpan>
<Styled.WithReceipt
slotReceipt={
<Styled.CheckboxContainer>
@@ -63,7 +61,12 @@ export const NobleDeposit = () => {
>
<TimeoutButton
timeoutInSeconds={8}
slotFinal={<CopyButton state={{ isDisabled: !hasAcknowledged }} value={nobleAddress} />}
onTimeOut={() => setHasTimedout(true)}
slotFinal={
<CopyButton state={{ isDisabled: !hasAcknowledged }} value={nobleAddress}>
{!hasAcknowledged ? stringGetter({ key: STRING_KEYS.ACKNOWLEDGE_RISKS }) : undefined}
</CopyButton>
}
/>
</Styled.WithReceipt>
</>
@@ -82,23 +85,14 @@ Styled.WithReceipt = styled(WithReceipt)`
--withReceipt-backgroundColor: var(--color-layer-2);
`;
Styled.QrCodeContainer = styled.div`
display: flex;
justify-content: center;
Styled.QrCode = styled(QrCode)<{ blurred: boolean }>`
border-radius: 0.5em;
padding: 0.5rem;
background-color: var(--color-layer-2);
border-radius: 0.5rem;
`;
Styled.QrCode = styled(QrCode)`
max-height: 20rem;
width: fit-content;
svg {
max-height: 20rem;
}
${({ blurred }) =>
blurred &&
css`
filter: blur(8px);
`}
`;
Styled.CheckboxContainer = styled.div`
+4 -5
View File
@@ -9,7 +9,6 @@ import { TransferInputField, TransferType } from '@/constants/abacus';
import { AlertType } from '@/constants/alerts';
import { ButtonShape, ButtonSize } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { NumberSign } from '@/constants/numbers';
import { DydxChainAsset } from '@/constants/wallets';
@@ -18,7 +17,6 @@ import {
useAccounts,
useDydxClient,
useRestrictions,
useSelectedNetwork,
useStringGetter,
useSubaccount,
useTokenConfigs,
@@ -41,6 +39,7 @@ import { TransferButtonAndReceipt } from '@/views/forms/TransferForm/TransferBut
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
import { getSubaccount } from '@/state/accountSelectors';
import { getSelectedDydxChainId } from '@/state/appSelectors';
import { getTransferInputs } from '@/state/inputsSelectors';
import abacusStateManager from '@/lib/abacus';
@@ -63,7 +62,7 @@ export const TransferForm = ({
const { dydxAddress } = useAccounts();
const { transfer } = useSubaccount();
const { nativeTokenBalance, usdcBalance } = useAccountBalance();
const { selectedNetwork } = useSelectedNetwork();
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const { tokensConfigs, usdcLabel, chainTokenLabel } = useTokenConfigs();
const {
@@ -239,7 +238,7 @@ export const TransferForm = ({
const networkOptions = [
{
chainId: ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId,
chainId: selectedDydxChainId,
label: (
<Styled.InlineRow>
<AssetIcon symbol="DYDX" /> {stringGetter({ key: STRING_KEYS.DYDX_CHAIN })}
@@ -322,7 +321,7 @@ export const TransferForm = ({
/>
<Styled.NetworkSelectMenu
label={stringGetter({ key: STRING_KEYS.NETWORK })}
value={ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId}
value={selectedDydxChainId}
slotTriggerAfter={null}
>
{networkOptions.map(({ chainId, label }) => (
+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,18 +1,21 @@
import { useMemo } from 'react';
import { useSelector } from 'react-redux';
import styled, { css, type AnyStyledComponent } from 'styled-components';
import { StatusResponse } from '@0xsquid/sdk';
import { useStringGetter, useSelectedNetwork, useURLConfigs } from '@/hooks';
import { STRING_KEYS } from '@/constants/localization';
import { TransferNotificationTypes } from '@/constants/notifications';
import { useStringGetter, useURLConfigs } from '@/hooks';
import { layoutMixins } from '@/styles/layoutMixins';
import { Link } from '@/components/Link';
import { Icon, IconName } from '@/components/Icon';
import { LoadingDots } from '@/components/Loading/LoadingDots';
import { LoadingSpinner } from '@/components/Loading/LoadingSpinner';
import { layoutMixins } from '@/styles/layoutMixins';
import { STRING_KEYS } from '@/constants/localization';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { TransferNotificationTypes } from '@/constants/notifications';
import { getSelectedDydxChainId } from '@/state/appSelectors';
type ElementProps = {
status?: StatusResponse;
@@ -32,9 +35,8 @@ enum TransferStatusStep {
export const TransferStatusSteps = ({ className, status, type }: ElementProps & StyleProps) => {
const stringGetter = useStringGetter();
const { selectedNetwork } = useSelectedNetwork();
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const { mintscan: mintscanTxUrl } = useURLConfigs();
const dydxChainId = ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId;
const { currentStep, steps } = useMemo(() => {
const routeStatus = status?.routeStatus;
@@ -55,7 +57,7 @@ export const TransferStatusSteps = ({ className, status, type }: ElementProps &
link:
type === TransferNotificationTypes.Deposit
? status?.fromChain?.transactionUrl
: routeStatus?.[0]?.chainId === dydxChainId && routeStatus[0].txHash
: routeStatus?.[0]?.chainId === selectedDydxChainId && routeStatus[0].txHash
? `${mintscanTxUrl?.replace('{tx_hash}', routeStatus[0].txHash.replace('0x', ''))}`
: undefined,
},
@@ -81,7 +83,7 @@ export const TransferStatusSteps = ({ className, status, type }: ElementProps &
link:
type === TransferNotificationTypes.Withdrawal
? status?.toChain?.transactionUrl
: currentStatus?.chainId === dydxChainId && currentStatus?.txHash
: currentStatus?.chainId === selectedDydxChainId && currentStatus?.txHash
? `${mintscanTxUrl?.replace('{tx_hash}', currentStatus.txHash.replace('0x', ''))}`
: undefined,
},
@@ -40,7 +40,7 @@ export const TransferStatusNotification = ({
const stringGetter = useStringGetter();
const [open, setOpen] = useState<boolean>(false);
const [secondsLeft, setSecondsLeft] = useState<number>(0);
const { fromChainId, status, txHash, toAmount } = transfer;
const { fromChainId, status, txHash, toAmount, isExchange } = transfer;
// @ts-ignore status.errors is not in the type definition but can be returned
const error = status?.errors?.length ? status?.errors[0] : status?.error;
@@ -54,6 +54,8 @@ export const TransferStatusNotification = ({
useInterval({ callback: updateSecondsLeft });
const isComplete = status?.squidTransactionStatus === 'success' || isExchange;
const inProgressStatusString =
type === TransferNotificationTypes.Deposit
? secondsLeft > 0
@@ -65,10 +67,10 @@ export const TransferStatusNotification = ({
const statusString =
type === TransferNotificationTypes.Deposit
? status?.squidTransactionStatus === 'success'
? isComplete
? STRING_KEYS.DEPOSIT_COMPLETE
: inProgressStatusString
: status?.squidTransactionStatus === 'success'
: isComplete
? STRING_KEYS.WITHDRAW_COMPLETE
: inProgressStatusString;
@@ -108,12 +110,12 @@ export const TransferStatusNotification = ({
slotIcon={isToast && slotIcon}
slotTitle={slotTitle}
slotCustomContent={
!status ? (
!status && !isExchange ? (
<LoadingDots size={3} />
) : (
<Styled.BridgingStatus>
{content}
{!isToast && status?.squidTransactionStatus !== 'success' && !hasError && (
{!isToast && !isComplete && !hasError && (
<Styled.TransferStatusSteps status={status} type={type} />
)}
</Styled.BridgingStatus>