Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f8cc17cf1 |
@@ -1,2 +1 @@
|
||||
node_modules/
|
||||
public/
|
||||
|
||||
@@ -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.5",
|
||||
"@dydxprotocol/v4-abacus": "^1.4.2",
|
||||
"@dydxprotocol/v4-client-js": "^1.0.20",
|
||||
"@dydxprotocol/v4-localization": "^1.1.30",
|
||||
"@dydxprotocol/v4-localization": "^1.1.29",
|
||||
"@ethersproject/providers": "^5.7.2",
|
||||
"@js-joda/core": "^5.5.3",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
|
||||
@@ -26,14 +26,14 @@ dependencies:
|
||||
specifier: ^0.32.1
|
||||
version: 0.32.2
|
||||
'@dydxprotocol/v4-abacus':
|
||||
specifier: ^1.4.5
|
||||
version: 1.4.5
|
||||
specifier: ^1.4.2
|
||||
version: 1.4.2
|
||||
'@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.29
|
||||
version: 1.1.29
|
||||
'@ethersproject/providers':
|
||||
specifier: ^5.7.2
|
||||
version: 5.7.2
|
||||
@@ -1286,8 +1286,8 @@ packages:
|
||||
resolution: {integrity: sha512-Gg5t+eR7vPJMAmhkFt6CZrzPd0EKpAslWwk5rFVYZpJsM8JG5KT9XQ99hgNM3Ov6ScNoIWbXkpX27F6A9cXR4Q==}
|
||||
dev: false
|
||||
|
||||
/@dydxprotocol/v4-abacus@1.4.5:
|
||||
resolution: {integrity: sha512-LhJmpIaUkHCsSiHx+jdk+59euvGp2E+gGFelpfmOYpH1+enZgEXDQvWsgHSFEQxYP3mRiGG4uo+ZYNGdvffg7g==}
|
||||
/@dydxprotocol/v4-abacus@1.4.2:
|
||||
resolution: {integrity: sha512-+hugk0RulMwMthR2xCMYXohcC3sEYqVW/lmiq0RUuHZ9yrjmgy48xl0aZUmXGUYXyoiHXPS4AULhRKHQ4OOLwg==}
|
||||
dev: false
|
||||
|
||||
/@dydxprotocol/v4-client-js@1.0.20:
|
||||
@@ -1319,8 +1319,8 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@dydxprotocol/v4-localization@1.1.30:
|
||||
resolution: {integrity: sha512-TZfWWRSOxcjLHs972wlJVVHkE7+DVqAUnGZSs24HYHsPtUkPhZiNXMOA2Vk9YddQxumhM79xIRH0cmJSe5DDUg==}
|
||||
/@dydxprotocol/v4-localization@1.1.29:
|
||||
resolution: {integrity: sha512-o9lxsYl5ObqO9OUyxiKuUxoBmYZk0qGDeNxGScY8uMRq4Ahhz3BPxAC7jUYypCNAMpieiQjVGxMnnhIbwEkm2w==}
|
||||
dev: false
|
||||
|
||||
/@dydxprotocol/v4-proto@4.0.0-dev.0:
|
||||
|
||||
@@ -1329,4 +1329,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,6 @@
|
||||
"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"],
|
||||
@@ -85,7 +78,7 @@
|
||||
},
|
||||
"BLUR-USD": {
|
||||
"name": "Blur",
|
||||
"tags": ["NFT"],
|
||||
"tags": [],
|
||||
"websiteLink": "https://blur.io/",
|
||||
"whitepaperLink": "https://docs.blur.foundation/",
|
||||
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/blur-token/"
|
||||
@@ -98,13 +91,6 @@
|
||||
"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": [],
|
||||
@@ -161,13 +147,6 @@
|
||||
"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"],
|
||||
@@ -191,13 +170,6 @@
|
||||
"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"],
|
||||
@@ -205,34 +177,6 @@
|
||||
"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"],
|
||||
@@ -240,13 +184,6 @@
|
||||
"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"],
|
||||
@@ -254,27 +191,6 @@
|
||||
"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"],
|
||||
@@ -282,13 +198,6 @@
|
||||
"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"],
|
||||
@@ -310,20 +219,6 @@
|
||||
"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"],
|
||||
@@ -331,13 +226,6 @@
|
||||
"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"],
|
||||
@@ -352,13 +240,6 @@
|
||||
"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": [],
|
||||
@@ -372,20 +253,6 @@
|
||||
"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"],
|
||||
@@ -393,13 +260,6 @@
|
||||
"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"],
|
||||
@@ -428,13 +288,6 @@
|
||||
"whitepaperLink": "https://solana.com/solana-whitepaper.pdf",
|
||||
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/solana/"
|
||||
},
|
||||
"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"],
|
||||
@@ -484,13 +337,6 @@
|
||||
"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"],
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
{
|
||||
"baseAsset": "CRV",
|
||||
"referencePrice": 0.48346754113361784,
|
||||
"numOracles": 6,
|
||||
"numOracles": 5,
|
||||
"liquidityTier": 2,
|
||||
"assetName": "Curve DAO Token",
|
||||
"p": -1.0,
|
||||
@@ -325,7 +325,7 @@
|
||||
{
|
||||
"baseAsset": "DYM",
|
||||
"referencePrice": 5.544949130771594,
|
||||
"numOracles": 6,
|
||||
"numOracles": 5,
|
||||
"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": "GMT",
|
||||
"assetName": "STEPN",
|
||||
"p": -1.0,
|
||||
"atomicResolution": -5.0,
|
||||
"minExchanges": 3,
|
||||
@@ -514,7 +514,7 @@
|
||||
"referencePrice": 0.07686278766140874,
|
||||
"numOracles": 6,
|
||||
"liquidityTier": 2,
|
||||
"assetName": "Hedera",
|
||||
"assetName": "Hedera Hashgraph",
|
||||
"p": -2.0,
|
||||
"atomicResolution": -4.0,
|
||||
"minExchanges": 3,
|
||||
@@ -565,7 +565,7 @@
|
||||
"referencePrice": 33.427379051845875,
|
||||
"numOracles": 7,
|
||||
"liquidityTier": 2,
|
||||
"assetName": "Injective",
|
||||
"assetName": "Injective Protocol",
|
||||
"p": 1.0,
|
||||
"atomicResolution": -7.0,
|
||||
"minExchanges": 3,
|
||||
@@ -597,7 +597,7 @@
|
||||
{
|
||||
"baseAsset": "JUP",
|
||||
"referencePrice": 0.4339790660244292,
|
||||
"numOracles": 6,
|
||||
"numOracles": 5,
|
||||
"liquidityTier": 2,
|
||||
"assetName": "Jupiter",
|
||||
"p": -1.0,
|
||||
@@ -750,7 +750,7 @@
|
||||
{
|
||||
"baseAsset": "MKR",
|
||||
"referencePrice": 1943.1865605831852,
|
||||
"numOracles": 6,
|
||||
"numOracles": 5,
|
||||
"liquidityTier": 2,
|
||||
"assetName": "Maker",
|
||||
"p": 3.0,
|
||||
@@ -869,7 +869,7 @@
|
||||
{
|
||||
"baseAsset": "RUNE",
|
||||
"referencePrice": 3.7264809096406806,
|
||||
"numOracles": 6,
|
||||
"numOracles": 5,
|
||||
"liquidityTier": 2,
|
||||
"assetName": "Thorchain",
|
||||
"p": 0.0,
|
||||
@@ -888,7 +888,7 @@
|
||||
"referencePrice": 0.37297439115035663,
|
||||
"numOracles": 6,
|
||||
"liquidityTier": 2,
|
||||
"assetName": "The Sandbox",
|
||||
"assetName": "SAND",
|
||||
"p": -1.0,
|
||||
"atomicResolution": -5.0,
|
||||
"minExchanges": 3,
|
||||
@@ -1073,9 +1073,9 @@
|
||||
{
|
||||
"baseAsset": "WOO",
|
||||
"referencePrice": 0.2944897275608197,
|
||||
"numOracles": 6,
|
||||
"numOracles": 5,
|
||||
"liquidityTier": 2,
|
||||
"assetName": "WOO Network",
|
||||
"assetName": "Wootrade Network",
|
||||
"p": -1.0,
|
||||
"atomicResolution": -5.0,
|
||||
"minExchanges": 3,
|
||||
|
||||
@@ -1,638 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"[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]"
|
||||
}
|
||||
},
|
||||
"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
|
||||
}
|
||||
},
|
||||
"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
|
||||
}
|
||||
},
|
||||
"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
|
||||
}
|
||||
},
|
||||
"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
|
||||
}
|
||||
},
|
||||
"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
|
||||
}
|
||||
},
|
||||
"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
|
||||
}
|
||||
},
|
||||
"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
|
||||
}
|
||||
},
|
||||
"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": false
|
||||
}
|
||||
},
|
||||
"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": false
|
||||
}
|
||||
},
|
||||
"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": false
|
||||
}
|
||||
},
|
||||
"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": false
|
||||
}
|
||||
},
|
||||
"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": false
|
||||
}
|
||||
},
|
||||
"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": false
|
||||
}
|
||||
},
|
||||
"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": false
|
||||
}
|
||||
},
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 348 KiB |
|
Before Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 31 KiB |
@@ -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-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)}();
|
||||
!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)}();
|
||||
</script>
|
||||
`;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ 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',
|
||||
@@ -21,7 +20,6 @@ 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',
|
||||
@@ -30,44 +28,25 @@ 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',
|
||||
@@ -78,7 +57,6 @@ 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',
|
||||
|
||||
@@ -33,9 +33,4 @@ TagStory.argTypes = {
|
||||
control: { type: 'select' },
|
||||
defaultValue: undefined,
|
||||
},
|
||||
isHighlighted: {
|
||||
options: [true, false],
|
||||
control: { type: 'select' },
|
||||
defaultValue: false,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -76,6 +76,5 @@ export const Tag = styled.span<StyleProps>`
|
||||
isHighlighted &&
|
||||
css`
|
||||
background-color: var(--color-accent);
|
||||
color: var(--color-text-button);
|
||||
`}
|
||||
`;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import environments from '../../public/configs/v1/env.json';
|
||||
import environments from '../../public/configs/env.json';
|
||||
|
||||
const CURRENT_MODE = ({
|
||||
production: 'MAINNET',
|
||||
@@ -14,10 +14,5 @@ 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;
|
||||
|
||||
@@ -22,5 +22,4 @@ 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%
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
import type { ThemeName } from 'public/tradingview/charting_library';
|
||||
|
||||
import { AppColorMode, AppTheme } from '@/state/configs';
|
||||
|
||||
export const THEME_NAMES: Record<AppTheme, ThemeName> = {
|
||||
[AppTheme.Classic]: 'Classic',
|
||||
[AppTheme.Dark]: 'Dark',
|
||||
[AppTheme.Light]: 'Light',
|
||||
};
|
||||
import { AppColorMode } from '@/state/configs';
|
||||
|
||||
export type Theme = {
|
||||
[AppColorMode.GreenUp]: ThemeColorBase;
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||
|
||||
import type {
|
||||
IChartingLibraryWidget,
|
||||
IOrderLineAdapter,
|
||||
IPositionLineAdapter,
|
||||
} from 'public/tradingview/charting_library';
|
||||
|
||||
export type TvWidget = IChartingLibraryWidget & { _id?: string; _ready?: boolean };
|
||||
|
||||
export type ChartLineType = OrderSide | 'position';
|
||||
|
||||
export type ChartLine = {
|
||||
line: IOrderLineAdapter | IPositionLineAdapter;
|
||||
chartLineType: ChartLineType;
|
||||
};
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
|
||||
import { isMetaMask } from '@/lib/wallet/providers';
|
||||
|
||||
import { DydxChainId, WALLETS_CONFIG_MAP } from './networks';
|
||||
import { DydxNetwork, ENVIRONMENT_CONFIG_MAP } from './networks';
|
||||
|
||||
// Wallet connection types
|
||||
|
||||
@@ -40,7 +40,6 @@ export enum WalletErrorType {
|
||||
// General
|
||||
ChainMismatch,
|
||||
UserCanceled,
|
||||
SwitchChainMethodMissing,
|
||||
|
||||
// Non-Deterministic
|
||||
NonDeterministicWallet,
|
||||
@@ -291,17 +290,17 @@ export const COSMOS_DERIVATION_PATH = "m/44'/118'/0'/0/0";
|
||||
/**
|
||||
* @description typed data to sign for dYdX Chain onboarding
|
||||
*/
|
||||
export const getSignTypedData = (selectedDydxChainId: DydxChainId) =>
|
||||
export const getSignTypedData = (selectedNetwork: DydxNetwork) =>
|
||||
({
|
||||
primaryType: 'dYdX',
|
||||
domain: {
|
||||
name: WALLETS_CONFIG_MAP[selectedDydxChainId].signTypedDataDomainName,
|
||||
name: ENVIRONMENT_CONFIG_MAP[selectedNetwork].wallets.signTypedDataDomainName,
|
||||
},
|
||||
types: {
|
||||
dYdX: [{ name: 'action', type: 'string' }],
|
||||
},
|
||||
message: {
|
||||
action: WALLETS_CONFIG_MAP[selectedDydxChainId].signTypedDataAction,
|
||||
action: ENVIRONMENT_CONFIG_MAP[selectedNetwork].wallets.signTypedDataAction,
|
||||
},
|
||||
} as const);
|
||||
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
export { useChartLines } from './useChartLines';
|
||||
export { useChartMarketAndResolution } from './useChartMarketAndResolution';
|
||||
export { useTradingView } from './useTradingView';
|
||||
export { useTradingViewTheme } from './useTradingViewTheme';
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
|
||||
import { AbacusOrderStatus, ORDER_SIDES, SubaccountOrder } from '@/constants/abacus';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { type OrderType, ORDER_TYPE_STRINGS } from '@/constants/trade';
|
||||
import type { ChartLine, TvWidget } from '@/constants/tvchart';
|
||||
|
||||
import { useStringGetter } from '@/hooks';
|
||||
|
||||
import { getCurrentMarketOrders, getCurrentMarketPositionData } from '@/state/accountSelectors';
|
||||
import { getAppTheme, getAppColorMode } from '@/state/configsSelectors';
|
||||
|
||||
import { MustBigNumber } from '@/lib/numbers';
|
||||
import { getChartLineColors } from '@/lib/tradingView/utils';
|
||||
|
||||
let chartLines: Record<string, ChartLine> = {};
|
||||
|
||||
/**
|
||||
* @description Hook to handle drawing chart lines
|
||||
*/
|
||||
|
||||
export const useChartLines = ({
|
||||
tvWidget,
|
||||
displayButton,
|
||||
isChartReady,
|
||||
}: {
|
||||
tvWidget: TvWidget | null;
|
||||
displayButton: HTMLElement | null;
|
||||
isChartReady?: boolean;
|
||||
}) => {
|
||||
const [showOrderLines, setShowOrderLines] = useState(false);
|
||||
|
||||
const stringGetter = useStringGetter();
|
||||
|
||||
const appTheme = useSelector(getAppTheme);
|
||||
const appColorMode = useSelector(getAppColorMode);
|
||||
|
||||
const currentMarketPositionData = useSelector(getCurrentMarketPositionData, shallowEqual);
|
||||
const currentMarketOrders: SubaccountOrder[] = useSelector(getCurrentMarketOrders, shallowEqual);
|
||||
|
||||
useEffect(() => {
|
||||
if (isChartReady && displayButton) {
|
||||
displayButton.onclick = () => {
|
||||
const newShowOrderLinesState = !showOrderLines;
|
||||
if (newShowOrderLinesState) {
|
||||
displayButton?.classList?.add('order-lines-active');
|
||||
} else {
|
||||
displayButton?.classList?.remove('order-lines-active');
|
||||
}
|
||||
setShowOrderLines(newShowOrderLinesState);
|
||||
};
|
||||
}
|
||||
}, [isChartReady, showOrderLines]);
|
||||
|
||||
useEffect(() => {
|
||||
if (tvWidget && isChartReady) {
|
||||
tvWidget.onChartReady(() => {
|
||||
tvWidget.chart().dataReady(() => {
|
||||
if (showOrderLines) {
|
||||
drawOrderLines();
|
||||
drawPositionLine();
|
||||
} else {
|
||||
deleteChartLines();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}, [isChartReady, showOrderLines, currentMarketPositionData, currentMarketOrders]);
|
||||
|
||||
const drawPositionLine = () => {
|
||||
if (!currentMarketPositionData) return;
|
||||
|
||||
const entryPrice = currentMarketPositionData.entryPrice?.current;
|
||||
const size = currentMarketPositionData.size?.current;
|
||||
|
||||
const key = currentMarketPositionData.id;
|
||||
const price = MustBigNumber(entryPrice).toNumber();
|
||||
|
||||
const maybePositionLine = chartLines[key]?.line;
|
||||
const shouldShow = size && size !== 0;
|
||||
|
||||
if (!shouldShow) {
|
||||
if (maybePositionLine) {
|
||||
maybePositionLine.remove();
|
||||
delete chartLines[key];
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const quantity = size.toString();
|
||||
|
||||
if (maybePositionLine) {
|
||||
if (maybePositionLine.getQuantity() !== quantity) {
|
||||
maybePositionLine.setQuantity(quantity);
|
||||
}
|
||||
if (maybePositionLine.getPrice() !== price) {
|
||||
maybePositionLine.setPrice(price);
|
||||
}
|
||||
} else {
|
||||
const positionLine = tvWidget
|
||||
?.chart()
|
||||
.createPositionLine({ disableUndo: false })
|
||||
.setText(stringGetter({ key: STRING_KEYS.ENTRY_PRICE_SHORT }))
|
||||
.setPrice(price)
|
||||
.setQuantity(quantity);
|
||||
|
||||
if (positionLine) {
|
||||
const chartLine = { line: positionLine, chartLineType: 'position' };
|
||||
setLineColors({ chartLine: chartLine });
|
||||
chartLines[key] = chartLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const drawOrderLines = () => {
|
||||
if (!currentMarketOrders) return;
|
||||
|
||||
currentMarketOrders.forEach(
|
||||
({
|
||||
id,
|
||||
type,
|
||||
status,
|
||||
side,
|
||||
cancelReason,
|
||||
remainingSize,
|
||||
size,
|
||||
triggerPrice,
|
||||
price,
|
||||
trailingPercent,
|
||||
}) => {
|
||||
const key = id;
|
||||
const quantity = (remainingSize ?? size).toString();
|
||||
|
||||
const orderType = type.rawValue as OrderType;
|
||||
const orderLabel = stringGetter({
|
||||
key: ORDER_TYPE_STRINGS[orderType].orderTypeKey,
|
||||
});
|
||||
const orderString = trailingPercent ? `${orderLabel} ${trailingPercent}%` : orderLabel;
|
||||
|
||||
const shouldShow =
|
||||
!cancelReason &&
|
||||
(status === AbacusOrderStatus.open || status === AbacusOrderStatus.untriggered);
|
||||
|
||||
const maybeOrderLine = chartLines[key]?.line;
|
||||
|
||||
if (!shouldShow) {
|
||||
if (maybeOrderLine) {
|
||||
maybeOrderLine.remove();
|
||||
delete chartLines[key];
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (maybeOrderLine) {
|
||||
if (maybeOrderLine.getQuantity() !== quantity) {
|
||||
maybeOrderLine.setQuantity(quantity);
|
||||
}
|
||||
} else {
|
||||
const orderLine = tvWidget
|
||||
?.chart()
|
||||
.createOrderLine({ disableUndo: false })
|
||||
.setPrice(MustBigNumber(triggerPrice ?? price).toNumber())
|
||||
.setQuantity(quantity)
|
||||
.setText(orderString);
|
||||
|
||||
if (orderLine) {
|
||||
const chartLine: ChartLine = {
|
||||
line: orderLine,
|
||||
chartLineType: ORDER_SIDES[side.name],
|
||||
};
|
||||
setLineColors({ chartLine: chartLine });
|
||||
chartLines[key] = chartLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const deleteChartLines = () => {
|
||||
Object.values(chartLines).forEach(({ line }) => {
|
||||
line.remove();
|
||||
});
|
||||
chartLines = {};
|
||||
};
|
||||
|
||||
const setLineColors = ({ chartLine }: { chartLine: ChartLine }) => {
|
||||
const { line, chartLineType } = chartLine;
|
||||
const { maybeQuantityColor, borderColor, backgroundColor, textColor, textButtonColor } =
|
||||
getChartLineColors({
|
||||
appTheme,
|
||||
appColorMode,
|
||||
chartLineType,
|
||||
});
|
||||
|
||||
line
|
||||
.setQuantityBorderColor(borderColor)
|
||||
.setBodyBackgroundColor(backgroundColor)
|
||||
.setBodyBorderColor(borderColor)
|
||||
.setBodyTextColor(textColor)
|
||||
.setQuantityTextColor(textButtonColor);
|
||||
|
||||
maybeQuantityColor &&
|
||||
line.setLineColor(maybeQuantityColor).setQuantityBackgroundColor(maybeQuantityColor);
|
||||
};
|
||||
|
||||
return { chartLines };
|
||||
};
|
||||
@@ -1,72 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import type { ResolutionString } from 'public/tradingview/charting_library';
|
||||
|
||||
import { DEFAULT_RESOLUTION, RESOLUTION_CHART_CONFIGS } from '@/constants/candles';
|
||||
import { DEFAULT_MARKETID } from '@/constants/markets';
|
||||
import type { TvWidget } from '@/constants/tvchart';
|
||||
|
||||
import { setTvChartResolution } from '@/state/perpetuals';
|
||||
import { getCurrentMarketId, getSelectedResolutionForMarket } from '@/state/perpetualsSelectors';
|
||||
|
||||
/**
|
||||
* @description Hook to handle changing markets and setting chart resolution
|
||||
*/
|
||||
|
||||
export const useChartMarketAndResolution = ({
|
||||
tvWidget,
|
||||
isWidgetReady,
|
||||
savedResolution,
|
||||
}: {
|
||||
tvWidget: TvWidget | null;
|
||||
isWidgetReady?: boolean;
|
||||
savedResolution?: ResolutionString;
|
||||
}) => {
|
||||
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]);
|
||||
|
||||
/**
|
||||
* @description Hook to handle changing chart resolution
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (chartResolution) {
|
||||
if (chartResolution !== selectedResolution) {
|
||||
dispatch(setTvChartResolution({ marketId: currentMarketId, resolution: chartResolution }));
|
||||
}
|
||||
|
||||
setVisibleRangeForResolution({ resolution: chartResolution });
|
||||
}
|
||||
}, [currentMarketId, chartResolution, selectedResolution]);
|
||||
|
||||
const setVisibleRangeForResolution = ({ resolution }: { resolution: ResolutionString }) => {
|
||||
// Different resolutions have different timeframes to display data efficiently.
|
||||
const { defaultRange } = RESOLUTION_CHART_CONFIGS[resolution];
|
||||
|
||||
// from/to values converted to epoch seconds
|
||||
const newRange = {
|
||||
from: (Date.now() - defaultRange) / 1000,
|
||||
to: Date.now() / 1000,
|
||||
};
|
||||
|
||||
tvWidget?.activeChart().setVisibleRange(newRange, { percentRightMargin: 10 });
|
||||
};
|
||||
};
|
||||
@@ -1,19 +1,17 @@
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
import { LanguageCode, ResolutionString, widget } from 'public/tradingview/charting_library';
|
||||
|
||||
import { DEFAULT_RESOLUTION } from '@/constants/candles';
|
||||
import { SUPPORTED_LOCALE_BASE_TAGS, STRING_KEYS } from '@/constants/localization';
|
||||
|
||||
import { LocalStorageKey } from '@/constants/localStorage';
|
||||
import type { TvWidget } from '@/constants/tvchart';
|
||||
|
||||
import { useDydxClient, useLocalStorage, useStringGetter } from '@/hooks';
|
||||
|
||||
import { store } from '@/state/_store';
|
||||
|
||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||
import { getAppTheme, getAppColorMode } from '@/state/configsSelectors';
|
||||
import { getSelectedLocale } from '@/state/localizationSelectors';
|
||||
@@ -30,8 +28,8 @@ export const useTradingView = ({
|
||||
displayButtonRef,
|
||||
setIsChartReady,
|
||||
}: {
|
||||
tvWidgetRef: React.MutableRefObject<TvWidget | null>;
|
||||
displayButtonRef: React.MutableRefObject<HTMLElement | null>;
|
||||
tvWidgetRef: React.MutableRefObject<any>;
|
||||
displayButtonRef: React.MutableRefObject<any>;
|
||||
setIsChartReady: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}) => {
|
||||
const stringGetter = useStringGetter();
|
||||
@@ -71,17 +69,15 @@ export const useTradingView = ({
|
||||
tvWidgetRef.current = tvChartWidget;
|
||||
|
||||
tvWidgetRef.current.onChartReady(() => {
|
||||
tvWidgetRef.current?.headerReady().then(() => {
|
||||
if (displayButtonRef && tvWidgetRef.current) {
|
||||
displayButtonRef.current = tvWidgetRef.current.createButton();
|
||||
displayButtonRef.current.innerHTML = `<span>${stringGetter({
|
||||
key: STRING_KEYS.ORDER_LINES,
|
||||
})}</span> <div class="displayOrdersButton-toggle"></div>`;
|
||||
displayButtonRef.current.setAttribute(
|
||||
'title',
|
||||
stringGetter({ key: STRING_KEYS.ORDER_LINES_TOOLTIP })
|
||||
);
|
||||
}
|
||||
tvWidgetRef?.current?.headerReady().then(() => {
|
||||
displayButtonRef.current = tvWidgetRef?.current?.createButton();
|
||||
displayButtonRef.current.innerHTML = `<span>${stringGetter({
|
||||
key: STRING_KEYS.ORDER_LINES,
|
||||
})}</span> <div class="displayOrdersButton-toggle"></div>`;
|
||||
displayButtonRef.current.setAttribute(
|
||||
'title',
|
||||
stringGetter({ key: STRING_KEYS.ORDER_LINES_TOOLTIP })
|
||||
);
|
||||
});
|
||||
|
||||
tvWidgetRef?.current?.subscribe('onAutoSaveNeeded', () =>
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { THEME_NAMES } from '@/constants/styles/colors';
|
||||
import type { ChartLine, TvWidget } from '@/constants/tvchart';
|
||||
import type {
|
||||
IChartingLibraryWidget,
|
||||
IOrderLineAdapter,
|
||||
ThemeName,
|
||||
} from 'public/tradingview/charting_library';
|
||||
|
||||
import { AppColorMode, AppTheme } from '@/state/configs';
|
||||
import { getAppTheme, getAppColorMode } from '@/state/configsSelectors';
|
||||
|
||||
import { getWidgetOverrides, getChartLineColors } from '@/lib/tradingView/utils';
|
||||
import { getWidgetOverrides, getOrderLineColors } from '@/lib/tradingView/utils';
|
||||
|
||||
/**
|
||||
* @description Method to define a type guard and check that an element is an IFRAME
|
||||
@@ -24,12 +26,12 @@ const isIFrame = (element: HTMLElement | null): element is HTMLIFrameElement =>
|
||||
* In order to support our Classic along with Dark/Light, we are directly accessing the <html> within the iFrame.
|
||||
*/
|
||||
export const useTradingViewTheme = ({
|
||||
chartLines,
|
||||
orderLines,
|
||||
tvWidget,
|
||||
isWidgetReady,
|
||||
}: {
|
||||
chartLines: Record<string, ChartLine>;
|
||||
tvWidget: TvWidget | null;
|
||||
orderLines: Record<string, IOrderLineAdapter>;
|
||||
tvWidget: (IChartingLibraryWidget & { _id?: string; _ready?: boolean }) | null;
|
||||
isWidgetReady?: boolean;
|
||||
}) => {
|
||||
const appTheme: AppTheme = useSelector(getAppTheme);
|
||||
@@ -37,64 +39,70 @@ export const useTradingViewTheme = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (tvWidget && isWidgetReady) {
|
||||
tvWidget.changeTheme?.(THEME_NAMES[appTheme]).then(() => {
|
||||
const tvChartId = tvWidget?._id;
|
||||
tvWidget
|
||||
.changeTheme?.(
|
||||
{
|
||||
[AppTheme.Classic]: '',
|
||||
[AppTheme.Dark]: 'dark',
|
||||
[AppTheme.Light]: 'light',
|
||||
}[appTheme] as ThemeName
|
||||
)
|
||||
.then(() => {
|
||||
const tvChartId = tvWidget?._id;
|
||||
|
||||
if (tvChartId) {
|
||||
const frame = document?.getElementById(tvChartId);
|
||||
if (tvChartId) {
|
||||
const frame = document?.getElementById(tvChartId);
|
||||
|
||||
if (isIFrame(frame) && frame.contentWindow) {
|
||||
const innerHtml = frame.contentWindow.document.documentElement;
|
||||
switch (appTheme) {
|
||||
case AppTheme.Classic:
|
||||
innerHtml?.classList.remove('theme-dark', 'theme-light');
|
||||
break;
|
||||
case AppTheme.Dark:
|
||||
innerHtml?.classList.remove('theme-light');
|
||||
innerHtml?.classList.add('theme-dark');
|
||||
break;
|
||||
case AppTheme.Light:
|
||||
innerHtml?.classList.remove('theme-dark');
|
||||
innerHtml?.classList.add('theme-light');
|
||||
if (isIFrame(frame) && frame.contentWindow) {
|
||||
const innerHtml = frame.contentWindow.document.documentElement;
|
||||
switch (appTheme) {
|
||||
case AppTheme.Classic:
|
||||
innerHtml?.classList.remove('theme-dark', 'theme-light');
|
||||
break;
|
||||
case AppTheme.Dark:
|
||||
innerHtml?.classList.remove('theme-light');
|
||||
innerHtml?.classList.add('theme-dark');
|
||||
break;
|
||||
case AppTheme.Light:
|
||||
innerHtml?.classList.remove('theme-dark');
|
||||
innerHtml?.classList.add('theme-light');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const { overrides, studies_overrides } = getWidgetOverrides({ appTheme, appColorMode });
|
||||
tvWidget?.applyOverrides(overrides);
|
||||
tvWidget?.applyStudiesOverrides(studies_overrides);
|
||||
const { overrides, studies_overrides } = getWidgetOverrides({ appTheme, appColorMode });
|
||||
tvWidget?.applyOverrides(overrides);
|
||||
tvWidget?.applyStudiesOverrides(studies_overrides);
|
||||
|
||||
// Necessary to update existing indicators
|
||||
const volumeStudyId = tvWidget
|
||||
?.activeChart()
|
||||
?.getAllStudies()
|
||||
?.find((x) => x.name === 'Volume')?.id;
|
||||
// Necessary to update existing indicators
|
||||
const volumeStudyId = tvWidget
|
||||
?.activeChart()
|
||||
?.getAllStudies()
|
||||
?.find((x) => x.name === 'Volume')?.id;
|
||||
|
||||
if (volumeStudyId) {
|
||||
const volume = tvWidget?.activeChart()?.getStudyById(volumeStudyId);
|
||||
volume.applyOverrides({
|
||||
'volume.color.0': studies_overrides['volume.volume.color.0'],
|
||||
'volume.color.1': studies_overrides['volume.volume.color.1'],
|
||||
});
|
||||
}
|
||||
|
||||
// Necessary to update existing chart lines
|
||||
Object.values(chartLines).forEach(({ chartLineType, line }) => {
|
||||
const { maybeQuantityColor, borderColor, backgroundColor, textColor, textButtonColor } =
|
||||
getChartLineColors({ chartLineType: chartLineType, appTheme, appColorMode });
|
||||
|
||||
if (maybeQuantityColor) {
|
||||
line.setLineColor(maybeQuantityColor).setQuantityBackgroundColor(maybeQuantityColor);
|
||||
if (volumeStudyId) {
|
||||
const volume = tvWidget?.activeChart()?.getStudyById(volumeStudyId);
|
||||
volume.applyOverrides({
|
||||
'volume.color.0': studies_overrides['volume.volume.color.0'],
|
||||
'volume.color.1': studies_overrides['volume.volume.color.1'],
|
||||
});
|
||||
}
|
||||
|
||||
line
|
||||
.setQuantityBorderColor(borderColor)
|
||||
.setBodyBackgroundColor(backgroundColor)
|
||||
.setBodyBorderColor(borderColor)
|
||||
.setBodyTextColor(textColor)
|
||||
.setQuantityTextColor(textButtonColor);
|
||||
// Necessary to update existing chart lines
|
||||
Object.entries(orderLines).forEach(([key, line]) => {
|
||||
const { orderColor, borderColor, backgroundColor, textColor, textButtonColor } =
|
||||
getOrderLineColors({ side: key.split('-')[0], appTheme, appColorMode });
|
||||
|
||||
line
|
||||
.setLineColor(orderColor)
|
||||
.setQuantityBackgroundColor(orderColor)
|
||||
.setQuantityBorderColor(borderColor)
|
||||
.setBodyBackgroundColor(backgroundColor)
|
||||
.setBodyBorderColor(borderColor)
|
||||
.setBodyTextColor(textColor)
|
||||
.setQuantityTextColor(textButtonColor);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}, [appTheme, appColorMode, isWidgetReady]);
|
||||
};
|
||||
|
||||
@@ -18,13 +18,14 @@ 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);
|
||||
@@ -40,8 +41,7 @@ const useDydxClientContext = () => {
|
||||
// ------ Network ------ //
|
||||
|
||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||
const { usdcDenom, usdcDecimals, usdcGasDenom, chainTokenDenom, chainTokenDecimals } =
|
||||
useTokenConfigs();
|
||||
const tokensConfigs = ENVIRONMENT_CONFIG_MAP[selectedNetwork].tokens;
|
||||
|
||||
const [networkConfig, setNetworkConfig] = useState<NetworkConfig>();
|
||||
|
||||
@@ -75,11 +75,11 @@ const useDydxClientContext = () => {
|
||||
networkConfig.validatorUrl,
|
||||
networkConfig.chainId,
|
||||
{
|
||||
USDC_DENOM: usdcDenom,
|
||||
USDC_DECIMALS: usdcDecimals,
|
||||
USDC_GAS_DENOM: usdcGasDenom,
|
||||
CHAINTOKEN_DENOM: chainTokenDenom,
|
||||
CHAINTOKEN_DECIMALS: chainTokenDecimals,
|
||||
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,
|
||||
},
|
||||
{
|
||||
broadcastPollIntervalMs: 3_000,
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { GOVERNANCE_CONFIG_MAP } from '@/constants/networks';
|
||||
|
||||
import { getSelectedDydxChainId } from '@/state/appSelectors';
|
||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||
import { useSelectedNetwork } from '@/hooks';
|
||||
|
||||
export interface GovernanceVariables {
|
||||
newMarketProposal: {
|
||||
@@ -13,7 +10,7 @@ export interface GovernanceVariables {
|
||||
}
|
||||
|
||||
export const useGovernanceVariables = (): GovernanceVariables => {
|
||||
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
|
||||
const governanceVars = GOVERNANCE_CONFIG_MAP[selectedDydxChainId] as GovernanceVariables;
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
const governanceVars = ENVIRONMENT_CONFIG_MAP[selectedNetwork].governance as GovernanceVariables;
|
||||
return governanceVars;
|
||||
};
|
||||
|
||||
@@ -5,6 +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 { DydxChainAsset } from '@/constants/wallets';
|
||||
|
||||
@@ -22,7 +23,7 @@ import {
|
||||
TransferNotificationTypes,
|
||||
} from '@/constants/notifications';
|
||||
|
||||
import { useStringGetter } from '@/hooks';
|
||||
import { useSelectedNetwork, useStringGetter } from '@/hooks';
|
||||
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
|
||||
|
||||
import { AssetIcon } from '@/components/AssetIcon';
|
||||
@@ -35,7 +36,6 @@ 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,7 +175,7 @@ export const notificationTypes: NotificationTypeConfig[] = [
|
||||
useTrigger: ({ trigger }) => {
|
||||
const stringGetter = useStringGetter();
|
||||
const { transferNotifications } = useLocalNotifications();
|
||||
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
|
||||
useEffect(() => {
|
||||
for (const transfer of transferNotifications) {
|
||||
@@ -184,7 +184,7 @@ export const notificationTypes: NotificationTypeConfig[] = [
|
||||
const icon = <Icon iconName={isFinished ? IconName.Transfer : IconName.Clock} />;
|
||||
|
||||
const transferType =
|
||||
type ?? fromChainId === selectedDydxChainId
|
||||
type ?? fromChainId === ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId
|
||||
? TransferNotificationTypes.Withdrawal
|
||||
: TransferNotificationTypes.Deposit;
|
||||
|
||||
|
||||
@@ -4,11 +4,8 @@ import { useSelector } from 'react-redux';
|
||||
import { DEFAULT_DOCUMENT_TITLE } from '@/constants/routes';
|
||||
|
||||
import { getSelectedLocale } from '@/state/localizationSelectors';
|
||||
import {
|
||||
getCurrentMarketId,
|
||||
getCurrentMarketMidMarketPrice,
|
||||
getCurrentMarketOraclePrice,
|
||||
} from '@/state/perpetualsSelectors';
|
||||
import { getCurrentMarketData, getCurrentMarketId } from '@/state/perpetualsSelectors';
|
||||
import type { RootState } from '@/state/_store';
|
||||
|
||||
import { useBreakpoints } from './useBreakpoints';
|
||||
|
||||
@@ -16,14 +13,11 @@ export const usePageTitlePriceUpdates = () => {
|
||||
const selectedLocale = useSelector(getSelectedLocale);
|
||||
const { isNotTablet } = useBreakpoints();
|
||||
const id = useSelector(getCurrentMarketId);
|
||||
const oraclePrice = useSelector(getCurrentMarketOraclePrice);
|
||||
const orderbookMidMarketPrice = useSelector(getCurrentMarketMidMarketPrice);
|
||||
|
||||
const price = orderbookMidMarketPrice ?? oraclePrice;
|
||||
const oraclePrice = useSelector((state: RootState) => getCurrentMarketData(state)?.oraclePrice);
|
||||
|
||||
useEffect(() => {
|
||||
if (id && price && isNotTablet) {
|
||||
const priceString = price.toLocaleString(selectedLocale);
|
||||
if (id && oraclePrice && isNotTablet) {
|
||||
const priceString = oraclePrice.toLocaleString(selectedLocale);
|
||||
document.title = `$${priceString} ${id} · ${DEFAULT_DOCUMENT_TITLE}`;
|
||||
} else {
|
||||
document.title = DEFAULT_DOCUMENT_TITLE;
|
||||
@@ -32,5 +26,5 @@ export const usePageTitlePriceUpdates = () => {
|
||||
return () => {
|
||||
document.title = DEFAULT_DOCUMENT_TITLE;
|
||||
};
|
||||
}, [price]);
|
||||
}, [oraclePrice]);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useCallback } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { LocalStorageKey } from '@/constants/localStorage';
|
||||
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork } from '@/constants/networks';
|
||||
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork, ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||
|
||||
import { useAccounts, useLocalStorage } from '@/hooks';
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import { setSubaccount, setHistoricalPnl, removeUncommittedOrderClientId } from
|
||||
import { getBalances } from '@/state/accountSelectors';
|
||||
|
||||
import abacusStateManager from '@/lib/abacus';
|
||||
import { hashFromTx } from '@/lib/txUtils';
|
||||
import { hashFromTx } from '@/lib/hashfromTx';
|
||||
import { log } from '@/lib/telemetry';
|
||||
|
||||
import { useAccounts } from './useAccounts';
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { TOKEN_CONFIG_MAP } from '@/constants/networks';
|
||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||
import { DydxChainAsset } from '@/constants/wallets';
|
||||
|
||||
import { getSelectedDydxChainId } from '@/state/appSelectors';
|
||||
import { useSelectedNetwork } from '@/hooks';
|
||||
|
||||
export const useTokenConfigs = (): {
|
||||
tokensConfigs: {
|
||||
@@ -12,33 +10,31 @@ 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 selectedDydxChainId = useSelector(getSelectedDydxChainId);
|
||||
const tokensConfigs = TOKEN_CONFIG_MAP[selectedDydxChainId];
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
const tokensConfigs = ENVIRONMENT_CONFIG_MAP[selectedNetwork].tokens;
|
||||
|
||||
return {
|
||||
return {
|
||||
tokensConfigs,
|
||||
usdcDenom: tokensConfigs[DydxChainAsset.USDC].denom,
|
||||
usdcDecimals: tokensConfigs[DydxChainAsset.USDC].decimals,
|
||||
usdcGasDenom: tokensConfigs[DydxChainAsset.USDC].gasDenom,
|
||||
usdcDenom: tokensConfigs[DydxChainAsset.USDC].denom,
|
||||
usdcDecimals: tokensConfigs[DydxChainAsset.USDC].decimals,
|
||||
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,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||
|
||||
import { LINKS_CONFIG_MAP } from '@/constants/networks';
|
||||
|
||||
import { getSelectedDydxChainId } from '@/state/appSelectors';
|
||||
import { useSelectedNetwork } from '@/hooks';
|
||||
|
||||
const FALLBACK_URL = 'https://help.dydx.exchange/';
|
||||
|
||||
export interface LinksConfigs {
|
||||
tos: string;
|
||||
privacy: string;
|
||||
statusPage: string;
|
||||
mintscan: string;
|
||||
mintscanBase: string;
|
||||
feedback?: string;
|
||||
@@ -30,13 +27,12 @@ export interface LinksConfigs {
|
||||
}
|
||||
|
||||
export const useURLConfigs = (): LinksConfigs => {
|
||||
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
|
||||
const linksConfigs = LINKS_CONFIG_MAP[selectedDydxChainId] as LinksConfigs;
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
const linksConfigs = ENVIRONMENT_CONFIG_MAP[selectedNetwork].links as LinksConfigs;
|
||||
|
||||
return {
|
||||
tos: linksConfigs.tos,
|
||||
privacy: linksConfigs.privacy,
|
||||
statusPage: linksConfigs.statusPage,
|
||||
mintscan: linksConfigs.mintscan,
|
||||
mintscanBase: linksConfigs.mintscanBase,
|
||||
feedback: linksConfigs.feedback || FALLBACK_URL,
|
||||
|
||||
@@ -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, WALLETS_CONFIG_MAP } from '@/constants/networks';
|
||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||
|
||||
import {
|
||||
type DydxAddress,
|
||||
@@ -32,7 +32,7 @@ import {
|
||||
WalletType as CosmosWalletType,
|
||||
} from 'graz';
|
||||
|
||||
import { getSelectedDydxChainId } from '@/state/appSelectors';
|
||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||
|
||||
import { resolveWagmiConnector } from '@/lib/wagmi';
|
||||
import { getWalletConnection, parseWalletError } from '@/lib/wallet';
|
||||
@@ -91,8 +91,8 @@ export const useWalletConnection = () => {
|
||||
|
||||
// Wallet connection
|
||||
|
||||
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
|
||||
const walletConnectConfig = WALLETS_CONFIG_MAP[selectedDydxChainId].walletconnect;
|
||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||
const walletConnectConfig = ENVIRONMENT_CONFIG_MAP[selectedNetwork].wallets.walletconnect;
|
||||
const wagmiConnector = useMemo(
|
||||
() =>
|
||||
walletType && walletConnectionType
|
||||
@@ -163,20 +163,17 @@ export const useWalletConnection = () => {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
const { isErrorExpected } = parseWalletError({ error, stringGetter });
|
||||
if (!isErrorExpected) {
|
||||
throw Object.assign(
|
||||
new Error([error.message, error.cause?.message].filter(Boolean).join('\n')),
|
||||
{
|
||||
walletConnectionType: walletConnection?.type,
|
||||
}
|
||||
);
|
||||
}
|
||||
throw Object.assign(
|
||||
new Error([error.message, error.cause?.message].filter(Boolean).join('\n')),
|
||||
{
|
||||
walletConnectionType: walletConnection?.type,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
walletType,
|
||||
walletConnectionType: walletConnection?.type,
|
||||
walletConnectionType: walletConnection.type,
|
||||
};
|
||||
},
|
||||
[isConnectedGraz, signerGraz, isConnectedWagmi, signerWagmi]
|
||||
|
||||
@@ -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 { isDev } from '@/constants/networks';
|
||||
import { ENVIRONMENT_CONFIG_MAP, isDev } from '@/constants/networks';
|
||||
|
||||
import { useApiState, useStringGetter, useURLConfigs } from '@/hooks';
|
||||
import { useApiState, useSelectedNetwork, useStringGetter } from '@/hooks';
|
||||
import { ChatIcon, LinkOutIcon } from '@/icons';
|
||||
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
@@ -28,7 +28,8 @@ enum ExchangeStatus {
|
||||
export const FooterDesktop = () => {
|
||||
const stringGetter = useStringGetter();
|
||||
const { height, indexerHeight, status, statusErrorMessage } = useApiState();
|
||||
const { statusPage } = useURLConfigs();
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
const { statusPage } = ENVIRONMENT_CONFIG_MAP[selectedNetwork].links;
|
||||
|
||||
const { exchangeStatus, label } =
|
||||
!status || status === AbacusApiStatus.NORMAL
|
||||
|
||||
@@ -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 { DydxChainId, isTestnet } from '@/constants/networks';
|
||||
import { ENVIRONMENT_CONFIG_MAP, DydxNetwork, isTestnet } from '@/constants/networks';
|
||||
|
||||
import { RootStore } from '@/state/_store';
|
||||
import { addUncommittedOrderClientId, removeUncommittedOrderClientId } from '@/state/account';
|
||||
@@ -43,11 +43,7 @@ import { openDialog } from '@/state/dialogs';
|
||||
import { StatefulOrderError } from '../errors';
|
||||
import { bytesToBigInt } from '../numbers';
|
||||
import { log } from '../telemetry';
|
||||
import { hashFromTx, getMintscanTxLink } from '../txUtils';
|
||||
|
||||
(BigInt.prototype as any).toJSON = function () {
|
||||
return this.toString();
|
||||
};
|
||||
import { hashFromTx } from '../hashfromTx';
|
||||
|
||||
class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
private compositeClient: CompositeClient | undefined;
|
||||
@@ -242,7 +238,9 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
|
||||
if (isTestnet) {
|
||||
console.log(
|
||||
getMintscanTxLink(this.compositeClient.network.getString() as DydxChainId, hash)
|
||||
`${ENVIRONMENT_CONFIG_MAP[
|
||||
this.compositeClient.network.getString() as DydxNetwork
|
||||
]?.links?.mintscan?.replace('{tx_hash}', hash.toString())}`
|
||||
);
|
||||
} else console.log(`txHash: ${hash}`);
|
||||
|
||||
@@ -538,6 +536,7 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
const result = await this.cctpWithdraw(params);
|
||||
callback(result);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export const hashFromTx = (
|
||||
txHash: string | Uint8Array
|
||||
): string => `0x${Buffer.from(txHash).toString('hex')}`;
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type DydxNetwork, ENVIRONMENT_CONFIG_MAP, type DydxChainId } from '@/constants/networks';
|
||||
import { type DydxNetwork, ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||
|
||||
export const validateAgainstAvailableEnvironments = (value: DydxNetwork) =>
|
||||
Object.keys(ENVIRONMENT_CONFIG_MAP).includes(value);
|
||||
Object.keys(ENVIRONMENT_CONFIG_MAP).includes(value);
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||
|
||||
import { Candle, TradingViewBar, TradingViewSymbol } from '@/constants/candles';
|
||||
import { THEME_NAMES } from '@/constants/styles/colors';
|
||||
import type { ChartLineType } from '@/constants/tvchart';
|
||||
|
||||
import { type AppColorMode, AppTheme } from '@/state/configs';
|
||||
import { AppTheme, type AppColorMode } from '@/state/configs';
|
||||
|
||||
import { Themes } from '@/styles/themes';
|
||||
|
||||
@@ -51,24 +49,23 @@ export const getHistorySlice = ({
|
||||
return bars.filter(({ time }) => time >= fromMs);
|
||||
};
|
||||
|
||||
export const getChartLineColors = ({
|
||||
export const getOrderLineColors = ({
|
||||
appTheme,
|
||||
appColorMode,
|
||||
chartLineType,
|
||||
side,
|
||||
}: {
|
||||
appTheme: AppTheme;
|
||||
appColorMode: AppColorMode;
|
||||
chartLineType: ChartLineType;
|
||||
side: OrderSide;
|
||||
}) => {
|
||||
const theme = Themes[appTheme][appColorMode];
|
||||
const orderColors = {
|
||||
const orderColor = {
|
||||
[OrderSide.BUY]: theme.positive,
|
||||
[OrderSide.SELL]: theme.negative,
|
||||
['position']: null,
|
||||
};
|
||||
}[side];
|
||||
|
||||
return {
|
||||
maybeQuantityColor: orderColors[chartLineType],
|
||||
orderColor,
|
||||
borderColor: theme.borderDefault,
|
||||
backgroundColor: theme.layer1,
|
||||
textColor: theme.textTertiary,
|
||||
@@ -86,7 +83,7 @@ export const getWidgetOverrides = ({
|
||||
const theme = Themes[appTheme][appColorMode];
|
||||
|
||||
return {
|
||||
theme: THEME_NAMES[appTheme],
|
||||
theme: appTheme === AppTheme.Dark ? 'dark' : AppTheme.Light ? 'light' : '',
|
||||
overrides: {
|
||||
'paneProperties.background': theme.layer2,
|
||||
'paneProperties.horzGridProperties.color': theme.layer3,
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
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())}`;
|
||||
@@ -92,10 +92,6 @@ export const getWalletErrorType = ({ error }: { error: Error }) => {
|
||||
return WalletErrorType.ChainMismatch;
|
||||
}
|
||||
|
||||
if (messageLower.includes('Missing or invalid. request() method: wallet_switchEthereumChain')) {
|
||||
return WalletErrorType.SwitchChainMethodMissing;
|
||||
}
|
||||
|
||||
// ImToken - User canceled
|
||||
if (messageLower.includes('用户取消了操作')) {
|
||||
return WalletErrorType.UserCanceled;
|
||||
@@ -117,18 +113,13 @@ export const parseWalletError = ({
|
||||
}) => {
|
||||
const walletErrorType = getWalletErrorType({ error });
|
||||
let message;
|
||||
let isErrorExpected;
|
||||
|
||||
switch (walletErrorType) {
|
||||
case WalletErrorType.ChainMismatch:
|
||||
case WalletErrorType.UserCanceled:
|
||||
case WalletErrorType.SwitchChainMethodMissing: {
|
||||
isErrorExpected = true;
|
||||
message = error.message;
|
||||
case WalletErrorType.UserCanceled: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
isErrorExpected = false;
|
||||
message = stringGetter({
|
||||
key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
|
||||
params: {
|
||||
@@ -141,6 +132,5 @@ export const parseWalletError = ({
|
||||
return {
|
||||
walletErrorType,
|
||||
message,
|
||||
isErrorExpected,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -26,6 +26,8 @@ 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();
|
||||
@@ -72,38 +74,14 @@ 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 ?? ''}`,
|
||||
queryKey: `launch_incentives_rewards_${dydxAddress ?? ''}_${SEASON_NUMBER}`,
|
||||
queryFn: async () => {
|
||||
if (!dydxAddress) return undefined;
|
||||
const resp = await fetch(`https://cloud.chaoslabs.co/query/api/dydx/points/${dydxAddress}`);
|
||||
const resp = await fetch(
|
||||
`https://cloud.chaoslabs.co/query/api/dydx/points/${dydxAddress}?n=${SEASON_NUMBER}`
|
||||
);
|
||||
return (await resp.json())?.incentivePoints;
|
||||
},
|
||||
onError: (error: Error) => log('LaunchIncentives/fetchPoints', error),
|
||||
@@ -114,14 +92,12 @@ const EstimatedRewards = () => {
|
||||
<Styled.EstimatedRewardsCardContent>
|
||||
<div>
|
||||
<span>{stringGetter({ key: STRING_KEYS.ESTIMATED_REWARDS })}</span>
|
||||
{seasonNumber !== undefined && (
|
||||
<Styled.Season>
|
||||
{stringGetter({
|
||||
key: STRING_KEYS.LAUNCH_INCENTIVES_SEASON_NUM,
|
||||
params: { SEASON_NUMBER: seasonNumber },
|
||||
})}
|
||||
</Styled.Season>
|
||||
)}
|
||||
<Styled.Season>
|
||||
{stringGetter({
|
||||
key: STRING_KEYS.LAUNCH_INCENTIVES_SEASON_NUM,
|
||||
params: { SEASON_NUMBER },
|
||||
})}
|
||||
</Styled.Season>
|
||||
</div>
|
||||
|
||||
<Styled.Points>
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
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;
|
||||
|
||||
@@ -107,12 +107,6 @@ export const getCurrentMarketHistoricalFundings = createSelector(
|
||||
currentMarketId ? historicalFundings?.[currentMarketId] ?? [] : []
|
||||
);
|
||||
|
||||
/**
|
||||
* @returns oracle price of the market the user is currently viewing
|
||||
*/
|
||||
export const getCurrentMarketOraclePrice = (state: RootState) =>
|
||||
getCurrentMarketData(state)?.oraclePrice;
|
||||
|
||||
/**
|
||||
* @returns Mid market price for the market the user is currently viewing
|
||||
*/
|
||||
|
||||
@@ -1,40 +1,205 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import styled, { type AnyStyledComponent, css } from 'styled-components';
|
||||
|
||||
import type { ResolutionString } from 'public/tradingview/charting_library';
|
||||
import type {
|
||||
IChartingLibraryWidget,
|
||||
IOrderLineAdapter,
|
||||
ResolutionString,
|
||||
} from 'public/tradingview/charting_library';
|
||||
|
||||
import type { TvWidget } from '@/constants/tvchart';
|
||||
import { AbacusOrderStatus } from '@/constants/abacus';
|
||||
import { DEFAULT_RESOLUTION, RESOLUTION_CHART_CONFIGS } from '@/constants/candles';
|
||||
import { DEFAULT_MARKETID } from '@/constants/markets';
|
||||
import { type OrderType, ORDER_TYPE_STRINGS } from '@/constants/trade';
|
||||
|
||||
import {
|
||||
useChartLines,
|
||||
useChartMarketAndResolution,
|
||||
useTradingView,
|
||||
useTradingViewTheme,
|
||||
} from '@/hooks/tradingView';
|
||||
import { useStringGetter } from '@/hooks';
|
||||
import { useTradingView, useTradingViewTheme } from '@/hooks/tradingView';
|
||||
|
||||
import { LoadingSpace } from '@/components/Loading/LoadingSpinner';
|
||||
|
||||
import { getCurrentMarketOrders } from '@/state/accountSelectors';
|
||||
import { getAppTheme, getAppColorMode } from '@/state/configsSelectors';
|
||||
import { setTvChartResolution } from '@/state/perpetuals';
|
||||
import { getCurrentMarketId, getSelectedResolutionForMarket } from '@/state/perpetualsSelectors';
|
||||
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
import { MustBigNumber } from '@/lib/numbers';
|
||||
import { getOrderLineColors } from '@/lib/tradingView/utils';
|
||||
|
||||
type TvWidget = IChartingLibraryWidget & { _id?: string; _ready?: boolean };
|
||||
|
||||
let orderLines: Record<string, IOrderLineAdapter> = {};
|
||||
|
||||
export const TvChart = () => {
|
||||
const dispatch = useDispatch();
|
||||
const stringGetter = useStringGetter();
|
||||
|
||||
const [isChartReady, setIsChartReady] = useState(false);
|
||||
const [showOrderLines, setShowOrderLines] = useState(false);
|
||||
|
||||
const displayButtonRef = useRef<HTMLElement | null>(null);
|
||||
|
||||
const appTheme = useSelector(getAppTheme);
|
||||
const appColorMode = useSelector(getAppColorMode);
|
||||
|
||||
const currentMarketId: string = useSelector(getCurrentMarketId) || DEFAULT_MARKETID;
|
||||
const currentMarketOrders = useSelector(getCurrentMarketOrders, shallowEqual);
|
||||
|
||||
const selectedResolution: string =
|
||||
useSelector(getSelectedResolutionForMarket(currentMarketId)) || DEFAULT_RESOLUTION;
|
||||
|
||||
const tvWidgetRef = useRef<TvWidget | null>(null);
|
||||
const tvWidget = tvWidgetRef.current;
|
||||
const isWidgetReady = tvWidget?._ready;
|
||||
|
||||
const displayButtonRef = useRef<HTMLElement | null>(null);
|
||||
const displayButton = displayButtonRef.current;
|
||||
const chart = isWidgetReady ? tvWidget?.chart() : undefined;
|
||||
const chartResolution = chart?.resolution?.();
|
||||
|
||||
const { savedResolution } = useTradingView({ tvWidgetRef, displayButtonRef, setIsChartReady });
|
||||
useChartMarketAndResolution({
|
||||
tvWidget,
|
||||
isWidgetReady,
|
||||
savedResolution: savedResolution as ResolutionString | undefined,
|
||||
});
|
||||
const { chartLines } = useChartLines({ tvWidget, displayButton, isChartReady });
|
||||
useTradingViewTheme({ tvWidget, isWidgetReady, chartLines });
|
||||
useTradingViewTheme({ tvWidget, isWidgetReady, orderLines });
|
||||
|
||||
const setVisibleRangeForResolution = ({ resolution }: { resolution: ResolutionString }) => {
|
||||
// Different resolutions have different timeframes to display data efficiently.
|
||||
const { defaultRange } = RESOLUTION_CHART_CONFIGS[resolution];
|
||||
|
||||
// from/to values converted to epoch seconds
|
||||
const newRange = {
|
||||
from: (Date.now() - defaultRange) / 1000,
|
||||
to: Date.now() / 1000,
|
||||
};
|
||||
|
||||
tvWidget?.activeChart().setVisibleRange(newRange, { percentRightMargin: 10 });
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Hook to handle changing chart resolution
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (chartResolution) {
|
||||
if (chartResolution !== selectedResolution) {
|
||||
dispatch(setTvChartResolution({ marketId: currentMarketId, resolution: chartResolution }));
|
||||
}
|
||||
|
||||
setVisibleRangeForResolution({ resolution: chartResolution });
|
||||
}
|
||||
}, [chartResolution]);
|
||||
|
||||
/**
|
||||
* @description Hook to handle changing markets
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (currentMarketId && isWidgetReady) {
|
||||
const resolution = savedResolution || selectedResolution;
|
||||
tvWidget?.setSymbol(currentMarketId, resolution as ResolutionString, () => {});
|
||||
}
|
||||
}, [currentMarketId, isWidgetReady]);
|
||||
|
||||
/**
|
||||
* @description Hook to handle order line toggle state
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (isChartReady && displayButtonRef && displayButtonRef.current) {
|
||||
displayButtonRef.current.onclick = () => {
|
||||
const newShowOrderLinesState = !showOrderLines;
|
||||
if (newShowOrderLinesState) {
|
||||
displayButtonRef.current?.classList?.add('order-lines-active');
|
||||
} else {
|
||||
displayButtonRef.current?.classList?.remove('order-lines-active');
|
||||
}
|
||||
setShowOrderLines(newShowOrderLinesState);
|
||||
};
|
||||
}
|
||||
}, [isChartReady, showOrderLines]);
|
||||
|
||||
/**
|
||||
* @description Hook to handle drawing order lines
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (tvWidget && isChartReady) {
|
||||
tvWidget.onChartReady(() => {
|
||||
tvWidget.chart().dataReady(() => {
|
||||
if (showOrderLines) {
|
||||
drawOrderLines();
|
||||
} else {
|
||||
deleteOrderLines();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}, [isChartReady, showOrderLines, currentMarketOrders, currentMarketId]);
|
||||
|
||||
const drawOrderLines = () => {
|
||||
if (!currentMarketOrders) return;
|
||||
currentMarketOrders.forEach(
|
||||
({
|
||||
id,
|
||||
type,
|
||||
status,
|
||||
side,
|
||||
cancelReason,
|
||||
remainingSize,
|
||||
size,
|
||||
triggerPrice,
|
||||
price,
|
||||
trailingPercent,
|
||||
}) => {
|
||||
const key = `${side.rawValue}-${id}`;
|
||||
const quantity = (remainingSize ?? size).toString();
|
||||
|
||||
const orderType = type.rawValue as OrderType;
|
||||
const orderLabel = stringGetter({
|
||||
key: ORDER_TYPE_STRINGS[orderType].orderTypeKey,
|
||||
});
|
||||
const orderString = trailingPercent ? `${orderLabel} ${trailingPercent}%` : orderLabel;
|
||||
|
||||
const shouldShow =
|
||||
!cancelReason &&
|
||||
(status === AbacusOrderStatus.open || status === AbacusOrderStatus.untriggered);
|
||||
|
||||
const maybeOrderLine = key in orderLines ? orderLines[key] : null;
|
||||
if (maybeOrderLine) {
|
||||
if (!shouldShow) {
|
||||
maybeOrderLine.remove();
|
||||
delete orderLines[key];
|
||||
return;
|
||||
} else if (maybeOrderLine.getQuantity() !== quantity) {
|
||||
maybeOrderLine.setQuantity(quantity);
|
||||
return;
|
||||
}
|
||||
} else if (shouldShow) {
|
||||
const { orderColor, borderColor, backgroundColor, textColor, textButtonColor } =
|
||||
getOrderLineColors({ side: side.rawValue, appTheme, appColorMode });
|
||||
|
||||
const orderLine = tvWidget
|
||||
?.chart()
|
||||
.createOrderLine({ disableUndo: false })
|
||||
.setPrice(MustBigNumber(triggerPrice ?? price).toNumber())
|
||||
.setQuantity(quantity)
|
||||
.setText(orderString)
|
||||
.setLineColor(orderColor)
|
||||
.setQuantityBackgroundColor(orderColor)
|
||||
.setQuantityBorderColor(borderColor)
|
||||
.setBodyBackgroundColor(backgroundColor)
|
||||
.setBodyBorderColor(borderColor)
|
||||
.setBodyTextColor(textColor)
|
||||
.setQuantityTextColor(textButtonColor);
|
||||
|
||||
if (orderLine) {
|
||||
orderLines[key] = orderLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const deleteOrderLines = () => {
|
||||
Object.values(orderLines).forEach((line) => {
|
||||
line.remove();
|
||||
});
|
||||
orderLines = {};
|
||||
};
|
||||
|
||||
return (
|
||||
<Styled.PriceChart isChartReady={isChartReady}>
|
||||
|
||||
@@ -32,15 +32,7 @@ export const ExternalNavKeplrDialog = ({ setIsOpen }: ElementProps) => {
|
||||
openDialog({
|
||||
type: DialogTypes.ExternalLink,
|
||||
dialogProps: {
|
||||
buttonText: stringGetter({ key: STRING_KEYS.CONTINUE }),
|
||||
link: keplrDashboard,
|
||||
title: stringGetter({ key: STRING_KEYS.LEAVING_WEBSITE_STAKING_GOVERNANCE }),
|
||||
slotContent: stringGetter({
|
||||
key: STRING_KEYS.STAKE_WITH_KEPLR_AND_LEAVING_DESCRIPTION,
|
||||
params: {
|
||||
CTA: stringGetter({ key: STRING_KEYS.CONTINUE }),
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
@@ -25,7 +25,7 @@ import { Switch } from '@/components/Switch';
|
||||
import { WithReceipt } from '@/components/WithReceipt';
|
||||
import { WithTooltip } from '@/components/WithTooltip';
|
||||
|
||||
import { getSelectedNetwork, getSelectedDydxChainId } from '@/state/appSelectors';
|
||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||
|
||||
import { track } from '@/lib/analytics';
|
||||
import { isTruthy } from '@/lib/isTruthy';
|
||||
@@ -44,6 +44,7 @@ export const GenerateKeys = ({
|
||||
onKeysDerived = () => {},
|
||||
}: ElementProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
const { isMobile } = useBreakpoints();
|
||||
|
||||
const [shouldRememberMe, setShouldRememberMe] = useState(false);
|
||||
|
||||
@@ -65,30 +66,17 @@ export const GenerateKeys = ({
|
||||
|
||||
try {
|
||||
await matchNetwork?.();
|
||||
return true;
|
||||
} catch (error) {
|
||||
const { message, walletErrorType, isErrorExpected } = parseWalletError({
|
||||
error,
|
||||
stringGetter,
|
||||
});
|
||||
|
||||
if (!isErrorExpected) {
|
||||
log('GenerateKeys/switchNetwork', error, { walletErrorType });
|
||||
}
|
||||
const { message, walletErrorType } = parseWalletError({ error, stringGetter });
|
||||
|
||||
if (message) {
|
||||
log('GenerateKeys/switchNetwork', error, { walletErrorType });
|
||||
setError(message);
|
||||
throw error;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const switchNetworkAndDeriveKeys = async () => {
|
||||
const networkSwitched = await switchNetwork();
|
||||
if (networkSwitched) await deriveKeys();
|
||||
};
|
||||
|
||||
// 2. Derive keys from EVM account
|
||||
const { getWalletFromEvmSignature } = useDydxClient();
|
||||
const { getSubaccounts } = useAccounts();
|
||||
@@ -98,8 +86,7 @@ export const GenerateKeys = ({
|
||||
EvmDerivedAccountStatus.Derived,
|
||||
].includes(status);
|
||||
|
||||
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
|
||||
const signTypedData = getSignTypedData(selectedDydxChainId);
|
||||
const signTypedData = getSignTypedData(selectedNetwork);
|
||||
const { signTypedDataAsync } = useSignTypedData({
|
||||
...signTypedData,
|
||||
domain: {
|
||||
@@ -167,16 +154,11 @@ export const GenerateKeys = ({
|
||||
setStatus(EvmDerivedAccountStatus.Derived);
|
||||
} catch (error) {
|
||||
setStatus(EvmDerivedAccountStatus.NotDerived);
|
||||
const { message, walletErrorType, isErrorExpected } = parseWalletError({
|
||||
error,
|
||||
stringGetter,
|
||||
});
|
||||
const { message, walletErrorType } = parseWalletError({ error, stringGetter });
|
||||
|
||||
if (message) {
|
||||
setError(message);
|
||||
if (!isErrorExpected) {
|
||||
log('GenerateKeys/deriveKeys', error, { walletErrorType });
|
||||
}
|
||||
log('GenerateKeys/deriveKeys', error, { walletErrorType });
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -249,7 +231,7 @@ export const GenerateKeys = ({
|
||||
{!isMatchingNetwork ? (
|
||||
<Button
|
||||
action={ButtonAction.Primary}
|
||||
onClick={() => switchNetworkAndDeriveKeys().then(onKeysDerived)}
|
||||
onClick={() => switchNetwork().then(deriveKeys).then(onKeysDerived)}
|
||||
state={{ isLoading: isSwitchingNetwork }}
|
||||
>
|
||||
{stringGetter({ key: STRING_KEYS.SWITCH_NETWORK })}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { TransferInputField, TransferInputTokenResource, TransferType } from '@/
|
||||
import { AlertType } from '@/constants/alerts';
|
||||
import { ButtonSize } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { isMainnet } from '@/constants/networks';
|
||||
import { ENVIRONMENT_CONFIG_MAP, isMainnet } from '@/constants/networks';
|
||||
import { MAX_CCTP_TRANSFER_AMOUNT, MAX_PRICE_IMPACT, NumberSign } from '@/constants/numbers';
|
||||
import type { EvmAddress } from '@/constants/wallets';
|
||||
|
||||
@@ -32,7 +32,6 @@ 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';
|
||||
@@ -57,7 +56,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 selectedDydxChainId = useSelector(getSelectedDydxChainId);
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
|
||||
const { evmAddress, signerWagmi, publicClientWagmi, nobleAddress } = useAccounts();
|
||||
|
||||
@@ -263,7 +262,9 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
if (txHash) {
|
||||
addTransferNotification({
|
||||
txHash: txHash,
|
||||
toChainId: !isCctp ? selectedDydxChainId : getNobleChainId(),
|
||||
toChainId: !isCctp
|
||||
? ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId
|
||||
: getNobleChainId(),
|
||||
fromChainId: chainIdStr || undefined,
|
||||
toAmount: summary?.usdcSize || undefined,
|
||||
triggeredAt: Date.now(),
|
||||
|
||||
@@ -9,14 +9,9 @@ import { TransferInputField, TransferInputTokenResource, TransferType } from '@/
|
||||
import { AlertType } from '@/constants/alerts';
|
||||
import { ButtonSize } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { isMainnet } from '@/constants/networks';
|
||||
import { ENVIRONMENT_CONFIG_MAP, isMainnet } from '@/constants/networks';
|
||||
import { TransferNotificationTypes } from '@/constants/notifications';
|
||||
import {
|
||||
MAX_CCTP_TRANSFER_AMOUNT,
|
||||
MAX_PRICE_IMPACT,
|
||||
MIN_CCTP_TRANSFER_AMOUNT,
|
||||
NumberSign,
|
||||
} from '@/constants/numbers';
|
||||
import { MAX_CCTP_TRANSFER_AMOUNT, MAX_PRICE_IMPACT, NumberSign } from '@/constants/numbers';
|
||||
|
||||
import {
|
||||
useAccounts,
|
||||
@@ -45,7 +40,6 @@ 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';
|
||||
|
||||
@@ -60,7 +54,7 @@ export const WithdrawForm = () => {
|
||||
const stringGetter = useStringGetter();
|
||||
const [error, setError] = useState<string>();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
|
||||
const { sendSquidWithdraw } = useSubaccount();
|
||||
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
|
||||
@@ -183,7 +177,9 @@ export const WithdrawForm = () => {
|
||||
addTransferNotification({
|
||||
txHash: txHash,
|
||||
type: TransferNotificationTypes.Withdrawal,
|
||||
fromChainId: !isCctp ? selectedDydxChainId : getNobleChainId(),
|
||||
fromChainId: !isCctp
|
||||
? ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId
|
||||
: getNobleChainId(),
|
||||
toChainId: chainIdStr || undefined,
|
||||
toAmount: debouncedAmountBN.toNumber(),
|
||||
triggeredAt: Date.now(),
|
||||
@@ -333,12 +329,6 @@ 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)) {
|
||||
|
||||
@@ -14,7 +14,6 @@ import { ButtonAction, ButtonShape, ButtonSize, ButtonType } from '@/constants/b
|
||||
import { TOKEN_DECIMALS } from '@/constants/numbers';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { MobilePlaceOrderSteps } from '@/constants/trade';
|
||||
|
||||
import { useBreakpoints, useIsFirstRender, useStringGetter, useSubaccount } from '@/hooks';
|
||||
import { useOnLastOrderIndexed } from '@/hooks/useOnLastOrderIndexed';
|
||||
|
||||
@@ -36,6 +35,7 @@ import { Orderbook, orderbookMixins, type OrderbookScrollBehavior } from '@/view
|
||||
import { PositionPreview } from '@/views/forms/TradeForm/PositionPreview';
|
||||
|
||||
import { getCurrentMarketPositionData } from '@/state/accountSelectors';
|
||||
|
||||
import { getCurrentMarketAssetData } from '@/state/assetsSelectors';
|
||||
import { getClosePositionInputErrors, getInputClosePositionData } from '@/state/inputsSelectors';
|
||||
import { getCurrentMarketConfig, getCurrentMarketId } from '@/state/perpetualsSelectors';
|
||||
@@ -291,14 +291,9 @@ export const ClosePositionForm = ({
|
||||
isLoading={isClosingPosition}
|
||||
hasValidationErrors={hasInputErrors}
|
||||
actionStringKey={inputAlert?.actionStringKey}
|
||||
validationErrorString={alertContent}
|
||||
summary={summary ?? undefined}
|
||||
currentStep={currentStep}
|
||||
confirmButtonConfig={{
|
||||
stringKey: STRING_KEYS.CLOSE_ORDER,
|
||||
buttonTextStringKey: STRING_KEYS.CLOSE_POSITION,
|
||||
buttonAction: ButtonAction.Destroy,
|
||||
}}
|
||||
isClosePosition
|
||||
/>
|
||||
</Styled.Footer>
|
||||
</Styled.ClosePositionForm>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { type FormEvent, useState, Ref, useCallback } from 'react';
|
||||
import { type FormEvent, useState, Ref, useCallback, useEffect } from 'react';
|
||||
import styled, { AnyStyledComponent, css } from 'styled-components';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import type { NumberFormatValues, SourceInfo } from 'react-number-format';
|
||||
|
||||
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||
|
||||
import { AlertType } from '@/constants/alerts';
|
||||
|
||||
import {
|
||||
@@ -18,12 +16,7 @@ import {
|
||||
import { ButtonAction, ButtonShape, ButtonSize, ButtonType } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { USD_DECIMALS } from '@/constants/numbers';
|
||||
import {
|
||||
InputErrorData,
|
||||
TradeBoxKeys,
|
||||
MobilePlaceOrderSteps,
|
||||
ORDER_TYPE_STRINGS,
|
||||
} from '@/constants/trade';
|
||||
import { InputErrorData, TradeBoxKeys, MobilePlaceOrderSteps } from '@/constants/trade';
|
||||
|
||||
import { breakpoints } from '@/styles';
|
||||
import { useStringGetter, useSubaccount } from '@/hooks';
|
||||
@@ -44,16 +37,11 @@ import { WithTooltip } from '@/components/WithTooltip';
|
||||
import { Orderbook } from '@/views/tables/Orderbook';
|
||||
|
||||
import { setTradeFormInputs } from '@/state/inputs';
|
||||
import {
|
||||
getCurrentInput,
|
||||
getInputTradeData,
|
||||
getTradeFormInputs,
|
||||
useTradeFormData,
|
||||
} from '@/state/inputsSelectors';
|
||||
import { getCurrentInput, getTradeFormInputs, useTradeFormData } from '@/state/inputsSelectors';
|
||||
import { getCurrentMarketConfig } from '@/state/perpetualsSelectors';
|
||||
|
||||
import abacusStateManager from '@/lib/abacus';
|
||||
import { getSelectedOrderSide, getSelectedTradeType, getTradeInputAlert } from '@/lib/tradeData';
|
||||
import { getTradeInputAlert } from '@/lib/tradeData';
|
||||
|
||||
import { AdvancedTradeOptions } from './TradeForm/AdvancedTradeOptions';
|
||||
import { TradeSizeInputs } from './TradeForm/TradeSizeInputs';
|
||||
@@ -120,21 +108,8 @@ export const TradeForm = ({
|
||||
const tradeFormInputValues = useSelector(getTradeFormInputs, shallowEqual);
|
||||
const { limitPriceInput, triggerPriceInput, trailingPercentInput } = tradeFormInputValues;
|
||||
|
||||
const currentTradeData = useSelector(getInputTradeData, shallowEqual);
|
||||
|
||||
const { side, type } = currentTradeData || {};
|
||||
|
||||
const selectedTradeType = getSelectedTradeType(type);
|
||||
const selectedOrderSide = getSelectedOrderSide(side);
|
||||
|
||||
const needsAdvancedOptions =
|
||||
needsGoodUntil ||
|
||||
timeInForceOptions ||
|
||||
executionOptions ||
|
||||
needsPostOnly ||
|
||||
postOnlyTooltip ||
|
||||
needsReduceOnly ||
|
||||
reduceOnlyTooltip;
|
||||
needsGoodUntil || timeInForceOptions || executionOptions || (needsPostOnly || postOnlyTooltip) || (needsReduceOnly || reduceOnlyTooltip);
|
||||
|
||||
const tradeFormInputs: TradeBoxInputConfig[] = [];
|
||||
|
||||
@@ -164,11 +139,6 @@ export const TradeForm = ({
|
||||
alertType = inputAlert?.type;
|
||||
}
|
||||
|
||||
const orderSideAction = {
|
||||
[OrderSide.BUY]: ButtonAction.Create,
|
||||
[OrderSide.SELL]: ButtonAction.Destroy,
|
||||
}[selectedOrderSide];
|
||||
|
||||
const onSubmit = async (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -349,15 +319,9 @@ export const TradeForm = ({
|
||||
isLoading={isPlacingOrder}
|
||||
hasValidationErrors={hasInputErrors}
|
||||
actionStringKey={inputAlert?.actionStringKey}
|
||||
validationErrorString={alertContent}
|
||||
summary={summary ?? undefined}
|
||||
currentStep={currentStep}
|
||||
showDeposit={inputAlert?.errorAction === TradeInputErrorAction.DEPOSIT}
|
||||
confirmButtonConfig={{
|
||||
stringKey: ORDER_TYPE_STRINGS[selectedTradeType].orderTypeKey,
|
||||
buttonTextStringKey: STRING_KEYS.PLACE_ORDER,
|
||||
buttonAction: orderSideAction,
|
||||
}}
|
||||
/>
|
||||
</Styled.Footer>
|
||||
</Styled.TradeForm>
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import styled, { type AnyStyledComponent, css } from 'styled-components';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||
|
||||
import type { TradeInputSummary } from '@/constants/abacus';
|
||||
import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { MobilePlaceOrderSteps } from '@/constants/trade';
|
||||
import { ORDER_TYPE_STRINGS, MobilePlaceOrderSteps } from '@/constants/trade';
|
||||
|
||||
import { useStringGetter, useTokenConfigs } from '@/hooks';
|
||||
|
||||
import { AssetIcon } from '@/components/AssetIcon';
|
||||
import { Button } from '@/components/Button';
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
import { Output, OutputType, ShowSign } from '@/components/Output';
|
||||
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
|
||||
import { WithTooltip } from '@/components/WithTooltip';
|
||||
@@ -21,34 +20,30 @@ import { OnboardingTriggerButton } from '@/views/dialogs/OnboardingTriggerButton
|
||||
import { calculateCanAccountTrade } from '@/state/accountCalculators';
|
||||
import { getSubaccountId } from '@/state/accountSelectors';
|
||||
import { openDialog } from '@/state/dialogs';
|
||||
import { getCurrentInput } from '@/state/inputsSelectors';
|
||||
import { getCurrentInput, getInputTradeData } from '@/state/inputsSelectors';
|
||||
|
||||
type ConfirmButtonConfig = {
|
||||
stringKey: string;
|
||||
buttonTextStringKey: string;
|
||||
buttonAction: ButtonAction;
|
||||
};
|
||||
import { getSelectedOrderSide, getSelectedTradeType } from '@/lib/tradeData';
|
||||
|
||||
type ElementProps = {
|
||||
isLoading: boolean;
|
||||
isClosePosition?: boolean;
|
||||
actionStringKey?: string;
|
||||
summary?: TradeInputSummary;
|
||||
hasValidationErrors?: boolean;
|
||||
validationErrorString?: string;
|
||||
currentStep?: MobilePlaceOrderSteps;
|
||||
showDeposit?: boolean;
|
||||
confirmButtonConfig: ConfirmButtonConfig;
|
||||
showConnectWallet?: boolean;
|
||||
};
|
||||
|
||||
export const PlaceOrderButtonAndReceipt = ({
|
||||
isLoading,
|
||||
isClosePosition,
|
||||
actionStringKey,
|
||||
summary,
|
||||
hasValidationErrors,
|
||||
validationErrorString,
|
||||
currentStep,
|
||||
showDeposit,
|
||||
confirmButtonConfig,
|
||||
showConnectWallet,
|
||||
}: ElementProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
const dispatch = useDispatch();
|
||||
@@ -57,12 +52,18 @@ export const PlaceOrderButtonAndReceipt = ({
|
||||
const canAccountTrade = useSelector(calculateCanAccountTrade);
|
||||
const subaccountNumber = useSelector(getSubaccountId);
|
||||
const currentInput = useSelector(getCurrentInput);
|
||||
const currentTradeData = useSelector(getInputTradeData, shallowEqual);
|
||||
|
||||
const hasMissingData = subaccountNumber === undefined;
|
||||
|
||||
const shouldEnableTrade =
|
||||
canAccountTrade && !hasMissingData && !hasValidationErrors && currentInput !== 'transfer';
|
||||
|
||||
const { side, type } = currentTradeData || {};
|
||||
|
||||
const selectedTradeType = getSelectedTradeType(type);
|
||||
const selectedOrderSide = getSelectedOrderSide(side);
|
||||
|
||||
const { fee, price: expectedPrice, total, reward } = summary || {};
|
||||
|
||||
const items = [
|
||||
@@ -109,6 +110,11 @@ export const PlaceOrderButtonAndReceipt = ({
|
||||
},
|
||||
];
|
||||
|
||||
const orderSideAction = {
|
||||
[OrderSide.BUY]: ButtonAction.Create,
|
||||
[OrderSide.SELL]: ButtonAction.Destroy,
|
||||
}[selectedOrderSide];
|
||||
|
||||
const buttonStatesPerStep = {
|
||||
[MobilePlaceOrderSteps.EditOrder]: {
|
||||
buttonTextStringKey: shouldEnableTrade
|
||||
@@ -122,7 +128,7 @@ export const PlaceOrderButtonAndReceipt = ({
|
||||
|
||||
[MobilePlaceOrderSteps.PreviewOrder]: {
|
||||
buttonTextStringKey: STRING_KEYS.CONFIRM_ORDER,
|
||||
buttonAction: confirmButtonConfig.buttonAction,
|
||||
buttonAction: isClosePosition ? ButtonAction.Destroy : orderSideAction,
|
||||
buttonState: { isLoading },
|
||||
},
|
||||
[MobilePlaceOrderSteps.PlacingOrder]: {
|
||||
@@ -139,13 +145,15 @@ export const PlaceOrderButtonAndReceipt = ({
|
||||
|
||||
const buttonAction = currentStep
|
||||
? buttonStatesPerStep[currentStep].buttonAction
|
||||
: confirmButtonConfig.buttonAction;
|
||||
: isClosePosition
|
||||
? ButtonAction.Destroy
|
||||
: orderSideAction;
|
||||
|
||||
let buttonTextStringKey = STRING_KEYS.UNAVAILABLE;
|
||||
if (currentStep) {
|
||||
buttonTextStringKey = buttonStatesPerStep[currentStep].buttonTextStringKey;
|
||||
} else if (shouldEnableTrade) {
|
||||
buttonTextStringKey = confirmButtonConfig.buttonTextStringKey;
|
||||
buttonTextStringKey = isClosePosition ? STRING_KEYS.CLOSE_POSITION : STRING_KEYS.PLACE_ORDER;
|
||||
} else if (actionStringKey) {
|
||||
buttonTextStringKey = actionStringKey;
|
||||
}
|
||||
@@ -157,56 +165,31 @@ export const PlaceOrderButtonAndReceipt = ({
|
||||
isLoading: isLoading || hasMissingData,
|
||||
};
|
||||
|
||||
const depositButton = (
|
||||
<Button
|
||||
action={ButtonAction.Primary}
|
||||
onClick={() => dispatch(openDialog({ type: DialogTypes.Deposit }))}
|
||||
>
|
||||
{stringGetter({ key: STRING_KEYS.DEPOSIT_FUNDS })}
|
||||
</Button>
|
||||
);
|
||||
|
||||
const submitButton = (
|
||||
<Styled.Button
|
||||
state={buttonState}
|
||||
type={ButtonType.Submit}
|
||||
action={buttonAction}
|
||||
slotLeft={
|
||||
hasValidationErrors ? <Styled.WarningIcon iconName={IconName.Warning} /> : undefined
|
||||
}
|
||||
>
|
||||
{stringGetter({
|
||||
key: buttonTextStringKey,
|
||||
params: {
|
||||
ORDER: stringGetter({
|
||||
key: confirmButtonConfig.stringKey,
|
||||
}),
|
||||
},
|
||||
})}
|
||||
</Styled.Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<WithDetailsReceipt detailItems={items}>
|
||||
{!canAccountTrade ? (
|
||||
{!canAccountTrade || showConnectWallet ? (
|
||||
<OnboardingTriggerButton size={ButtonSize.Base} />
|
||||
) : showDeposit ? (
|
||||
depositButton
|
||||
<Button
|
||||
action={ButtonAction.Primary}
|
||||
onClick={() => dispatch(openDialog({ type: DialogTypes.Deposit }))}
|
||||
>
|
||||
{stringGetter({ key: STRING_KEYS.DEPOSIT_FUNDS })}
|
||||
</Button>
|
||||
) : (
|
||||
<WithTooltip tooltipString={hasValidationErrors ? validationErrorString : undefined}>
|
||||
{submitButton}
|
||||
</WithTooltip>
|
||||
<Button state={buttonState} type={ButtonType.Submit} action={buttonAction}>
|
||||
{stringGetter({
|
||||
key: buttonTextStringKey,
|
||||
params: {
|
||||
ORDER: stringGetter({
|
||||
key: isClosePosition
|
||||
? STRING_KEYS.CLOSE_ORDER
|
||||
: ORDER_TYPE_STRINGS[selectedTradeType].orderTypeKey,
|
||||
}),
|
||||
},
|
||||
})}
|
||||
</Button>
|
||||
)}
|
||||
</WithDetailsReceipt>
|
||||
);
|
||||
};
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.Button = styled(Button)`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
Styled.WarningIcon = styled(Icon)`
|
||||
color: var(--color-warning);
|
||||
`;
|
||||
|
||||
@@ -9,6 +9,7 @@ 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';
|
||||
|
||||
@@ -17,6 +18,7 @@ import {
|
||||
useAccounts,
|
||||
useDydxClient,
|
||||
useRestrictions,
|
||||
useSelectedNetwork,
|
||||
useStringGetter,
|
||||
useSubaccount,
|
||||
useTokenConfigs,
|
||||
@@ -39,7 +41,6 @@ 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';
|
||||
@@ -62,7 +63,7 @@ export const TransferForm = ({
|
||||
const { dydxAddress } = useAccounts();
|
||||
const { transfer } = useSubaccount();
|
||||
const { nativeTokenBalance, usdcBalance } = useAccountBalance();
|
||||
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
const { tokensConfigs, usdcLabel, chainTokenLabel } = useTokenConfigs();
|
||||
|
||||
const {
|
||||
@@ -238,7 +239,7 @@ export const TransferForm = ({
|
||||
|
||||
const networkOptions = [
|
||||
{
|
||||
chainId: selectedDydxChainId,
|
||||
chainId: ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId,
|
||||
label: (
|
||||
<Styled.InlineRow>
|
||||
<AssetIcon symbol="DYDX" /> {stringGetter({ key: STRING_KEYS.DYDX_CHAIN })}
|
||||
@@ -321,7 +322,7 @@ export const TransferForm = ({
|
||||
/>
|
||||
<Styled.NetworkSelectMenu
|
||||
label={stringGetter({ key: STRING_KEYS.NETWORK })}
|
||||
value={selectedDydxChainId}
|
||||
value={ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId}
|
||||
slotTriggerAfter={null}
|
||||
>
|
||||
{networkOptions.map(({ chainId, label }) => (
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import styled, { css, type AnyStyledComponent } from 'styled-components';
|
||||
import { StatusResponse } from '@0xsquid/sdk';
|
||||
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { TransferNotificationTypes } from '@/constants/notifications';
|
||||
|
||||
import { useStringGetter, useURLConfigs } from '@/hooks';
|
||||
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { useStringGetter, useSelectedNetwork, useURLConfigs } from '@/hooks';
|
||||
|
||||
import { Link } from '@/components/Link';
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
import { LoadingDots } from '@/components/Loading/LoadingDots';
|
||||
import { LoadingSpinner } from '@/components/Loading/LoadingSpinner';
|
||||
|
||||
import { getSelectedDydxChainId } from '@/state/appSelectors';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||
import { TransferNotificationTypes } from '@/constants/notifications';
|
||||
|
||||
type ElementProps = {
|
||||
status?: StatusResponse;
|
||||
@@ -35,8 +32,9 @@ enum TransferStatusStep {
|
||||
|
||||
export const TransferStatusSteps = ({ className, status, type }: ElementProps & StyleProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
const { mintscan: mintscanTxUrl } = useURLConfigs();
|
||||
const dydxChainId = ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId;
|
||||
|
||||
const { currentStep, steps } = useMemo(() => {
|
||||
const routeStatus = status?.routeStatus;
|
||||
@@ -57,7 +55,7 @@ export const TransferStatusSteps = ({ className, status, type }: ElementProps &
|
||||
link:
|
||||
type === TransferNotificationTypes.Deposit
|
||||
? status?.fromChain?.transactionUrl
|
||||
: routeStatus?.[0]?.chainId === selectedDydxChainId && routeStatus[0].txHash
|
||||
: routeStatus?.[0]?.chainId === dydxChainId && routeStatus[0].txHash
|
||||
? `${mintscanTxUrl?.replace('{tx_hash}', routeStatus[0].txHash.replace('0x', ''))}`
|
||||
: undefined,
|
||||
},
|
||||
@@ -83,7 +81,7 @@ export const TransferStatusSteps = ({ className, status, type }: ElementProps &
|
||||
link:
|
||||
type === TransferNotificationTypes.Withdrawal
|
||||
? status?.toChain?.transactionUrl
|
||||
: currentStatus?.chainId === selectedDydxChainId && currentStatus?.txHash
|
||||
: currentStatus?.chainId === dydxChainId && currentStatus?.txHash
|
||||
? `${mintscanTxUrl?.replace('{tx_hash}', currentStatus.txHash.replace('0x', ''))}`
|
||||
: undefined,
|
||||
},
|
||||
|
||||