Compare commits

..
Author SHA1 Message Date
aforaleka ed7db77a34 fix network as chain id 2024-02-16 23:31:47 -05:00
aforaleka 854f12fcf1 fix parsing error and surface tx broadcast error 2024-02-16 17:33:50 -05:00
yujin512 b115bf33a0 Update markets.json (#311)
update ORDI asset name
2024-02-16 10:54:13 -08:00
aleka b544b8202b fetch chaos labs latest season (#309)
* fetch chaos labs latest season

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

* Update otherMarketParameters.json

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

* Update otherMarketParameters.json

update numOracles for markets with robust DEX oracles

* update asset name to match cmc

* Update otherMarketParameters.json

* add icons for other markets

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

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

* use new config path

* bump abacus to 1.4.5

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

* Move to v1/env.json

* dydx-testnet-4
2024-02-14 13:37:51 -05:00
moo-onthelawn b638ec1ad6 CT-463 Add Position (entry) line to TradingView (#292)
* wip

* fix deleted line issue

* compress tgz changes

* fix dependency hook

* simplify

* typo

* add trailing percent

* fix bug

* fix order

* merge order types

* wip

* rename variable

* review comments

* remove file

* rebase on new changes

* remove log

* clean up chart line type

* clean up typings a bit more

* fix var rename

* review comments

* clean up logic

* typing
2024-02-14 09:41:04 -05:00
Jared Vu f7a1cfc67e Updated Keplr language (#300) 2024-02-13 17:07:22 -08:00
aleka d66a776ad2 show trading rewards in testnet (#299) 2024-02-13 16:02:10 -05:00
moo-onthelawn e3e00f4f1e CT-145 Add warning icon + tooltip to trade order button CTA (#297)
* update

* rename to config
2024-02-13 16:00:46 -05:00
aleka 9ea578b8e4 avoid logging expected switch chain error (#291)
* avoid logging expected switch chain error

* skip logging more expected errors

* update switch chain error requirements check
2024-02-13 13:51:47 -05:00
moo-onthelawn f47fda45bf CT-428 Update browser tab title to be mid market price (#294)
* calculation

* make new selectors
2024-02-13 13:49:24 -05:00
moo-onthelawn a7addda930 CT-425 + TRCL-2154 Add orderlines to TradingView + fix colors (#287)
* wip

* fix deleted line issue

* compress tgz changes

* fix dependency hook

* simplify

* typo

* add trailing percent

* fix bug

* fix order

* merge order types
2024-02-12 10:31:15 -05:00
yujin512andjaredvu b839cf695e upload new jsons and update file names (#295)
* upload new jsons and update file names

* add disclaimer and format json

* change filename

* remove (ENS) from assetName

---------

Co-authored-by: jaredvu <jaredvu@gmail.com>
2024-02-09 21:03:00 -08:00
yujin512andJared Vu c9b8f1d59b Yujin/update assets (#293)
* add links for DYM, BNB, ZETA

* add icons

* update asseticon.tsc

* readd JUP

* bump v4-localization

* Added TODO

* Update public/configs/markets.json

Co-authored-by: Jared Vu <jaredvu@gmail.com>

* address comments

* higher resolution icons

---------

Co-authored-by: jaredvu <jaredvu@gmail.com>
2024-02-09 14:32:52 -08:00
moo-onthelawn 91c04956d6 adjust calculation (#290) 2024-02-08 16:12:42 -08:00
89 changed files with 2746 additions and 4515 deletions
+1
View File
@@ -1 +1,2 @@
node_modules/
public/
+2 -2
View File
@@ -40,9 +40,9 @@
"@cosmjs/proto-signing": "^0.32.1",
"@cosmjs/stargate": "^0.32.1",
"@cosmjs/tendermint-rpc": "^0.32.1",
"@dydxprotocol/v4-abacus": "^1.4.2",
"@dydxprotocol/v4-abacus": "^1.4.5",
"@dydxprotocol/v4-client-js": "^1.0.20",
"@dydxprotocol/v4-localization": "^1.1.26",
"@dydxprotocol/v4-localization": "^1.1.30",
"@ethersproject/providers": "^5.7.2",
"@js-joda/core": "^5.5.3",
"@radix-ui/react-accordion": "^1.1.2",
+15 -19
View File
@@ -1,9 +1,5 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
overrides:
follow-redirects: 1.15.3
@@ -30,14 +26,14 @@ dependencies:
specifier: ^0.32.1
version: 0.32.2
'@dydxprotocol/v4-abacus':
specifier: ^1.4.2
version: 1.4.2
specifier: ^1.4.5
version: 1.4.5
'@dydxprotocol/v4-client-js':
specifier: ^1.0.20
version: 1.0.20
'@dydxprotocol/v4-localization':
specifier: ^1.1.26
version: 1.1.26
specifier: ^1.1.30
version: 1.1.30
'@ethersproject/providers':
specifier: ^5.7.2
version: 5.7.2
@@ -1290,8 +1286,8 @@ packages:
resolution: {integrity: sha512-Gg5t+eR7vPJMAmhkFt6CZrzPd0EKpAslWwk5rFVYZpJsM8JG5KT9XQ99hgNM3Ov6ScNoIWbXkpX27F6A9cXR4Q==}
dev: false
/@dydxprotocol/v4-abacus@1.4.2:
resolution: {integrity: sha512-+hugk0RulMwMthR2xCMYXohcC3sEYqVW/lmiq0RUuHZ9yrjmgy48xl0aZUmXGUYXyoiHXPS4AULhRKHQ4OOLwg==}
/@dydxprotocol/v4-abacus@1.4.5:
resolution: {integrity: sha512-LhJmpIaUkHCsSiHx+jdk+59euvGp2E+gGFelpfmOYpH1+enZgEXDQvWsgHSFEQxYP3mRiGG4uo+ZYNGdvffg7g==}
dev: false
/@dydxprotocol/v4-client-js@1.0.20:
@@ -1323,8 +1319,8 @@ packages:
- utf-8-validate
dev: false
/@dydxprotocol/v4-localization@1.1.26:
resolution: {integrity: sha512-u+J1J5Up8McwZOcDaG9GrH/A8p4vD2NU2CT2hPdYyKgEd28XeAYvv7bNAQRKdiBaqTePbbF5uB6TMAQnEGnb1A==}
/@dydxprotocol/v4-localization@1.1.30:
resolution: {integrity: sha512-TZfWWRSOxcjLHs972wlJVVHkE7+DVqAUnGZSs24HYHsPtUkPhZiNXMOA2Vk9YddQxumhM79xIRH0cmJSe5DDUg==}
dev: false
/@dydxprotocol/v4-proto@4.0.0-dev.0:
@@ -12888,10 +12884,6 @@ packages:
engines: {node: '>=10.5.0'}
dev: true
/node-fetch-native@1.6.1:
resolution: {integrity: sha512-bW9T/uJDPAJB2YNYEpWzE54U5O3MQidXsOyTfnbKYtTtFexRvGzb1waphBN4ZwP6EcIvYYEOwW0b72BpAqydTw==}
dev: false
/node-fetch-native@1.6.2:
resolution: {integrity: sha512-69mtXOFZ6hSkYiXAVB5SqaRvrbITC/NPyqv7yuu/qw0nmgPyYbIMYYNIDhNtwPrzk0ptrimrLz/hhjvm4w5Z+w==}
dev: false
@@ -13049,7 +13041,7 @@ packages:
resolution: {integrity: sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg==}
dependencies:
destr: 2.0.2
node-fetch-native: 1.6.1
node-fetch-native: 1.6.2
ufo: 1.3.2
dev: false
@@ -15029,7 +15021,7 @@ packages:
consola: 3.2.3
defu: 6.1.3
mime: 3.0.0
node-fetch-native: 1.6.1
node-fetch-native: 1.6.2
pathe: 1.1.1
dev: false
@@ -15175,7 +15167,7 @@ packages:
listhen: 1.5.5
lru-cache: 10.1.0
mri: 1.2.0
node-fetch-native: 1.6.1
node-fetch-native: 1.6.2
ofetch: 1.3.3
ufo: 1.3.2
transitivePeerDependencies:
@@ -16057,3 +16049,7 @@ packages:
/zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
dev: true
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
+1 -1
View File
@@ -1329,4 +1329,4 @@
}
}
}
}
}
+177 -1
View File
@@ -20,6 +20,13 @@
"whitepaperLink": "https://why.cardano.org/en/introduction/motivation/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/cardano/"
},
"AGIX-USD": {
"name": "SingularityNET",
"tags": ["AI"],
"websiteLink": "https://public.singularitynet.io/whitepaper.pdf",
"whitepaperLink": "https://public.singularitynet.io/whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/singularitynet/"
},
"ALGO-USD": {
"name": "Algorand",
"tags": ["Layer 1"],
@@ -78,11 +85,26 @@
},
"BLUR-USD": {
"name": "Blur",
"tags": [],
"tags": ["NFT"],
"websiteLink": "https://blur.io/",
"whitepaperLink": "https://docs.blur.foundation/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/blur-token/"
},
"BNB-USD":{
"name": "BNB",
"tags": ["Layer 1"],
"websiteLink": "https://www.bnbchain.org/en",
"whitepaperLink": "https://www.exodus.com/assets/docs/binance-coin-whitepaper.pdf",
"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": [],
@@ -125,6 +147,13 @@
"whitepaperLink": "https://polkadot.network/PolkaDotPaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/polkadot-new/"
},
"DYM-USD": {
"name": "Dymension",
"tags": [],
"websiteLink": "https://dymension.xyz/",
"whitepaperLink": "https://docs.dymension.xyz/dymension-litepaper/dymension-litepaper-index",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/dymension/"
},
"ENJ-USD": {
"name": "Enjin",
"tags": [],
@@ -132,6 +161,13 @@
"whitepaperLink": "https://cdn.enjin.io/downloads/whitepapers/enjin-coin/en.pdf/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/enjin-coin/"
},
"ENS-USD": {
"name": "Ethereum Name Service",
"tags": [],
"websiteLink": "https://coinmarketcap.com/currencies/ethereum-name-service/",
"whitepaperLink": "https://docs.ens.domains/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/ethereum-name-service/"
},
"EOS-USD": {
"name": "EOS",
"tags": ["Layer 1"],
@@ -155,6 +191,13 @@
"displayStepSize": "0.001",
"displayTickSize": "0.1"
},
"FET-USD": {
"name": "Fetch.ai",
"tags": ["AI"],
"websiteLink": "https://fetch.ai/",
"whitepaperLink": "https://www.dropbox.com/s/gxptsecwdl3jjtn/David%20Minarsch%20-%202021-04-26%2010.34.17%20-%20paper_21_finalversion.pdf?e=1&dl=0",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/fetch/"
},
"FIL-USD": {
"name": "Filecoin",
"tags": ["Layer 1"],
@@ -162,6 +205,34 @@
"whitepaperLink": "https://filecoin.io/filecoin.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/filecoin/"
},
"FTM-USD": {
"name": "Fantom",
"tags": [],
"websiteLink": "https://fantom.foundation/",
"whitepaperLink": "https://fantom.foundation/_next/static/media/wp_fantom_v1.6.39329cdc5d0ee59684cbc6f228516383.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/fantom/"
},
"GALA-USD": {
"name": "Gala",
"tags": ["Gaming", "Layer 1"],
"websiteLink": "https://gala.com/",
"whitepaperLink": "https://galahackathon.com/v1.0.0/pdf/sdk-documentation.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/gala/"
},
"GMT-USD": {
"name": "GMT",
"tags": ["Gaming"],
"websiteLink": "https://stepn.com/",
"whitepaperLink/": "https://whitepaper.stepn.com/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/green-metaverse-token/"
},
"GRT-USD": {
"name": "The Graph",
"tags": [],
"websiteLink": "https://thegraph.com/",
"whitepaperLink/": "https://github.com/graphprotocol/research/blob/master/papers/whitepaper/the-graph-whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/the-graph/"
},
"HNT-USD": {
"name": "Helium",
"tags": ["Layer 1"],
@@ -169,6 +240,13 @@
"whitepaperLink": "http://whitepaper.helium.com",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/helium/"
},
"HBAR-USD": {
"name": "Hedera",
"tags": [],
"websiteLink": "https://hedera.com/",
"whitepaperLink/": "https://files.hedera.com/hh_whitepaper_v2.2-20230918.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/hedera/"
},
"ICP-USD": {
"name": "Internet Computer",
"tags": ["Layer 1"],
@@ -176,6 +254,27 @@
"whitepaperLink": "https://dfinity.org/whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/internet-computer/"
},
"IMX-USD": {
"name": "Immutable X",
"tags": ["Gaming", "Layer 2", "NFT"],
"websiteLink": "https://www.immutable.com/",
"whitepaperLink": "https://assets.website-files.com/646557ee455c3e16e4a9bcb3/6499367de527dd82ab7475a3_Immutable%20Whitepaper%20Update%202023%20(3).pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/immutable-x/"
},
"INJ-USD": {
"name": "Injective",
"tags": ["Layer 1", "Defi"],
"websiteLink": "https://injective.com/",
"whitepaperLink": "https://docs.injective.network/intro/01_overview.html",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/injective/"
},
"JTO-USD": {
"name": "Jito",
"tags": ["Defi"],
"websiteLink": "https://www.jito.network/",
"whitepaperLink": "https://github.com/jito-foundation",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/jito/"
},
"JUP-USD": {
"name": "Jupiter",
"tags": ["Defi"],
@@ -183,6 +282,13 @@
"whitepaperLink": "https://station.jup.ag/blog/green-paper",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/jupiter-ag/"
},
"KAVA-USD": {
"name": "Kava",
"tags": ["Layer 1"],
"websiteLink": "https://www.kava.io/",
"whitepaperLink": "https://docsend.com/view/gwbwpc3",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/kava/"
},
"LDO-USD": {
"name": "Lido DAO",
"tags": ["Defi"],
@@ -204,6 +310,20 @@
"whitepaperLink": "https://litecoin.info/index.php/Main_Page",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/litecoin/"
},
"MANA-USD": {
"name": "Decentraland",
"tags": ["AR/VR"],
"websiteLink": "https://decentraland.org/",
"whitepaperLink": "https://decentraland.org/whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/decentraland/"
},
"MASK-USD": {
"name": "Mask Network",
"tags": [],
"websiteLink": "https://mask.io/",
"whitepaperLink": "https://masknetwork.medium.com/introducing-mask-network-maskbook-the-future-of-the-internet-5a973d874edd",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/mask-network/"
},
"MATIC-USD": {
"name": "Polygon",
"tags": ["Layer 2"],
@@ -211,6 +331,13 @@
"whitepaperLink": "https://polygon.technology/lightpaper-polygon.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/polygon/"
},
"MINA-USD": {
"name": "Mina",
"tags": ["Layer 1"],
"websiteLink": "https://minaprotocol.com/",
"whitepaperLink": "https://docs.minaprotocol.com/assets/economicsWhitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/mina/"
},
"MKR-USD": {
"name": "Maker",
"tags": ["Governance"],
@@ -225,6 +352,13 @@
"whitepaperLink": "https://near.org/papers/the-official-near-white-paper/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/near-protocol/"
},
"ORDI-USD": {
"name": "Ordinals",
"tags": ["NFT"],
"websiteLink": "https://ordinals.com/",
"whitepaperLink": "https://rodarmor.com/blog/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/ordi/"
},
"OP-USD": {
"name": "Optimism",
"tags": [],
@@ -238,6 +372,20 @@
"websiteLink": "https://www.pepe.vip/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/pepe/"
},
"PYTH-USD": {
"name": "Pyth Network",
"tags": [],
"websiteLink": "https://pyth.network/",
"whitepaperLink": "https://pyth.network/whitepaper_v2.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/pyth-network/"
},
"RNDR-USD": {
"name": "Render Token",
"tags": ["AI"],
"websiteLink": "https://rendernetwork.com/",
"whitepaperLink": "https://renderfoundation.com/whitepaper",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/render/"
},
"RUNE-USD": {
"name": "THORChain",
"tags": ["Layer 1"],
@@ -245,6 +393,13 @@
"whitepaperLink": "https://whitepaper.io/document/709/thorchain-whitepaper",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/thorchain/"
},
"SAND-USD": {
"name": "The Sandbox",
"tags": ["Gaming"],
"websiteLink": "https://www.sandbox.game/en/",
"whitepaperLink": "https://installers.sandbox.game/The_Sandbox_Whitepaper_2020.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/the-sandbox/"
},
"SEI-USD": {
"name": "Sei",
"tags": ["Layer 1", "Defi"],
@@ -273,6 +428,13 @@
"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"],
@@ -322,6 +484,13 @@
"whitepaperLink": "https://whitepaper.worldcoin.org/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/worldcoin-org/"
},
"WOO-USD": {
"name": "WOO Network",
"tags": ["Defi"],
"websiteLink": "https://woo.org/",
"whitepaperLink": "https://woo.org/Litepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/wootrade/"
},
"XLM-USD": {
"name": "Stellar",
"tags": ["Layer 1"],
@@ -364,6 +533,13 @@
"whitepaperLink": "https://z.cash/technology/",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/zcash/"
},
"ZETA-USD": {
"name": "ZetaChain",
"tags": ["Layer 1"],
"websiteLink": "https://www.zetachain.com/",
"whitepaperLink": "https://www.zetachain.com/whitepaper.pdf",
"coinMarketCapsLink": "https://coinmarketcap.com/currencies/zetachain/"
},
"ZRX-USD": {
"name": "0x",
"tags": ["Defi"],
+1
View File
@@ -0,0 +1 @@
This file identifies parameters for the optimal performance of various assets with the dYdX v4 open source software ("dYdX Chain"). For information on which assets are likely to be best compatible with dYdX Chain and how likely software compatibility and optimal parameters are assessed, please review the documentation [here](https://docs.dydx.trade/governance/proposing_a_new_market#example-proposal-json). Users considering using the permissionless markets function of the dYdX Chain are encouraged to consult qualified legal counsel to ensure compliance with the laws of their jurisdiction. The information herein does not constitute and should not be relied on as an endorsement or recommendation for any specific market, or investment, legal, or any other form of professional advice. Use of the v4 software is prohibited in the United States, Canada, and sanctioned jurisdictions as described in the [v4 Terms of Use](https://dydx.exchange/v4-terms).
@@ -0,0 +1,608 @@
{
"1INCH": [
{ "exchangeName": "Binance", "ticker": "1INCHUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "1INCH-USD" },
{ "exchangeName": "Gate", "ticker": "1INCH_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "1INCH-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "1INCH-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "1INCH_USDT", "adjustByMarket": "USDT-USD" }
],
"AAVE": [
{ "exchangeName": "Binance", "ticker": "AAVEUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "AAVE-USD" },
{ "exchangeName": "Huobi", "ticker": "aaveusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "AAVEUSD" },
{ "exchangeName": "Kucoin", "ticker": "AAVE-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "AAVE-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "AAVE_USDT", "adjustByMarket": "USDT-USD" }
],
"ADA": [
{ "exchangeName": "Binance", "ticker": "ADAUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bitstamp", "ticker": "ADA/USD" },
{ "exchangeName": "Bybit", "ticker": "ADAUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "ADA-USD" },
{ "exchangeName": "Huobi", "ticker": "adausdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "ADAUSD" },
{ "exchangeName": "Kucoin", "ticker": "ADA-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "ADA-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "ADA_USDT", "adjustByMarket": "USDT-USD" }
],
"AGIX": [
{ "exchangeName": "Binance", "ticker": "AGIXUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "AGIXUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Gate", "ticker": "AGIX_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "AGIX-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "AGIX-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "AGIX_USDT", "adjustByMarket": "USDT-USD" }
],
"ALGO": [
{ "exchangeName": "Binance", "ticker": "ALGOUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "ALGO-USD" },
{ "exchangeName": "Kraken", "ticker": "ALGOUSD" },
{ "exchangeName": "Kucoin", "ticker": "ALGO-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "ALGO-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "ALGO_USDT", "adjustByMarket": "USDT-USD" }
],
"APE": [
{ "exchangeName": "Binance", "ticker": "APEUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "APE-USD" },
{ "exchangeName": "Gate", "ticker": "APE_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "APEUSD" },
{ "exchangeName": "Kucoin", "ticker": "APE-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "APE-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "APE_USDT", "adjustByMarket": "USDT-USD" }
],
"APT": [
{ "exchangeName": "Binance", "ticker": "APTUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "APTUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "APT-USD" },
{ "exchangeName": "Gate", "ticker": "APT_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Huobi", "ticker": "aptusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "APTUSD" },
{ "exchangeName": "Kucoin", "ticker": "APT-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "APT-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "APT_USDT", "adjustByMarket": "USDT-USD" }
],
"ARB": [
{ "exchangeName": "Binance", "ticker": "ARBUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "ARBUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "ARB-USD" },
{ "exchangeName": "Huobi", "ticker": "arbusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "ARBUSD" },
{ "exchangeName": "Kucoin", "ticker": "ARB-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "ARB-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "ARB_USDT", "adjustByMarket": "USDT-USD" }
],
"ATOM": [
{ "exchangeName": "Binance", "ticker": "ATOMUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "ATOMUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "ATOM-USD" },
{ "exchangeName": "Gate", "ticker": "ATOM_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "ATOMUSD" },
{ "exchangeName": "Kucoin", "ticker": "ATOM-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "ATOM-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "ATOM_USDT", "adjustByMarket": "USDT-USD" }
],
"AVAX": [
{ "exchangeName": "Binance", "ticker": "AVAXUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bitstamp", "ticker": "AVAX/USD" },
{ "exchangeName": "Bybit", "ticker": "AVAXUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "AVAX-USD" },
{ "exchangeName": "Huobi", "ticker": "avaxusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "AVAXUSD" },
{ "exchangeName": "Kucoin", "ticker": "AVAX-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "AVAX-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "AVAX_USDT", "adjustByMarket": "USDT-USD" }
],
"BCH": [
{ "exchangeName": "Binance", "ticker": "BCHUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bitstamp", "ticker": "BCH/USD" },
{ "exchangeName": "Bybit", "ticker": "BCHUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "BCH-USD" },
{ "exchangeName": "Huobi", "ticker": "bchusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "BCHUSD" },
{ "exchangeName": "Kucoin", "ticker": "BCH-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "BCH-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "BCH_USDT", "adjustByMarket": "USDT-USD" }
],
"BLUR": [
{ "exchangeName": "Binance", "ticker": "BLURUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "BLURUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "BLUR-USD" },
{ "exchangeName": "Kraken", "ticker": "BLURUSD" },
{ "exchangeName": "Kucoin", "ticker": "BLUR-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "BLUR-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "BLUR_USDT", "adjustByMarket": "USDT-USD" }
],
"BNB": [
{ "exchangeName": "Binance", "ticker": "BNBUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "BNBUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Gate", "ticker": "BNB_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "BNB-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "BNB-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "BNB_USDT", "adjustByMarket": "USDT-USD" }
],
"BONK": [
{ "exchangeName": "Binance", "ticker": "BONKUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "BONKUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "BONK-USD" },
{ "exchangeName": "Kucoin", "ticker": "BONK-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "BONK-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "BONK_USDT", "adjustByMarket": "USDT-USD" }
],
"BTC": [
{ "exchangeName": "Binance", "ticker": "BTCUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bitstamp", "ticker": "BTC/USD" },
{ "exchangeName": "Bybit", "ticker": "BTCUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "BTC-USD" },
{ "exchangeName": "Huobi", "ticker": "btcusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "BTCUSD" },
{ "exchangeName": "Kucoin", "ticker": "BTC-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "BTC-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "BTC_USDT", "adjustByMarket": "USDT-USD" }
],
"CHZ": [
{ "exchangeName": "Binance", "ticker": "CHZUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "CHZ-USD" },
{ "exchangeName": "Kraken", "ticker": "CHZUSD" },
{ "exchangeName": "Kucoin", "ticker": "CHZ-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "CHZ-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "CHZ_USDT", "adjustByMarket": "USDT-USD" }
],
"CRV": [
{ "exchangeName": "Binance", "ticker": "CRVUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "CRV-USD" },
{ "exchangeName": "Kraken", "ticker": "CRVUSD" },
{ "exchangeName": "Kucoin", "ticker": "CRV-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "CRV-USDT", "adjustByMarket": "USDT-USD" }
],
"DOGE": [
{ "exchangeName": "Binance", "ticker": "DOGEUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "DOGEUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "DOGE-USD" },
{ "exchangeName": "Huobi", "ticker": "dogeusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "DOGEUSD" },
{ "exchangeName": "Kucoin", "ticker": "DOGE-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "DOGE-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "DOGE_USDT", "adjustByMarket": "USDT-USD" }
],
"DOT": [
{ "exchangeName": "Binance", "ticker": "DOTUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "DOTUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "DOT-USD" },
{ "exchangeName": "Huobi", "ticker": "dotusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "DOTUSD" },
{ "exchangeName": "Kucoin", "ticker": "DOT-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "DOT-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "DOT_USDT", "adjustByMarket": "USDT-USD" }
],
"DYM": [
{ "exchangeName": "Binance", "ticker": "DYMUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "DYMUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Gate", "ticker": "DYM_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "DYM-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "DYM_USDT", "adjustByMarket": "USDT-USD" }
],
"ENS": [
{ "exchangeName": "Binance", "ticker": "ENSUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "ENS-USD" },
{ "exchangeName": "Gate", "ticker": "ENS_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "ENS-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "ENS-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "ENS_USDT", "adjustByMarket": "USDT-USD" }
],
"EOS": [
{ "exchangeName": "Binance", "ticker": "EOSUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "EOSUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "EOS-USD" },
{ "exchangeName": "Gate", "ticker": "EOS_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "EOSUSD" },
{ "exchangeName": "Kucoin", "ticker": "EOS-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "EOS-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "EOS_USDT", "adjustByMarket": "USDT-USD" }
],
"ETC": [
{ "exchangeName": "Binance", "ticker": "ETCUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "ETCUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "ETC-USD" },
{ "exchangeName": "Huobi", "ticker": "etcusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "ETCUSD" },
{ "exchangeName": "Kucoin", "ticker": "ETC-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "ETC-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "ETC_USDT", "adjustByMarket": "USDT-USD" }
],
"ETH": [
{ "exchangeName": "Binance", "ticker": "ETHUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bitstamp", "ticker": "ETH/USD" },
{ "exchangeName": "Bybit", "ticker": "ETHUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "ETH-USD" },
{ "exchangeName": "Huobi", "ticker": "ethusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "ETHUSD" },
{ "exchangeName": "Kucoin", "ticker": "ETH-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "ETH-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "ETH_USDT", "adjustByMarket": "USDT-USD" }
],
"FET": [
{ "exchangeName": "Binance", "ticker": "FETUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "FET-USD" },
{ "exchangeName": "Kraken", "ticker": "FETUSD" },
{ "exchangeName": "Kucoin", "ticker": "FET-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "FET-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "FET_USDT", "adjustByMarket": "USDT-USD" }
],
"FIL": [
{ "exchangeName": "Binance", "ticker": "FILUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "FILUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "FIL-USD" },
{ "exchangeName": "Huobi", "ticker": "filusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "FILUSD" },
{ "exchangeName": "Kucoin", "ticker": "FIL-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "FIL-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "FIL_USDT", "adjustByMarket": "USDT-USD" }
],
"FTM": [
{ "exchangeName": "Binance", "ticker": "FTMUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "FTMUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "FTMUSD" },
{ "exchangeName": "Kucoin", "ticker": "FTM-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "FTM-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "FTM_USDT", "adjustByMarket": "USDT-USD" }
],
"GALA": [
{ "exchangeName": "Binance", "ticker": "GALAUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "GALAUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Gate", "ticker": "GALA_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "GALAUSD" },
{ "exchangeName": "Okx", "ticker": "GALA-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "GALA_USDT", "adjustByMarket": "USDT-USD" }
],
"GMT": [
{ "exchangeName": "Binance", "ticker": "GMTUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "GMTUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "GMT-USD" },
{ "exchangeName": "Gate", "ticker": "GMT_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "GMT-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "GMT-USDT", "adjustByMarket": "USDT-USD" }
],
"GRT": [
{ "exchangeName": "Binance", "ticker": "GRTUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "GRT-USD" },
{ "exchangeName": "Gate", "ticker": "GRT_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "GRTUSD" },
{ "exchangeName": "Kucoin", "ticker": "GRT-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "GRT-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "GRT_USDT", "adjustByMarket": "USDT-USD" }
],
"HBAR": [
{ "exchangeName": "Binance", "ticker": "HBARUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "HBARUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "HBAR-USD" },
{ "exchangeName": "Kucoin", "ticker": "HBAR-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "HBAR-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "HBAR_USDT", "adjustByMarket": "USDT-USD" }
],
"ICP": [
{ "exchangeName": "Binance", "ticker": "ICPUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "ICPUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "ICP-USD" },
{ "exchangeName": "Kraken", "ticker": "ICPUSD" },
{ "exchangeName": "Kucoin", "ticker": "ICP-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "ICP-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "ICP_USDT", "adjustByMarket": "USDT-USD" }
],
"IMX": [
{ "exchangeName": "Binance", "ticker": "IMXUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "IMX-USD" },
{ "exchangeName": "Kraken", "ticker": "IMXUSD" },
{ "exchangeName": "Kucoin", "ticker": "IMX-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "IMX-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "IMX_USDT", "adjustByMarket": "USDT-USD" }
],
"INJ": [
{ "exchangeName": "Binance", "ticker": "INJUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "INJUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "INJ-USD" },
{ "exchangeName": "Kraken", "ticker": "INJUSD" },
{ "exchangeName": "Kucoin", "ticker": "INJ-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "INJ-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "INJ_USDT", "adjustByMarket": "USDT-USD" }
],
"JTO": [
{ "exchangeName": "Binance", "ticker": "JTOUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "JTOUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "JTO-USD" },
{ "exchangeName": "Kucoin", "ticker": "JTO-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "JTO-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "JTO_USDT", "adjustByMarket": "USDT-USD" }
],
"JUP": [
{ "exchangeName": "Binance", "ticker": "JUPUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "JUPUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Gate", "ticker": "JUP_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "JUP-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "JUP_USDT", "adjustByMarket": "USDT-USD" }
],
"KAVA": [
{ "exchangeName": "Binance", "ticker": "KAVAUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "KAVAUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "KAVA-USD" },
{ "exchangeName": "Gate", "ticker": "KAVA_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "KAVAUSD" },
{ "exchangeName": "Kucoin", "ticker": "KAVA-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "KAVA_USDT", "adjustByMarket": "USDT-USD" }
],
"LDO": [
{ "exchangeName": "Binance", "ticker": "LDOUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "LDOUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "LDO-USD" },
{ "exchangeName": "Kraken", "ticker": "LDOUSD" },
{ "exchangeName": "Kucoin", "ticker": "LDO-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "LDO-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "LDO_USDT", "adjustByMarket": "USDT-USD" }
],
"LINK": [
{ "exchangeName": "Binance", "ticker": "LINKUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bitstamp", "ticker": "LINK/USD" },
{ "exchangeName": "Bybit", "ticker": "LINKUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "LINK-USD" },
{ "exchangeName": "Kraken", "ticker": "LINKUSD" },
{ "exchangeName": "Kucoin", "ticker": "LINK-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "LINK-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "LINK_USDT", "adjustByMarket": "USDT-USD" }
],
"LTC": [
{ "exchangeName": "Binance", "ticker": "LTCUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bitstamp", "ticker": "LTC/USD" },
{ "exchangeName": "Bybit", "ticker": "LTCUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "LTC-USD" },
{ "exchangeName": "Huobi", "ticker": "ltcusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "LTCUSD" },
{ "exchangeName": "Kucoin", "ticker": "LTC-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "LTC-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "LTC_USDT", "adjustByMarket": "USDT-USD" }
],
"MANA": [
{ "exchangeName": "Binance", "ticker": "MANAUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "MANA-USD" },
{ "exchangeName": "Gate", "ticker": "MANA_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "MANAUSD" },
{ "exchangeName": "Kucoin", "ticker": "MANA-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "MANA-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "MANA_USDT", "adjustByMarket": "USDT-USD" }
],
"MASK": [
{ "exchangeName": "Binance", "ticker": "MASKUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "MASKUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "MASK-USD" },
{ "exchangeName": "Gate", "ticker": "MASK_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Huobi", "ticker": "maskusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "MASK-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "MASK-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "MASK_USDT", "adjustByMarket": "USDT-USD" }
],
"MATIC": [
{ "exchangeName": "Binance", "ticker": "MATICUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bitstamp", "ticker": "MATIC/USD" },
{ "exchangeName": "Bybit", "ticker": "MATICUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "MATIC-USD" },
{ "exchangeName": "Huobi", "ticker": "maticusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "MATICUSD" },
{ "exchangeName": "Kucoin", "ticker": "MATIC-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "MATIC-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "MATIC_USDT", "adjustByMarket": "USDT-USD" }
],
"MINA": [
{ "exchangeName": "Binance", "ticker": "MINAUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "MINA-USD" },
{ "exchangeName": "Gate", "ticker": "MINA_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "MINAUSD" },
{ "exchangeName": "Okx", "ticker": "MINA-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "MINA_USDT", "adjustByMarket": "USDT-USD" }
],
"MKR": [
{ "exchangeName": "Binance", "ticker": "MKRUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "MKR-USD" },
{ "exchangeName": "Kraken", "ticker": "MKRUSD" },
{ "exchangeName": "Kucoin", "ticker": "MKR-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "MKR-USDT", "adjustByMarket": "USDT-USD" }
],
"NEAR": [
{ "exchangeName": "Binance", "ticker": "NEARUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "NEARUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "NEAR-USD" },
{ "exchangeName": "Huobi", "ticker": "nearusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "NEARUSD" },
{ "exchangeName": "Kucoin", "ticker": "NEAR-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "NEAR-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "NEAR_USDT", "adjustByMarket": "USDT-USD" }
],
"OP": [
{ "exchangeName": "Binance", "ticker": "OPUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "OPUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "OP-USD" },
{ "exchangeName": "Gate", "ticker": "OP_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "OPUSD" },
{ "exchangeName": "Kucoin", "ticker": "OP-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "OP-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "OP_USDT", "adjustByMarket": "USDT-USD" }
],
"ORDI": [
{ "exchangeName": "Binance", "ticker": "ORDIUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "ORDIUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Gate", "ticker": "ORDI_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Huobi", "ticker": "ordiusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "ORDI-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "ORDI-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "ORDI_USDT", "adjustByMarket": "USDT-USD" }
],
"PEPE": [
{ "exchangeName": "Binance", "ticker": "PEPEUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "PEPEUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "PEPEUSD" },
{ "exchangeName": "Kucoin", "ticker": "PEPE-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "PEPE-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "PEPE_USDT", "adjustByMarket": "USDT-USD" }
],
"PYTH": [
{ "exchangeName": "Binance", "ticker": "PYTHUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "PYTHUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Gate", "ticker": "PYTH_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "PYTH-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "PYTH-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "PYTH_USDT", "adjustByMarket": "USDT-USD" }
],
"RNDR": [
{ "exchangeName": "Binance", "ticker": "RNDRUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "RNDR-USD" },
{ "exchangeName": "Kraken", "ticker": "RNDRUSD" },
{ "exchangeName": "Kucoin", "ticker": "RNDR-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "RNDR-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "RNDR_USDT", "adjustByMarket": "USDT-USD" }
],
"RUNE": [
{ "exchangeName": "Binance", "ticker": "RUNEUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Gate", "ticker": "RUNE_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "RUNEUSD" },
{ "exchangeName": "Kucoin", "ticker": "RUNE-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "RUNE_USDT", "adjustByMarket": "USDT-USD" }
],
"SAND": [
{ "exchangeName": "Binance", "ticker": "SANDUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "SAND-USD" },
{ "exchangeName": "Gate", "ticker": "SAND_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "SAND-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "SAND-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "SAND_USDT", "adjustByMarket": "USDT-USD" }
],
"SEI": [
{ "exchangeName": "Binance", "ticker": "SEIUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "SEIUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "SEI-USD" },
{ "exchangeName": "Huobi", "ticker": "seiusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "SEIUSD" },
{ "exchangeName": "Kucoin", "ticker": "SEI-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "SEI_USDT", "adjustByMarket": "USDT-USD" }
],
"SHIB": [
{ "exchangeName": "Binance", "ticker": "SHIBUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "SHIBUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "SHIB-USD" },
{ "exchangeName": "Huobi", "ticker": "shibusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "SHIBUSD" },
{ "exchangeName": "Kucoin", "ticker": "SHIB-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "SHIB-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "SHIB_USDT", "adjustByMarket": "USDT-USD" }
],
"SNX": [
{ "exchangeName": "Binance", "ticker": "SNXUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "SNXUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "SNX-USD" },
{ "exchangeName": "Kraken", "ticker": "SNXUSD" },
{ "exchangeName": "Kucoin", "ticker": "SNX-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "SNX-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "SNX_USDT", "adjustByMarket": "USDT-USD" }
],
"SOL": [
{ "exchangeName": "Binance", "ticker": "SOLUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bitstamp", "ticker": "SOL/USD" },
{ "exchangeName": "Bybit", "ticker": "SOLUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "SOL-USD" },
{ "exchangeName": "Huobi", "ticker": "solusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "SOLUSD" },
{ "exchangeName": "Kucoin", "ticker": "SOL-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "SOL-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "SOL_USDT", "adjustByMarket": "USDT-USD" }
],
"STX": [
{ "exchangeName": "Binance", "ticker": "STXUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "STXUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "STX-USD" },
{ "exchangeName": "Gate", "ticker": "STX_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "STXUSD" },
{ "exchangeName": "Kucoin", "ticker": "STX-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "STX-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "STX_USDT", "adjustByMarket": "USDT-USD" }
],
"SUI": [
{ "exchangeName": "Binance", "ticker": "SUIUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "SUIUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "SUI-USD" },
{ "exchangeName": "Huobi", "ticker": "suiusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "SUIUSD" },
{ "exchangeName": "Kucoin", "ticker": "SUI-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "SUI-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "SUI_USDT", "adjustByMarket": "USDT-USD" }
],
"TIA": [
{ "exchangeName": "Binance", "ticker": "TIAUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "TIAUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "TIA-USD" },
{ "exchangeName": "Kraken", "ticker": "TIAUSD" },
{ "exchangeName": "Kucoin", "ticker": "TIA-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "TIA-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "TIA_USDT", "adjustByMarket": "USDT-USD" }
],
"TRX": [
{ "exchangeName": "Binance", "ticker": "TRXUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "TRXUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Gate", "ticker": "TRX_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Huobi", "ticker": "trxusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "TRXUSD" },
{ "exchangeName": "Kucoin", "ticker": "TRX-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "TRX-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "TRX_USDT", "adjustByMarket": "USDT-USD" }
],
"UNI": [
{ "exchangeName": "Binance", "ticker": "UNIUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "UNIUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "UNI-USD" },
{ "exchangeName": "Kraken", "ticker": "UNIUSD" },
{ "exchangeName": "Kucoin", "ticker": "UNI-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "UNI-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "UNI_USDT", "adjustByMarket": "USDT-USD" }
],
"WLD": [
{ "exchangeName": "Binance", "ticker": "WLDUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bybit", "ticker": "WLDUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Gate", "ticker": "WLD_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "WLD-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "WLD-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "WLD_USDT", "adjustByMarket": "USDT-USD" }
],
"WOO": [
{ "exchangeName": "Binance", "ticker": "WOOUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Gate", "ticker": "WOO_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "WOO-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "WOO-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "WOO_USDT", "adjustByMarket": "USDT-USD" }
],
"XLM": [
{ "exchangeName": "Binance", "ticker": "XLMUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bitstamp", "ticker": "XLM/USD" },
{ "exchangeName": "Bybit", "ticker": "XLMUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "XLM-USD" },
{ "exchangeName": "Kraken", "ticker": "XLMUSD" },
{ "exchangeName": "Kucoin", "ticker": "XLM-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "XLM-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "XLM_USDT", "adjustByMarket": "USDT-USD" }
],
"XRP": [
{ "exchangeName": "Binance", "ticker": "XRPUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Bitstamp", "ticker": "XRP/USD" },
{ "exchangeName": "Bybit", "ticker": "XRPUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "XRP-USD" },
{ "exchangeName": "Huobi", "ticker": "xrpusdt", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kraken", "ticker": "XRPUSD" },
{ "exchangeName": "Kucoin", "ticker": "XRP-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "XRP-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "XRP_USDT", "adjustByMarket": "USDT-USD" }
],
"ZETA": [
{ "exchangeName": "Bybit", "ticker": "ZETAUSDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "CoinbasePro", "ticker": "ZETA-USD" },
{ "exchangeName": "Gate", "ticker": "ZETA_USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Kucoin", "ticker": "ZETA-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Okx", "ticker": "ZETA-USDT", "adjustByMarket": "USDT-USD" },
{ "exchangeName": "Mexc", "ticker": "ZETA_USDT", "adjustByMarket": "USDT-USD" }
]
}
File diff suppressed because it is too large Load Diff
+638
View File
@@ -0,0 +1,638 @@
{
"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
}
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -14,7 +14,7 @@ if (AMPLITUDE_API_KEY) {
const html = await fs.readFile(htmlFilePath, 'utf-8');
const amplitudeCdnScript = `<script type="text/javascript">
!function(){"use strict";!function(e,t){var n=e.amplitude||{_q:[],_iq:{}};if(n.invoked)e.console&&console.error&&console.error("Amplitude snippet has been loaded.");else{var r=function(e,t){e.prototype[t]=function(){return this._q.push({name:t,args:Array.prototype.slice.call(arguments,0)}),this}},s=function(e,t,n){return function(r){e._q.push({name:t,args:Array.prototype.slice.call(n,0),resolve:r})}},o=function(e,t,n){e[t]=function(){if(n)return{promise:new Promise(s(e,t,Array.prototype.slice.call(arguments)))}}},i=function(e){for(var t=0;t<m.length;t++)o(e,m[t],!1);for(var n=0;n<g.length;n++)o(e,g[n],!0)};n.invoked=!0;var u=t.createElement("script");u.type="text/javascript",u.integrity="sha384-x0ik2D45ZDEEEpYpEuDpmj05fY91P7EOZkgdKmq4dKL/ZAVcufJ+nULFtGn0HIZE",u.crossOrigin="anonymous",u.async=!0,u.src="https://cdn.amplitude.com/libs/analytics-browser-2.0.0-min.js.gz",u.onload=function(){e.amplitude.runQueuedFunctions||console.log("[Amplitude] Error: could not load SDK")};var a=t.getElementsByTagName("script")[0];a.parentNode.insertBefore(u,a);for(var c=function(){return this._q=[],this},p=["add","append","clearAll","prepend","set","setOnce","unset","preInsert","postInsert","remove","getUserProperties"],l=0;l<p.length;l++)r(c,p[l]);n.Identify=c;for(var d=function(){return this._q=[],this},f=["getEventProperties","setProductId","setQuantity","setPrice","setRevenue","setRevenueType","setEventProperties"],v=0;v<f.length;v++)r(d,f[v]);n.Revenue=d;var m=["getDeviceId","setDeviceId","getSessionId","setSessionId","getUserId","setUserId","setOptOut","setTransport","reset","extendSession"],g=["init","add","remove","track","logEvent","identify","groupIdentify","setGroup","revenue","flush"];i(n),n.createInstance=function(e){return n._iq[e]={_q:[]},i(n._iq[e]),n._iq[e]},e.amplitude=n}}(window,document)}();
!function(){"use strict";!function(e,t){var n=e.amplitude||{_q:[],_iq:{}};if(n.invoked)e.console&&console.error&&console.error("Amplitude snippet has been loaded.");else{var r=function(e,t){e.prototype[t]=function(){return this._q.push({name:t,args:Array.prototype.slice.call(arguments,0)}),this}},s=function(e,t,n){return function(r){e._q.push({name:t,args:Array.prototype.slice.call(n,0),resolve:r})}},o=function(e,t,n){e[t]=function(){if(n)return{promise:new Promise(s(e,t,Array.prototype.slice.call(arguments)))}}},i=function(e){for(var t=0;t<m.length;t++)o(e,m[t],!1);for(var n=0;n<g.length;n++)o(e,g[n],!0)};n.invoked=!0;var u=t.createElement("script");u.type="text/javascript",u.integrity="sha384-BVo5ZjsjH373rWbcjz9Qjb2L6BgLwLADcZtZZPu3nMl8+7LPDhi1NcUEf0Ate41Y",u.crossOrigin="anonymous",u.async=!0,u.src="/libs/amplitude-analytics-browser-2.0.0-min.js",u.onload=function(){e.amplitude.runQueuedFunctions||console.log("[Amplitude] Error: could not load SDK")};var a=t.getElementsByTagName("script")[0];a.parentNode.insertBefore(u,a);for(var c=function(){return this._q=[],this},p=["add","append","clearAll","prepend","set","setOnce","unset","preInsert","postInsert","remove","getUserProperties"],l=0;l<p.length;l++)r(c,p[l]);n.Identify=c;for(var d=function(){return this._q=[],this},f=["getEventProperties","setProductId","setQuantity","setPrice","setRevenue","setRevenueType","setEventProperties"],v=0;v<f.length;v++)r(d,f[v]);n.Revenue=d;var m=["getDeviceId","setDeviceId","getSessionId","setSessionId","getUserId","setUserId","setOptOut","setTransport","reset","extendSession"],g=["init","add","remove","track","logEvent","identify","groupIdentify","setGroup","revenue","flush"];i(n),n.createInstance=function(e){return n._iq[e]={_q:[]},i(n._iq[e]),n._iq[e]},e.amplitude=n}}(window,document)}();
</script>
`;
+5 -5
View File
@@ -32,20 +32,20 @@ if (
/* hardcoded injection depending on whether the app is available on App Store and/or Google Play */
if (SMARTBANNER_APPSTORE_URL) {
smartbanner = `\t<meta name="smartbanner:button-url-apple" content="${SMARTBANNER_APPSTORE_URL}">\n${smartbanner}`;
smartbanner = `\t<meta name="smartbanner:button-url-apple" content="${SMARTBANNER_APPSTORE_URL}">\n` + smartbanner;
}
if (SMARTBANNER_GOOGLEPLAY_URL) {
smartbanner = `\t<meta name="smartbanner:button-url-google" content="${SMARTBANNER_GOOGLEPLAY_URL}">\n${smartbanner}`;
smartbanner = `\t<meta name="smartbanner:button-url-google" content="${SMARTBANNER_GOOGLEPLAY_URL}">\n` + smartbanner;
}
if (SMARTBANNER_APPSTORE_URL) {
if (SMARTBANNER_GOOGLEPLAY_URL) {
smartbanner = `\t<meta name="smartbanner:enabled-platforms" content="android,ios">\n${smartbanner}`;
smartbanner = `\t<meta name="smartbanner:enabled-platforms" content="android,ios">\n` + smartbanner;
} else {
smartbanner = `\t<meta name="smartbanner:enabled-platforms" content="ios">\n${smartbanner}`;
smartbanner = `\t<meta name="smartbanner:enabled-platforms" content="ios">\n` + smartbanner;
}
} else {
if (SMARTBANNER_GOOGLEPLAY_URL) {
smartbanner = `\t<meta name="smartbanner:enabled-platforms" content="android">\n${smartbanner}`;
smartbanner = `\t<meta name="smartbanner:enabled-platforms" content="android">\n` + smartbanner;
}
}
+25
View File
@@ -8,6 +8,7 @@ const assetIcons = {
'1INCH': '/currencies/1inch.png',
AAVE: '/currencies/aave.png',
ADA: '/currencies/ada.png',
AGIX: '/currencies/agix.png',
ALGO: '/currencies/algo.png',
APE: '/currencies/ape.png',
APT: '/currencies/apt.png',
@@ -16,35 +17,57 @@ const assetIcons = {
AVAX: '/currencies/avax.png',
BCH: '/currencies/bch.png',
BLUR: '/currencies/blur.png',
BNB: '/currencies/bnb.png',
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',
DOGE: '/currencies/doge.png',
DOT: '/currencies/dot.png',
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',
@@ -55,6 +78,7 @@ const assetIcons = {
USDT: '/currencies/usdt.png',
WBTC: '/currencies/wbtc.png',
WETH: '/currencies/weth.png',
WOO: '/currencies/woo.png',
WLD: '/currencies/wld.png',
XLM: '/currencies/xlm.png',
XMR: '/currencies/xmr.png',
@@ -62,6 +86,7 @@ const assetIcons = {
XTZ: '/currencies/xtz.png',
YFI: '/currencies/yfi.png',
ZEC: '/currencies/zec.png',
ZETA: '/currencies/zeta.png',
ZRX: '/currencies/zrx.png',
} as const;
+5
View File
@@ -33,4 +33,9 @@ TagStory.argTypes = {
control: { type: 'select' },
defaultValue: undefined,
},
isHighlighted: {
options: [true, false],
control: { type: 'select' },
defaultValue: false,
},
};
+1
View File
@@ -76,5 +76,6 @@ export const Tag = styled.span<StyleProps>`
isHighlighted &&
css`
background-color: var(--color-accent);
color: var(--color-text-button);
`}
`;
+6 -1
View File
@@ -1,4 +1,4 @@
import environments from '../../public/configs/env.json';
import environments from '../../public/configs/v1/env.json';
const CURRENT_MODE = ({
production: 'MAINNET',
@@ -14,5 +14,10 @@ export const isDev = CURRENT_MODE === 'DEV';
export const AVAILABLE_ENVIRONMENTS = environments.deployments[CURRENT_MODE];
export const CURRENT_ABACUS_DEPLOYMENT = CURRENT_MODE;
export const ENVIRONMENT_CONFIG_MAP = environments.environments;
export const TOKEN_CONFIG_MAP = environments.tokens;
export const LINKS_CONFIG_MAP = environments.links;
export const WALLETS_CONFIG_MAP = environments.wallets;
export const GOVERNANCE_CONFIG_MAP = environments.governance;
export type DydxNetwork = keyof typeof ENVIRONMENT_CONFIG_MAP;
export type DydxChainId = keyof typeof TOKEN_CONFIG_MAP;
export const DEFAULT_APP_ENVIRONMENT = AVAILABLE_ENVIRONMENTS.default as DydxNetwork;
+1
View File
@@ -22,4 +22,5 @@ export enum NumberSign {
// Deposit/Withdraw
export const MAX_CCTP_TRANSFER_AMOUNT = 1_000_000;
export const MIN_CCTP_TRANSFER_AMOUNT = 10;
export const MAX_PRICE_IMPACT = 0.02; // 2%
+9 -1
View File
@@ -1,4 +1,12 @@
import { AppColorMode } from '@/state/configs';
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',
};
export type Theme = {
[AppColorMode.GreenUp]: ThemeColorBase;
+54 -20
View File
@@ -4,7 +4,6 @@ import { AlertType } from '@/constants/alerts';
import { STRING_KEYS } from '@/constants/localization';
import { TimeUnitShort } from '@/constants/time';
// TODO: rename to OrderType
export enum TradeTypes {
MARKET = 'MARKET',
LIMIT = 'LIMIT',
@@ -15,6 +14,16 @@ export enum TradeTypes {
TRAILING_STOP = 'TRAILING_STOP',
}
enum ClosingTradeTypes {
LIQUIDATED = 'LIQUIDATED',
LIQUIDATION = 'LIQUIDATION',
OFFSETTING = 'OFFSETTING',
DELEVERAGED = 'DELEVERAGED',
FINAL_SETTLEMENT = 'FINAL_SETTLEMENT',
}
export type OrderType = TradeTypes | ClosingTradeTypes;
export enum TimeInForceOptions {
GTT = 'GTT',
FOK = 'FOK',
@@ -40,49 +49,74 @@ export const POSITION_SIDE_STRINGS: Record<PositionSide, string> = {
[PositionSide.Short]: STRING_KEYS.SHORT_POSITION_SHORT,
};
export const TRADE_TYPE_STRINGS: Record<
TradeTypes,
export const ORDER_TYPE_STRINGS: Record<
OrderType,
{
tradeTypeKeyShort: string;
tradeTypeKey: string;
descriptionKey: string;
orderTypeKeyShort: string;
orderTypeKey: string;
descriptionKey: string | null;
}
> = {
[TradeTypes.LIMIT]: {
tradeTypeKeyShort: STRING_KEYS.LIMIT_ORDER_SHORT,
tradeTypeKey: STRING_KEYS.LIMIT_ORDER,
orderTypeKeyShort: STRING_KEYS.LIMIT_ORDER_SHORT,
orderTypeKey: STRING_KEYS.LIMIT_ORDER,
descriptionKey: STRING_KEYS.LIMIT_ORDER_DESCRIPTION,
},
[TradeTypes.MARKET]: {
tradeTypeKeyShort: STRING_KEYS.MARKET_ORDER_SHORT,
tradeTypeKey: STRING_KEYS.MARKET_ORDER,
orderTypeKeyShort: STRING_KEYS.MARKET_ORDER_SHORT,
orderTypeKey: STRING_KEYS.MARKET_ORDER,
descriptionKey: STRING_KEYS.MARKET_ORDER_DESCRIPTION,
},
[TradeTypes.STOP_LIMIT]: {
tradeTypeKeyShort: STRING_KEYS.STOP_LIMIT,
tradeTypeKey: STRING_KEYS.STOP_LIMIT,
orderTypeKeyShort: STRING_KEYS.STOP_LIMIT,
orderTypeKey: STRING_KEYS.STOP_LIMIT,
descriptionKey: STRING_KEYS.STOP_LIMIT_DESCRIPTION,
},
[TradeTypes.STOP_MARKET]: {
tradeTypeKeyShort: STRING_KEYS.STOP_MARKET,
tradeTypeKey: STRING_KEYS.STOP_MARKET,
orderTypeKeyShort: STRING_KEYS.STOP_MARKET,
orderTypeKey: STRING_KEYS.STOP_MARKET,
descriptionKey: STRING_KEYS.STOP_MARKET_DESCRIPTION,
},
[TradeTypes.TAKE_PROFIT]: {
tradeTypeKeyShort: STRING_KEYS.TAKE_PROFIT_LIMIT,
tradeTypeKey: STRING_KEYS.TAKE_PROFIT_LIMIT,
orderTypeKeyShort: STRING_KEYS.TAKE_PROFIT_LIMIT,
orderTypeKey: STRING_KEYS.TAKE_PROFIT_LIMIT,
descriptionKey: STRING_KEYS.TAKE_PROFIT_LIMIT_DESCRIPTION,
},
[TradeTypes.TAKE_PROFIT_MARKET]: {
tradeTypeKeyShort: STRING_KEYS.TAKE_PROFIT_MARKET,
tradeTypeKey: STRING_KEYS.TAKE_PROFIT_MARKET,
orderTypeKeyShort: STRING_KEYS.TAKE_PROFIT_MARKET,
orderTypeKey: STRING_KEYS.TAKE_PROFIT_MARKET,
descriptionKey: STRING_KEYS.TAKE_PROFIT_MARKET_DESCRIPTION,
},
[TradeTypes.TRAILING_STOP]: {
tradeTypeKeyShort: STRING_KEYS.TRAILING_STOP,
tradeTypeKey: STRING_KEYS.TRAILING_STOP,
orderTypeKeyShort: STRING_KEYS.TRAILING_STOP,
orderTypeKey: STRING_KEYS.TRAILING_STOP,
descriptionKey: STRING_KEYS.TRAILING_STOP_DESCRIPTION,
},
[ClosingTradeTypes.LIQUIDATED]: {
orderTypeKeyShort: STRING_KEYS.LIQUIDATED,
orderTypeKey: STRING_KEYS.LIQUIDATED,
descriptionKey: null,
},
[ClosingTradeTypes.LIQUIDATION]: {
orderTypeKeyShort: STRING_KEYS.LIQUIDATION,
orderTypeKey: STRING_KEYS.LIQUIDATION,
descriptionKey: null,
},
[ClosingTradeTypes.OFFSETTING]: {
orderTypeKeyShort: STRING_KEYS.OFFSETTING,
orderTypeKey: STRING_KEYS.OFFSETTING,
descriptionKey: null,
},
[ClosingTradeTypes.DELEVERAGED]: {
orderTypeKeyShort: STRING_KEYS.DELEVERAGED,
orderTypeKey: STRING_KEYS.DELEVERAGED,
descriptionKey: null,
},
[ClosingTradeTypes.FINAL_SETTLEMENT]: {
orderTypeKeyShort: STRING_KEYS.FINAL_SETTLEMENT,
orderTypeKey: STRING_KEYS.FINAL_SETTLEMENT,
descriptionKey: null,
},
};
export const GOOD_TIL_TIME_TIMESCALE_STRINGS: Record<TimeUnitShort, string> = {
+16
View File
@@ -0,0 +1,16 @@
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;
};
+5 -4
View File
@@ -24,7 +24,7 @@ import {
import { isMetaMask } from '@/lib/wallet/providers';
import { DydxNetwork, ENVIRONMENT_CONFIG_MAP } from './networks';
import { DydxChainId, WALLETS_CONFIG_MAP } from './networks';
// Wallet connection types
@@ -40,6 +40,7 @@ export enum WalletErrorType {
// General
ChainMismatch,
UserCanceled,
SwitchChainMethodMissing,
// Non-Deterministic
NonDeterministicWallet,
@@ -290,17 +291,17 @@ export const COSMOS_DERIVATION_PATH = "m/44'/118'/0'/0/0";
/**
* @description typed data to sign for dYdX Chain onboarding
*/
export const getSignTypedData = (selectedNetwork: DydxNetwork) =>
export const getSignTypedData = (selectedDydxChainId: DydxChainId) =>
({
primaryType: 'dYdX',
domain: {
name: ENVIRONMENT_CONFIG_MAP[selectedNetwork].wallets.signTypedDataDomainName,
name: WALLETS_CONFIG_MAP[selectedDydxChainId].signTypedDataDomainName,
},
types: {
dYdX: [{ name: 'action', type: 'string' }],
},
message: {
action: ENVIRONMENT_CONFIG_MAP[selectedNetwork].wallets.signTypedDataAction,
action: WALLETS_CONFIG_MAP[selectedDydxChainId].signTypedDataAction,
},
} as const);
+2
View File
@@ -1,2 +1,4 @@
export { useChartLines } from './useChartLines';
export { useChartMarketAndResolution } from './useChartMarketAndResolution';
export { useTradingView } from './useTradingView';
export { useTradingViewTheme } from './useTradingViewTheme';
+209
View File
@@ -0,0 +1,209 @@
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 };
};
@@ -0,0 +1,72 @@
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 });
};
};
+30 -7
View File
@@ -1,15 +1,19 @@
import { useEffect } from 'react';
import React, { 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 } from '@/constants/localization';
import { SUPPORTED_LOCALE_BASE_TAGS, STRING_KEYS } from '@/constants/localization';
import { LocalStorageKey } from '@/constants/localStorage';
import { useDydxClient, useLocalStorage } from '@/hooks';
import { store } from '@/state/_store';
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';
@@ -23,14 +27,19 @@ import { getSavedResolution, getWidgetOptions, getWidgetOverrides } from '@/lib/
*/
export const useTradingView = ({
tvWidgetRef,
displayButtonRef,
setIsChartReady,
}: {
tvWidgetRef: React.MutableRefObject<any>;
tvWidgetRef: React.MutableRefObject<TvWidget | null>;
displayButtonRef: React.MutableRefObject<HTMLElement | null>;
setIsChartReady: React.Dispatch<React.SetStateAction<boolean>>;
}) => {
const marketId = useSelector(getCurrentMarketId);
const stringGetter = useStringGetter();
const appTheme = useSelector(getAppTheme);
const appColorMode = useSelector(getAppColorMode);
const marketId = useSelector(getCurrentMarketId);
const marketIds = useSelector(getMarketIds, shallowEqual);
const selectedLocale = useSelector(getSelectedLocale);
const selectedNetwork = useSelector(getSelectedNetwork);
@@ -49,7 +58,6 @@ export const useTradingView = ({
const widgetOptions = getWidgetOptions();
const widgetOverrides = getWidgetOverrides({ appTheme, appColorMode });
const options = {
// debug: true,
...widgetOptions,
...widgetOverrides,
datafeed: getDydxDatafeed(store, getCandlesForDatafeed),
@@ -63,6 +71,19 @@ 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?.subscribe('onAutoSaveNeeded', () =>
tvWidgetRef?.current?.save((chartConfig: object) => setTvChartConfig(chartConfig))
);
@@ -72,6 +93,8 @@ export const useTradingView = ({
}
return () => {
displayButtonRef.current?.remove();
displayButtonRef.current = null;
tvWidgetRef.current?.remove();
tvWidgetRef.current = null;
setIsChartReady(false);
+56 -35
View File
@@ -1,12 +1,14 @@
import { useEffect } from 'react';
import { useSelector } from 'react-redux';
import type { IChartingLibraryWidget, ThemeName } from 'public/tradingview/charting_library';
import { THEME_NAMES } from '@/constants/styles/colors';
import type { ChartLine, TvWidget } from '@/constants/tvchart';
import { AppColorMode, AppTheme } from '@/state/configs';
import { getAppTheme, getAppColorMode } from '@/state/configsSelectors';
import { getWidgetOverrides } from '@/lib/tradingView/utils';
import { getWidgetOverrides, getChartLineColors } from '@/lib/tradingView/utils';
/**
* @description Method to define a type guard and check that an element is an IFRAME
@@ -22,10 +24,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,
tvWidget,
isWidgetReady,
}: {
tvWidget: (IChartingLibraryWidget & { _id?: string; _ready?: boolean }) | null;
chartLines: Record<string, ChartLine>;
tvWidget: TvWidget | null;
isWidgetReady?: boolean;
}) => {
const appTheme: AppTheme = useSelector(getAppTheme);
@@ -33,47 +37,64 @@ export const useTradingViewTheme = ({
useEffect(() => {
if (tvWidget && isWidgetReady) {
tvWidget
.changeTheme?.(
{
[AppTheme.Classic]: '',
[AppTheme.Dark]: 'Dark',
[AppTheme.Light]: 'Light',
}[appTheme] as ThemeName
)
.then(() => {
const tvChartId = tvWidget?._id;
tvWidget.changeTheme?.(THEME_NAMES[appTheme]).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;
if (appTheme === AppTheme.Classic) {
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'],
});
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);
}
line
.setQuantityBorderColor(borderColor)
.setBodyBackgroundColor(backgroundColor)
.setBodyBorderColor(borderColor)
.setBodyTextColor(textColor)
.setQuantityTextColor(textButtonColor);
});
});
}
}, [appTheme, appColorMode]);
}, [appTheme, appColorMode, isWidgetReady]);
};
+8 -8
View File
@@ -18,14 +18,13 @@ import type { ResolutionString } from 'public/tradingview/charting_library';
import type { ConnectNetworkEvent, NetworkConfig } from '@/constants/abacus';
import { DEFAULT_TRANSACTION_MEMO } from '@/constants/analytics';
import { type Candle, RESOLUTION_MAP } from '@/constants/candles';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { DydxChainAsset } from '@/constants/wallets';
import { getSelectedNetwork } from '@/state/appSelectors';
import { log } from '@/lib/telemetry';
import { useRestrictions } from './useRestrictions';
import { useTokenConfigs } from './useTokenConfigs';
type DydxContextType = ReturnType<typeof useDydxClientContext>;
const DydxContext = createContext<DydxContextType>({} as DydxContextType);
@@ -41,7 +40,8 @@ const useDydxClientContext = () => {
// ------ Network ------ //
const selectedNetwork = useSelector(getSelectedNetwork);
const tokensConfigs = ENVIRONMENT_CONFIG_MAP[selectedNetwork].tokens;
const { usdcDenom, usdcDecimals, usdcGasDenom, chainTokenDenom, chainTokenDecimals } =
useTokenConfigs();
const [networkConfig, setNetworkConfig] = useState<NetworkConfig>();
@@ -75,11 +75,11 @@ const useDydxClientContext = () => {
networkConfig.validatorUrl,
networkConfig.chainId,
{
USDC_DENOM: tokensConfigs[DydxChainAsset.USDC].denom,
USDC_DECIMALS: tokensConfigs[DydxChainAsset.USDC].decimals,
USDC_GAS_DENOM: tokensConfigs[DydxChainAsset.USDC].gasDenom,
CHAINTOKEN_DENOM: tokensConfigs[DydxChainAsset.CHAINTOKEN].denom,
CHAINTOKEN_DECIMALS: tokensConfigs[DydxChainAsset.CHAINTOKEN].decimals,
USDC_DENOM: usdcDenom,
USDC_DECIMALS: usdcDecimals,
USDC_GAS_DENOM: usdcGasDenom,
CHAINTOKEN_DENOM: chainTokenDenom,
CHAINTOKEN_DECIMALS: chainTokenDecimals,
},
{
broadcastPollIntervalMs: 3_000,
+7 -4
View File
@@ -1,5 +1,8 @@
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { useSelectedNetwork } from '@/hooks';
import { useSelector } from 'react-redux';
import { GOVERNANCE_CONFIG_MAP } from '@/constants/networks';
import { getSelectedDydxChainId } from '@/state/appSelectors';
export interface GovernanceVariables {
newMarketProposal: {
@@ -10,7 +13,7 @@ export interface GovernanceVariables {
}
export const useGovernanceVariables = (): GovernanceVariables => {
const { selectedNetwork } = useSelectedNetwork();
const governanceVars = ENVIRONMENT_CONFIG_MAP[selectedNetwork].governance as GovernanceVariables;
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const governanceVars = GOVERNANCE_CONFIG_MAP[selectedDydxChainId] as GovernanceVariables;
return governanceVars;
};
+4 -4
View File
@@ -5,7 +5,6 @@ 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';
@@ -23,7 +22,7 @@ import {
TransferNotificationTypes,
} from '@/constants/notifications';
import { useSelectedNetwork, useStringGetter } from '@/hooks';
import { useStringGetter } from '@/hooks';
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
import { AssetIcon } from '@/components/AssetIcon';
@@ -36,6 +35,7 @@ import { getSubaccountFills, getSubaccountOrders } from '@/state/accountSelector
import { openDialog } from '@/state/dialogs';
import { getAbacusNotifications } from '@/state/notificationsSelectors';
import { getMarketIds } from '@/state/perpetualsSelectors';
import { getSelectedDydxChainId } from '@/state/appSelectors';
import { formatSeconds } from '@/lib/timeUtils';
@@ -175,7 +175,7 @@ export const notificationTypes: NotificationTypeConfig[] = [
useTrigger: ({ trigger }) => {
const stringGetter = useStringGetter();
const { transferNotifications } = useLocalNotifications();
const { selectedNetwork } = useSelectedNetwork();
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
useEffect(() => {
for (const transfer of transferNotifications) {
@@ -184,7 +184,7 @@ export const notificationTypes: NotificationTypeConfig[] = [
const icon = <Icon iconName={isFinished ? IconName.Transfer : IconName.Clock} />;
const transferType =
type ?? fromChainId === ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId
type ?? fromChainId === selectedDydxChainId
? TransferNotificationTypes.Withdrawal
: TransferNotificationTypes.Deposit;
+12 -6
View File
@@ -4,8 +4,11 @@ import { useSelector } from 'react-redux';
import { DEFAULT_DOCUMENT_TITLE } from '@/constants/routes';
import { getSelectedLocale } from '@/state/localizationSelectors';
import { getCurrentMarketData, getCurrentMarketId } from '@/state/perpetualsSelectors';
import type { RootState } from '@/state/_store';
import {
getCurrentMarketId,
getCurrentMarketMidMarketPrice,
getCurrentMarketOraclePrice,
} from '@/state/perpetualsSelectors';
import { useBreakpoints } from './useBreakpoints';
@@ -13,11 +16,14 @@ export const usePageTitlePriceUpdates = () => {
const selectedLocale = useSelector(getSelectedLocale);
const { isNotTablet } = useBreakpoints();
const id = useSelector(getCurrentMarketId);
const oraclePrice = useSelector((state: RootState) => getCurrentMarketData(state)?.oraclePrice);
const oraclePrice = useSelector(getCurrentMarketOraclePrice);
const orderbookMidMarketPrice = useSelector(getCurrentMarketMidMarketPrice);
const price = orderbookMidMarketPrice ?? oraclePrice;
useEffect(() => {
if (id && oraclePrice && isNotTablet) {
const priceString = oraclePrice.toLocaleString(selectedLocale);
if (id && price && isNotTablet) {
const priceString = price.toLocaleString(selectedLocale);
document.title = `$${priceString} ${id} · ${DEFAULT_DOCUMENT_TITLE}`;
} else {
document.title = DEFAULT_DOCUMENT_TITLE;
@@ -26,5 +32,5 @@ export const usePageTitlePriceUpdates = () => {
return () => {
document.title = DEFAULT_DOCUMENT_TITLE;
};
}, [oraclePrice]);
}, [price]);
};
+3 -2
View File
@@ -47,8 +47,9 @@ export const PotentialMarketsProvider = ({ ...props }) => (
export const usePotentialMarkets = () => useContext(PotentialMarketsContext);
const EXCHANGE_CONFIG_FILE_PATH = '/configs/potentialMarketExchangeConfig.json';
const POTENTIAL_MARKETS_FILE_PATH = '/configs/potentialMarketParameters.json';
const EXCHANGE_CONFIG_FILE_PATH = '/configs/otherMarketExchangeConfig.json';
const POTENTIAL_MARKETS_FILE_PATH = '/configs/otherMarketParameters.json';
export const usePotentialMarketsContext = () => {
const stringGetter = useStringGetter();
+1 -1
View File
@@ -2,7 +2,7 @@ import { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { LocalStorageKey } from '@/constants/localStorage';
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork, ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork } from '@/constants/networks';
import { useAccounts, useLocalStorage } from '@/hooks';
+1 -1
View File
@@ -28,7 +28,7 @@ import { setSubaccount, setHistoricalPnl, removeUncommittedOrderClientId } from
import { getBalances } from '@/state/accountSelectors';
import abacusStateManager from '@/lib/abacus';
import { hashFromTx } from '@/lib/hashfromTx';
import { hashFromTx } from '@/lib/txUtils';
import { log } from '@/lib/telemetry';
import { useAccounts } from './useAccounts';
+14 -10
View File
@@ -1,7 +1,9 @@
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { useSelector } from 'react-redux';
import { TOKEN_CONFIG_MAP } from '@/constants/networks';
import { DydxChainAsset } from '@/constants/wallets';
import { useSelectedNetwork } from '@/hooks';
import { getSelectedDydxChainId } from '@/state/appSelectors';
export const useTokenConfigs = (): {
tokensConfigs: {
@@ -10,31 +12,33 @@ export const useTokenConfigs = (): {
name: string;
decimals: number;
gasDenom?: string;
},
};
[DydxChainAsset.CHAINTOKEN]: {
denom: string;
name: string;
decimals: number;
gasDenom?: string;
},
};
};
usdcDenom: string;
usdcDecimals: number;
usdcGasDenom: string;
usdcLabel: string;
chainTokenDenom: string;
chainTokenDecimals: number;
chainTokenLabel: string;
} => {
const { selectedNetwork } = useSelectedNetwork();
const tokensConfigs = ENVIRONMENT_CONFIG_MAP[selectedNetwork].tokens;
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const tokensConfigs = TOKEN_CONFIG_MAP[selectedDydxChainId];
return {
return {
tokensConfigs,
usdcDenom: tokensConfigs[DydxChainAsset.USDC].denom,
usdcDecimals: tokensConfigs[DydxChainAsset.USDC].decimals,
usdcDenom: tokensConfigs[DydxChainAsset.USDC].denom,
usdcDecimals: tokensConfigs[DydxChainAsset.USDC].decimals,
usdcGasDenom: tokensConfigs[DydxChainAsset.USDC].gasDenom,
usdcLabel: tokensConfigs[DydxChainAsset.USDC].name,
chainTokenDenom: tokensConfigs[DydxChainAsset.CHAINTOKEN].denom,
chainTokenDecimals: tokensConfigs[DydxChainAsset.CHAINTOKEN].decimals,
chainTokenDecimals: tokensConfigs[DydxChainAsset.CHAINTOKEN].decimals,
chainTokenLabel: tokensConfigs[DydxChainAsset.CHAINTOKEN].name,
};
};
+8 -4
View File
@@ -1,12 +1,15 @@
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { useSelector } from 'react-redux';
import { useSelectedNetwork } from '@/hooks';
import { LINKS_CONFIG_MAP } from '@/constants/networks';
import { getSelectedDydxChainId } from '@/state/appSelectors';
const FALLBACK_URL = 'https://help.dydx.exchange/';
export interface LinksConfigs {
tos: string;
privacy: string;
statusPage: string;
mintscan: string;
mintscanBase: string;
feedback?: string;
@@ -27,12 +30,13 @@ export interface LinksConfigs {
}
export const useURLConfigs = (): LinksConfigs => {
const { selectedNetwork } = useSelectedNetwork();
const linksConfigs = ENVIRONMENT_CONFIG_MAP[selectedNetwork].links as LinksConfigs;
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const linksConfigs = LINKS_CONFIG_MAP[selectedDydxChainId] as LinksConfigs;
return {
tos: linksConfigs.tos,
privacy: linksConfigs.privacy,
statusPage: linksConfigs.statusPage,
mintscan: linksConfigs.mintscan,
mintscanBase: linksConfigs.mintscanBase,
feedback: linksConfigs.feedback || FALLBACK_URL,
+14 -11
View File
@@ -4,7 +4,7 @@ import { useSelector } from 'react-redux';
import { EvmDerivedAddresses } from '@/constants/account';
import { STRING_KEYS } from '@/constants/localization';
import { LocalStorageKey } from '@/constants/localStorage';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { ENVIRONMENT_CONFIG_MAP, WALLETS_CONFIG_MAP } from '@/constants/networks';
import {
type DydxAddress,
@@ -32,7 +32,7 @@ import {
WalletType as CosmosWalletType,
} from 'graz';
import { getSelectedNetwork } from '@/state/appSelectors';
import { getSelectedDydxChainId } from '@/state/appSelectors';
import { resolveWagmiConnector } from '@/lib/wagmi';
import { getWalletConnection, parseWalletError } from '@/lib/wallet';
@@ -91,8 +91,8 @@ export const useWalletConnection = () => {
// Wallet connection
const selectedNetwork = useSelector(getSelectedNetwork);
const walletConnectConfig = ENVIRONMENT_CONFIG_MAP[selectedNetwork].wallets.walletconnect;
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const walletConnectConfig = WALLETS_CONFIG_MAP[selectedDydxChainId].walletconnect;
const wagmiConnector = useMemo(
() =>
walletType && walletConnectionType
@@ -163,17 +163,20 @@ export const useWalletConnection = () => {
}
}
} catch (error) {
throw Object.assign(
new Error([error.message, error.cause?.message].filter(Boolean).join('\n')),
{
walletConnectionType: walletConnection?.type,
}
);
const { isErrorExpected } = parseWalletError({ error, stringGetter });
if (!isErrorExpected) {
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 -4
View File
@@ -3,9 +3,9 @@ import styled, { type AnyStyledComponent, css } from 'styled-components';
import { AbacusApiStatus } from '@/constants/abacus';
import { ButtonSize, ButtonType } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { ENVIRONMENT_CONFIG_MAP, isDev } from '@/constants/networks';
import { isDev } from '@/constants/networks';
import { useApiState, useSelectedNetwork, useStringGetter } from '@/hooks';
import { useApiState, useStringGetter, useURLConfigs } from '@/hooks';
import { ChatIcon, LinkOutIcon } from '@/icons';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -28,8 +28,7 @@ enum ExchangeStatus {
export const FooterDesktop = () => {
const stringGetter = useStringGetter();
const { height, indexerHeight, status, statusErrorMessage } = useApiState();
const { selectedNetwork } = useSelectedNetwork();
const { statusPage } = ENVIRONMENT_CONFIG_MAP[selectedNetwork].links;
const { statusPage } = useURLConfigs();
const { exchangeStatus, label } =
!status || status === AbacusApiStatus.NORMAL
+7 -6
View File
@@ -34,7 +34,7 @@ import {
import { DEFAULT_TRANSACTION_MEMO } from '@/constants/analytics';
import { DialogTypes } from '@/constants/dialogs';
import { UNCOMMITTED_ORDER_TIMEOUT_MS } from '@/constants/trade';
import { ENVIRONMENT_CONFIG_MAP, DydxNetwork, isTestnet } from '@/constants/networks';
import { DydxChainId, isTestnet } from '@/constants/networks';
import { RootStore } from '@/state/_store';
import { addUncommittedOrderClientId, removeUncommittedOrderClientId } from '@/state/account';
@@ -43,7 +43,11 @@ import { openDialog } from '@/state/dialogs';
import { StatefulOrderError } from '../errors';
import { bytesToBigInt } from '../numbers';
import { log } from '../telemetry';
import { hashFromTx } from '../hashfromTx';
import { hashFromTx, getMintscanTxLink } from '../txUtils';
(BigInt.prototype as any).toJSON = function () {
return this.toString();
};
class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
private compositeClient: CompositeClient | undefined;
@@ -238,9 +242,7 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
if (isTestnet) {
console.log(
`${ENVIRONMENT_CONFIG_MAP[
this.compositeClient.network.getString() as DydxNetwork
]?.links?.mintscan?.replace('{tx_hash}', hash.toString())}`
getMintscanTxLink(this.compositeClient.network.getString() as DydxChainId, hash)
);
} else console.log(`txHash: ${hash}`);
@@ -536,7 +538,6 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
const result = await this.cctpWithdraw(params);
callback(result);
break;
break;
}
default: {
break;
-3
View File
@@ -1,3 +0,0 @@
export const hashFromTx = (
txHash: string | Uint8Array
): string => `0x${Buffer.from(txHash).toString('hex')}`;
+2 -2
View File
@@ -1,4 +1,4 @@
import { type DydxNetwork, ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { type DydxNetwork, ENVIRONMENT_CONFIG_MAP, type DydxChainId } from '@/constants/networks';
export const validateAgainstAvailableEnvironments = (value: DydxNetwork) =>
Object.keys(ENVIRONMENT_CONFIG_MAP).includes(value);
Object.keys(ENVIRONMENT_CONFIG_MAP).includes(value);
+32 -2
View File
@@ -1,6 +1,10 @@
import { Candle, TradingViewBar, TradingViewSymbol } from '@/constants/candles';
import { OrderSide } from '@dydxprotocol/v4-client-js';
import type { AppTheme, AppColorMode } from '@/state/configs';
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 { Themes } from '@/styles/themes';
@@ -47,6 +51,31 @@ export const getHistorySlice = ({
return bars.filter(({ time }) => time >= fromMs);
};
export const getChartLineColors = ({
appTheme,
appColorMode,
chartLineType,
}: {
appTheme: AppTheme;
appColorMode: AppColorMode;
chartLineType: ChartLineType;
}) => {
const theme = Themes[appTheme][appColorMode];
const orderColors = {
[OrderSide.BUY]: theme.positive,
[OrderSide.SELL]: theme.negative,
['position']: null,
};
return {
maybeQuantityColor: orderColors[chartLineType],
borderColor: theme.borderDefault,
backgroundColor: theme.layer1,
textColor: theme.textTertiary,
textButtonColor: theme.textButton,
};
};
export const getWidgetOverrides = ({
appTheme,
appColorMode,
@@ -57,6 +86,7 @@ export const getWidgetOverrides = ({
const theme = Themes[appTheme][appColorMode];
return {
theme: THEME_NAMES[appTheme],
overrides: {
'paneProperties.background': theme.layer2,
'paneProperties.horzGridProperties.color': theme.layer3,
+7
View File
@@ -0,0 +1,7 @@
import { DydxChainId, LINKS_CONFIG_MAP } from '@/constants/networks';
export const hashFromTx = (txHash: string | Uint8Array): string =>
`0x${Buffer.from(txHash).toString('hex')}`;
export const getMintscanTxLink = (dydxChainId: DydxChainId, txHash: string): string =>
`${LINKS_CONFIG_MAP[dydxChainId]?.mintscan?.replace('{tx_hash}', txHash.toString())}`;
+11 -1
View File
@@ -92,6 +92,10 @@ 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;
@@ -113,13 +117,18 @@ export const parseWalletError = ({
}) => {
const walletErrorType = getWalletErrorType({ error });
let message;
let isErrorExpected;
switch (walletErrorType) {
case WalletErrorType.ChainMismatch:
case WalletErrorType.UserCanceled: {
case WalletErrorType.UserCanceled:
case WalletErrorType.SwitchChainMethodMissing: {
isErrorExpected = true;
message = error.message;
break;
}
default: {
isErrorExpected = false;
message = stringGetter({
key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
params: {
@@ -132,5 +141,6 @@ export const parseWalletError = ({
return {
walletErrorType,
message,
isErrorExpected,
};
};
@@ -26,8 +26,6 @@ import { openDialog } from '@/state/dialogs';
import { log } from '@/lib/telemetry';
const SEASON_NUMBER = 2;
export const LaunchIncentivesPanel = ({ className }: { className?: string }) => {
const { isNotTablet } = useBreakpoints();
const dispatch = useDispatch();
@@ -74,14 +72,38 @@ const EstimatedRewards = () => {
const stringGetter = useStringGetter();
const { dydxAddress } = useAccounts();
const { data: seasonNumber } = useQuery({
queryKey: 'chaos_labs_season_number',
queryFn: async () => {
const resp = await fetch('https://cloud.chaoslabs.co/query/ccar-perpetuals', {
method: 'POST',
headers: {
'apollographql-client-name': 'dydx-v4',
'content-type': 'application/json',
protocol: 'dydx-v4',
},
body: JSON.stringify({
operationName: 'TradingSeasons',
variables: {},
query: `query TradingSeasons {
tradingSeasons {
label
}
}`,
}),
});
const seasons = (await resp.json())?.data?.tradingSeasons;
return seasons && seasons.length > 0 ? seasons[seasons.length - 1].label : undefined;
},
onError: (error: Error) => log('LaunchIncentives/fetchSeasonNumber', error),
});
const { data, isLoading } = useQuery({
enabled: !!dydxAddress,
queryKey: `launch_incentives_rewards_${dydxAddress ?? ''}_${SEASON_NUMBER}`,
queryKey: `launch_incentives_rewards_${dydxAddress ?? ''}`,
queryFn: async () => {
if (!dydxAddress) return undefined;
const resp = await fetch(
`https://cloud.chaoslabs.co/query/api/dydx/points/${dydxAddress}?n=${SEASON_NUMBER}`
);
const resp = await fetch(`https://cloud.chaoslabs.co/query/api/dydx/points/${dydxAddress}`);
return (await resp.json())?.incentivePoints;
},
onError: (error: Error) => log('LaunchIncentives/fetchPoints', error),
@@ -92,12 +114,14 @@ const EstimatedRewards = () => {
<Styled.EstimatedRewardsCardContent>
<div>
<span>{stringGetter({ key: STRING_KEYS.ESTIMATED_REWARDS })}</span>
<Styled.Season>
{stringGetter({
key: STRING_KEYS.LAUNCH_INCENTIVES_SEASON_NUM,
params: { SEASON_NUMBER },
})}
</Styled.Season>
{seasonNumber !== undefined && (
<Styled.Season>
{stringGetter({
key: STRING_KEYS.LAUNCH_INCENTIVES_SEASON_NUM,
params: { SEASON_NUMBER: seasonNumber },
})}
</Styled.Season>
)}
</div>
<Styled.Points>
+24 -1
View File
@@ -9,10 +9,13 @@ import {
HistoricalTradingRewardsPeriods,
} from '@/constants/abacus';
import { isMainnet } from '@/constants/networks';
import { STRING_KEYS } from '@/constants/localization';
import breakpoints from '@/styles/breakpoints';
import { layoutMixins } from '@/styles/layoutMixins';
import { Output, OutputType } from '@/components/Output';
import { Panel } from '@/components/Panel';
import { ToggleGroup } from '@/components/ToggleGroup';
import { WithTooltip } from '@/components/WithTooltip';
@@ -20,6 +23,9 @@ import { TradingRewardHistoryTable } from '@/views/tables/TradingRewardHistoryTa
import abacusStateManager from '@/lib/abacus';
// TODO: set in env featureFlag config
const REWARDS_HISTORY_START_DATE_MS = isMainnet ? 1706486400000 : 1704844800000;
export const RewardHistoryPanel = () => {
const stringGetter = useStringGetter();
@@ -47,7 +53,20 @@ export const RewardHistoryPanel = () => {
<WithTooltip tooltip="reward-history">
<h3>{stringGetter({ key: STRING_KEYS.REWARD_HISTORY })}</h3>
</WithTooltip>
<span>{stringGetter({ key: STRING_KEYS.REWARD_HISTORY_DESCRIPTION })}</span>
<span>
{stringGetter({
key: STRING_KEYS.REWARD_HISTORY_DESCRIPTION,
params: {
REWARDS_HISTORY_START_DATE: (
<Styled.Output
type={OutputType.Date}
value={REWARDS_HISTORY_START_DATE_MS}
timeOptions={{ useUTC: true }}
/>
),
},
})}
</span>
</Styled.Title>
<ToggleGroup
items={[
@@ -103,3 +122,7 @@ Styled.Content = styled.div`
${layoutMixins.flexColumn}
gap: 0.75rem;
`;
Styled.Output = styled(Output)`
display: inline;
`;
+6 -3
View File
@@ -1,6 +1,7 @@
import styled, { AnyStyledComponent, css } from 'styled-components';
import { useNavigate } from 'react-router-dom';
import { isMainnet } from '@/constants/networks';
import { STRING_KEYS } from '@/constants/localization';
import { AppRoute } from '@/constants/routes';
@@ -27,6 +28,8 @@ const RewardsPage = () => {
const { isTablet, isNotTablet } = useBreakpoints();
const navigate = useNavigate();
const showTradingRewards = testFlags.showTradingRewards || !isMainnet;
return (
<div>
{isTablet && (
@@ -37,7 +40,7 @@ const RewardsPage = () => {
)}
<DetachedSection>
<Styled.GridLayout
showTradingRewards={testFlags.showTradingRewards}
showTradingRewards={showTradingRewards}
showMigratePanel={import.meta.env.VITE_V3_TOKEN_ADDRESS && isNotTablet}
>
{import.meta.env.VITE_V3_TOKEN_ADDRESS && isNotTablet && <Styled.MigratePanel />}
@@ -51,7 +54,7 @@ const RewardsPage = () => {
</>
)}
{testFlags.showTradingRewards && (
{showTradingRewards && (
<Styled.TradingRewardsColumn>
<TradingRewardsSummaryPanel />
{isTablet && <RewardsHelpPanel />}
@@ -60,7 +63,7 @@ const RewardsPage = () => {
)}
{isNotTablet && (
<Styled.OtherColumn showTradingRewards={testFlags.showTradingRewards}>
<Styled.OtherColumn showTradingRewards={showTradingRewards}>
<RewardsHelpPanel />
</Styled.OtherColumn>
)}
+2 -2
View File
@@ -3,7 +3,7 @@ import { useSelector, shallowEqual } from 'react-redux';
import styled, { AnyStyledComponent } from 'styled-components';
import { STRING_KEYS } from '@/constants/localization';
import { TRADE_TYPE_STRINGS } from '@/constants/trade';
import { ORDER_TYPE_STRINGS } from '@/constants/trade';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -43,7 +43,7 @@ export const TradeDialogTrigger = () => {
<Styled.TradeSummary>
<Styled.TradeType>
<span>
{stringGetter({ key: TRADE_TYPE_STRINGS[selectedTradeType].tradeTypeKey })}
{stringGetter({ key: ORDER_TYPE_STRINGS[selectedTradeType].orderTypeKey })}
</span>
<OrderSideTag size={TagSize.Medium} orderSide={selectedOrderSide} />
</Styled.TradeType>
+4
View File
@@ -1,4 +1,8 @@
import { DydxChainId, ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import type { RootState } from './_store';
export const getApiState = (state: RootState) => state.app.apiState;
export const getSelectedNetwork = (state: RootState) => state.app.selectedNetwork;
export const getSelectedDydxChainId = (state: RootState) =>
ENVIRONMENT_CONFIG_MAP[state.app.selectedNetwork].dydxChainId as DydxChainId;
+6
View File
@@ -107,6 +107,12 @@ 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
*/
+5 -5
View File
@@ -48,12 +48,12 @@ export const DepthChartTooltipContent = ({
const depthChartSeries = nearestDatum.key as DepthChartSeries;
return {
[DepthChartSeries.Bids]: MustBigNumber(nearestDatum?.datum.price)
.minus(chartPointAtPointer.price)
.div(nearestDatum?.datum.price),
[DepthChartSeries.Asks]: MustBigNumber(chartPointAtPointer.price)
[DepthChartSeries.Bids]: MustBigNumber(midMarketPrice)
.minus(nearestDatum?.datum.price)
.div(chartPointAtPointer.price),
.div(midMarketPrice),
[DepthChartSeries.Asks]: MustBigNumber(nearestDatum?.datum.price)
.minus(midMarketPrice)
.div(midMarketPrice),
[DepthChartSeries.MidMarket]: undefined,
}[depthChartSeries];
}
+21 -54
View File
@@ -1,73 +1,40 @@
import { useEffect, useRef, useState } from 'react';
import { useRef, useState } from 'react';
import styled, { type AnyStyledComponent, css } from 'styled-components';
import { useDispatch, useSelector } from 'react-redux';
import type { IChartingLibraryWidget, ResolutionString } from 'public/tradingview/charting_library';
import type { ResolutionString } from 'public/tradingview/charting_library';
import { DEFAULT_MARKETID } from '@/constants/markets';
import { DEFAULT_RESOLUTION, RESOLUTION_CHART_CONFIGS } from '@/constants/candles';
import { useTradingView, useTradingViewTheme } from '@/hooks/tradingView';
import type { TvWidget } from '@/constants/tvchart';
import {
useChartLines,
useChartMarketAndResolution,
useTradingView,
useTradingViewTheme,
} from '@/hooks/tradingView';
import { LoadingSpace } from '@/components/Loading/LoadingSpinner';
import { setTvChartResolution } from '@/state/perpetuals';
import { getCurrentMarketId, getSelectedResolutionForMarket } from '@/state/perpetualsSelectors';
import { layoutMixins } from '@/styles/layoutMixins';
type TvWidget = IChartingLibraryWidget & { _id?: string; _ready?: boolean };
export const TvChart = () => {
const [isChartReady, setIsChartReady] = useState(false);
const dispatch = useDispatch();
const currentMarketId: string = useSelector(getCurrentMarketId) || DEFAULT_MARKETID;
const selectedResolution: string =
useSelector(getSelectedResolutionForMarket(currentMarketId)) || DEFAULT_RESOLUTION;
const tvWidgetRef = useRef<TvWidget | null>(null);
const tvWidget = tvWidgetRef.current;
const isWidgetReady = tvWidget?._ready;
const chart = isWidgetReady ? tvWidget?.chart() : undefined;
const chartResolution = chart?.resolution?.();
const { savedResolution } = useTradingView({ tvWidgetRef, setIsChartReady });
useTradingViewTheme({ tvWidget, isWidgetReady });
const displayButtonRef = useRef<HTMLElement | null>(null);
const displayButton = displayButtonRef.current;
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 });
};
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]);
const { savedResolution } = useTradingView({ tvWidgetRef, displayButtonRef, setIsChartReady });
useChartMarketAndResolution({
tvWidget,
isWidgetReady,
savedResolution: savedResolution as ResolutionString | undefined,
});
const { chartLines } = useChartLines({ tvWidget, displayButton, isChartReady });
useTradingViewTheme({ tvWidget, isWidgetReady, chartLines });
return (
<Styled.PriceChart isChartReady={isChartReady}>
@@ -32,7 +32,15 @@ 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 } from '@/state/appSelectors';
import { getSelectedNetwork, getSelectedDydxChainId } from '@/state/appSelectors';
import { track } from '@/lib/analytics';
import { isTruthy } from '@/lib/isTruthy';
@@ -44,7 +44,6 @@ export const GenerateKeys = ({
onKeysDerived = () => {},
}: ElementProps) => {
const stringGetter = useStringGetter();
const { isMobile } = useBreakpoints();
const [shouldRememberMe, setShouldRememberMe] = useState(false);
@@ -66,17 +65,30 @@ export const GenerateKeys = ({
try {
await matchNetwork?.();
return true;
} catch (error) {
const { message, walletErrorType } = parseWalletError({ error, stringGetter });
const { message, walletErrorType, isErrorExpected } = parseWalletError({
error,
stringGetter,
});
if (!isErrorExpected) {
log('GenerateKeys/switchNetwork', error, { walletErrorType });
}
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();
@@ -86,7 +98,8 @@ export const GenerateKeys = ({
EvmDerivedAccountStatus.Derived,
].includes(status);
const signTypedData = getSignTypedData(selectedNetwork);
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const signTypedData = getSignTypedData(selectedDydxChainId);
const { signTypedDataAsync } = useSignTypedData({
...signTypedData,
domain: {
@@ -154,11 +167,16 @@ export const GenerateKeys = ({
setStatus(EvmDerivedAccountStatus.Derived);
} catch (error) {
setStatus(EvmDerivedAccountStatus.NotDerived);
const { message, walletErrorType } = parseWalletError({ error, stringGetter });
const { message, walletErrorType, isErrorExpected } = parseWalletError({
error,
stringGetter,
});
if (message) {
setError(message);
log('GenerateKeys/deriveKeys', error, { walletErrorType });
if (!isErrorExpected) {
log('GenerateKeys/deriveKeys', error, { walletErrorType });
}
}
}
};
@@ -231,7 +249,7 @@ export const GenerateKeys = ({
{!isMatchingNetwork ? (
<Button
action={ButtonAction.Primary}
onClick={() => switchNetwork().then(deriveKeys).then(onKeysDerived)}
onClick={() => switchNetworkAndDeriveKeys().then(onKeysDerived)}
state={{ isLoading: isSwitchingNetwork }}
>
{stringGetter({ key: STRING_KEYS.SWITCH_NETWORK })}
+1 -1
View File
@@ -4,7 +4,7 @@ import styled, { AnyStyledComponent, css } from 'styled-components';
import { TradeInputField } from '@/constants/abacus';
import { STRING_KEYS, StringKey } from '@/constants/localization';
import { TradeTypes, TRADE_TYPE_STRINGS, MobilePlaceOrderSteps } from '@/constants/trade';
import { TradeTypes, ORDER_TYPE_STRINGS, MobilePlaceOrderSteps } from '@/constants/trade';
import { useBreakpoints, useStringGetter } from '@/hooks';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -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 { ENVIRONMENT_CONFIG_MAP, isMainnet } from '@/constants/networks';
import { isMainnet } from '@/constants/networks';
import { MAX_CCTP_TRANSFER_AMOUNT, MAX_PRICE_IMPACT, NumberSign } from '@/constants/numbers';
import type { EvmAddress } from '@/constants/wallets';
@@ -32,6 +32,7 @@ import { OutputType } from '@/components/Output';
import { Tag } from '@/components/Tag';
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
import { getSelectedDydxChainId } from '@/state/appSelectors';
import { getTransferInputs } from '@/state/inputsSelectors';
import abacusStateManager from '@/lib/abacus';
@@ -56,7 +57,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
const [error, setError] = useState<Error | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [requireUserActionInWallet, setRequireUserActionInWallet] = useState(false);
const { selectedNetwork } = useSelectedNetwork();
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const { evmAddress, signerWagmi, publicClientWagmi, nobleAddress } = useAccounts();
@@ -262,9 +263,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
if (txHash) {
addTransferNotification({
txHash: txHash,
toChainId: !isCctp
? ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId
: getNobleChainId(),
toChainId: !isCctp ? selectedDydxChainId : getNobleChainId(),
fromChainId: chainIdStr || undefined,
toAmount: summary?.usdcSize || undefined,
triggeredAt: Date.now(),
@@ -9,9 +9,14 @@ import { TransferInputField, TransferInputTokenResource, TransferType } from '@/
import { AlertType } from '@/constants/alerts';
import { ButtonSize } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { ENVIRONMENT_CONFIG_MAP, isMainnet } from '@/constants/networks';
import { isMainnet } from '@/constants/networks';
import { TransferNotificationTypes } from '@/constants/notifications';
import { MAX_CCTP_TRANSFER_AMOUNT, MAX_PRICE_IMPACT, NumberSign } from '@/constants/numbers';
import {
MAX_CCTP_TRANSFER_AMOUNT,
MAX_PRICE_IMPACT,
MIN_CCTP_TRANSFER_AMOUNT,
NumberSign,
} from '@/constants/numbers';
import {
useAccounts,
@@ -40,6 +45,7 @@ import { Icon, IconName } from '@/components/Icon';
import { SourceSelectMenu } from '@/views/forms/AccountManagementForms/SourceSelectMenu';
import { getSelectedDydxChainId } from '@/state/appSelectors';
import { getSubaccount } from '@/state/accountSelectors';
import { getTransferInputs } from '@/state/inputsSelectors';
@@ -54,7 +60,7 @@ export const WithdrawForm = () => {
const stringGetter = useStringGetter();
const [error, setError] = useState<string>();
const [isLoading, setIsLoading] = useState(false);
const { selectedNetwork } = useSelectedNetwork();
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const { sendSquidWithdraw } = useSubaccount();
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
@@ -177,9 +183,7 @@ export const WithdrawForm = () => {
addTransferNotification({
txHash: txHash,
type: TransferNotificationTypes.Withdrawal,
fromChainId: !isCctp
? ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId
: getNobleChainId(),
fromChainId: !isCctp ? selectedDydxChainId : getNobleChainId(),
toChainId: chainIdStr || undefined,
toAmount: debouncedAmountBN.toNumber(),
triggeredAt: Date.now(),
@@ -329,6 +333,12 @@ export const WithdrawForm = () => {
},
});
}
if (
!debouncedAmountBN.isZero() &&
MustBigNumber(debouncedAmountBN).lte(MIN_CCTP_TRANSFER_AMOUNT)
) {
return 'Amount must be greater than 10 USDC';
}
}
if (isMainnet && MustBigNumber(summary?.aggregatePriceImpact).gte(MAX_PRICE_IMPACT)) {
+7 -2
View File
@@ -14,6 +14,7 @@ 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';
@@ -35,7 +36,6 @@ 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,9 +291,14 @@ export const ClosePositionForm = ({
isLoading={isClosingPosition}
hasValidationErrors={hasInputErrors}
actionStringKey={inputAlert?.actionStringKey}
validationErrorString={alertContent}
summary={summary ?? undefined}
currentStep={currentStep}
isClosePosition
confirmButtonConfig={{
stringKey: STRING_KEYS.CLOSE_ORDER,
buttonTextStringKey: STRING_KEYS.CLOSE_POSITION,
buttonAction: ButtonAction.Destroy,
}}
/>
</Styled.Footer>
</Styled.ClosePositionForm>
+41 -5
View File
@@ -1,8 +1,10 @@
import { type FormEvent, useState, Ref, useCallback, useEffect } from 'react';
import { type FormEvent, useState, Ref, useCallback } 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 {
@@ -16,7 +18,12 @@ 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 } from '@/constants/trade';
import {
InputErrorData,
TradeBoxKeys,
MobilePlaceOrderSteps,
ORDER_TYPE_STRINGS,
} from '@/constants/trade';
import { breakpoints } from '@/styles';
import { useStringGetter, useSubaccount } from '@/hooks';
@@ -37,11 +44,16 @@ import { WithTooltip } from '@/components/WithTooltip';
import { Orderbook } from '@/views/tables/Orderbook';
import { setTradeFormInputs } from '@/state/inputs';
import { getCurrentInput, getTradeFormInputs, useTradeFormData } from '@/state/inputsSelectors';
import {
getCurrentInput,
getInputTradeData,
getTradeFormInputs,
useTradeFormData,
} from '@/state/inputsSelectors';
import { getCurrentMarketConfig } from '@/state/perpetualsSelectors';
import abacusStateManager from '@/lib/abacus';
import { getTradeInputAlert } from '@/lib/tradeData';
import { getSelectedOrderSide, getSelectedTradeType, getTradeInputAlert } from '@/lib/tradeData';
import { AdvancedTradeOptions } from './TradeForm/AdvancedTradeOptions';
import { TradeSizeInputs } from './TradeForm/TradeSizeInputs';
@@ -108,8 +120,21 @@ 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[] = [];
@@ -139,6 +164,11 @@ export const TradeForm = ({
alertType = inputAlert?.type;
}
const orderSideAction = {
[OrderSide.BUY]: ButtonAction.Create,
[OrderSide.SELL]: ButtonAction.Destroy,
}[selectedOrderSide];
const onSubmit = async (e: FormEvent) => {
e.preventDefault();
@@ -319,9 +349,15 @@ 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,16 +1,17 @@
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { OrderSide } from '@dydxprotocol/v4-client-js';
import { useDispatch, useSelector } from 'react-redux';
import styled, { type AnyStyledComponent, css } from 'styled-components';
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 { TRADE_TYPE_STRINGS, MobilePlaceOrderSteps } from '@/constants/trade';
import { 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';
@@ -20,30 +21,34 @@ import { OnboardingTriggerButton } from '@/views/dialogs/OnboardingTriggerButton
import { calculateCanAccountTrade } from '@/state/accountCalculators';
import { getSubaccountId } from '@/state/accountSelectors';
import { openDialog } from '@/state/dialogs';
import { getCurrentInput, getInputTradeData } from '@/state/inputsSelectors';
import { getCurrentInput } from '@/state/inputsSelectors';
import { getSelectedOrderSide, getSelectedTradeType } from '@/lib/tradeData';
type ConfirmButtonConfig = {
stringKey: string;
buttonTextStringKey: string;
buttonAction: ButtonAction;
};
type ElementProps = {
isLoading: boolean;
isClosePosition?: boolean;
actionStringKey?: string;
summary?: TradeInputSummary;
hasValidationErrors?: boolean;
validationErrorString?: string;
currentStep?: MobilePlaceOrderSteps;
showDeposit?: boolean;
showConnectWallet?: boolean;
confirmButtonConfig: ConfirmButtonConfig;
};
export const PlaceOrderButtonAndReceipt = ({
isLoading,
isClosePosition,
actionStringKey,
summary,
hasValidationErrors,
validationErrorString,
currentStep,
showDeposit,
showConnectWallet,
confirmButtonConfig,
}: ElementProps) => {
const stringGetter = useStringGetter();
const dispatch = useDispatch();
@@ -52,18 +57,12 @@ 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 = [
@@ -110,11 +109,6 @@ export const PlaceOrderButtonAndReceipt = ({
},
];
const orderSideAction = {
[OrderSide.BUY]: ButtonAction.Create,
[OrderSide.SELL]: ButtonAction.Destroy,
}[selectedOrderSide];
const buttonStatesPerStep = {
[MobilePlaceOrderSteps.EditOrder]: {
buttonTextStringKey: shouldEnableTrade
@@ -128,7 +122,7 @@ export const PlaceOrderButtonAndReceipt = ({
[MobilePlaceOrderSteps.PreviewOrder]: {
buttonTextStringKey: STRING_KEYS.CONFIRM_ORDER,
buttonAction: isClosePosition ? ButtonAction.Destroy : orderSideAction,
buttonAction: confirmButtonConfig.buttonAction,
buttonState: { isLoading },
},
[MobilePlaceOrderSteps.PlacingOrder]: {
@@ -145,15 +139,13 @@ export const PlaceOrderButtonAndReceipt = ({
const buttonAction = currentStep
? buttonStatesPerStep[currentStep].buttonAction
: isClosePosition
? ButtonAction.Destroy
: orderSideAction;
: confirmButtonConfig.buttonAction;
let buttonTextStringKey = STRING_KEYS.UNAVAILABLE;
if (currentStep) {
buttonTextStringKey = buttonStatesPerStep[currentStep].buttonTextStringKey;
} else if (shouldEnableTrade) {
buttonTextStringKey = isClosePosition ? STRING_KEYS.CLOSE_POSITION : STRING_KEYS.PLACE_ORDER;
buttonTextStringKey = confirmButtonConfig.buttonTextStringKey;
} else if (actionStringKey) {
buttonTextStringKey = actionStringKey;
}
@@ -165,31 +157,56 @@ 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 || showConnectWallet ? (
{!canAccountTrade ? (
<OnboardingTriggerButton size={ButtonSize.Base} />
) : showDeposit ? (
<Button
action={ButtonAction.Primary}
onClick={() => dispatch(openDialog({ type: DialogTypes.Deposit }))}
>
{stringGetter({ key: STRING_KEYS.DEPOSIT_FUNDS })}
</Button>
depositButton
) : (
<Button state={buttonState} type={ButtonType.Submit} action={buttonAction}>
{stringGetter({
key: buttonTextStringKey,
params: {
ORDER: stringGetter({
key: isClosePosition
? STRING_KEYS.CLOSE_ORDER
: TRADE_TYPE_STRINGS[selectedTradeType].tradeTypeKey,
}),
},
})}
</Button>
<WithTooltip tooltipString={hasValidationErrors ? validationErrorString : undefined}>
{submitButton}
</WithTooltip>
)}
</WithDetailsReceipt>
);
};
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Button = styled(Button)`
width: 100%;
`;
Styled.WarningIcon = styled(Icon)`
color: var(--color-warning);
`;
+4 -5
View File
@@ -9,7 +9,6 @@ import { TransferInputField, TransferType } from '@/constants/abacus';
import { AlertType } from '@/constants/alerts';
import { ButtonShape, ButtonSize } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { NumberSign } from '@/constants/numbers';
import { DydxChainAsset } from '@/constants/wallets';
@@ -18,7 +17,6 @@ import {
useAccounts,
useDydxClient,
useRestrictions,
useSelectedNetwork,
useStringGetter,
useSubaccount,
useTokenConfigs,
@@ -41,6 +39,7 @@ import { TransferButtonAndReceipt } from '@/views/forms/TransferForm/TransferBut
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
import { getSubaccount } from '@/state/accountSelectors';
import { getSelectedDydxChainId } from '@/state/appSelectors';
import { getTransferInputs } from '@/state/inputsSelectors';
import abacusStateManager from '@/lib/abacus';
@@ -63,7 +62,7 @@ export const TransferForm = ({
const { dydxAddress } = useAccounts();
const { transfer } = useSubaccount();
const { nativeTokenBalance, usdcBalance } = useAccountBalance();
const { selectedNetwork } = useSelectedNetwork();
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const { tokensConfigs, usdcLabel, chainTokenLabel } = useTokenConfigs();
const {
@@ -239,7 +238,7 @@ export const TransferForm = ({
const networkOptions = [
{
chainId: ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId,
chainId: selectedDydxChainId,
label: (
<Styled.InlineRow>
<AssetIcon symbol="DYDX" /> {stringGetter({ key: STRING_KEYS.DYDX_CHAIN })}
@@ -322,7 +321,7 @@ export const TransferForm = ({
/>
<Styled.NetworkSelectMenu
label={stringGetter({ key: STRING_KEYS.NETWORK })}
value={ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId}
value={selectedDydxChainId}
slotTriggerAfter={null}
>
{networkOptions.map(({ chainId, label }) => (
@@ -11,7 +11,7 @@ import {
} from '@/constants/abacus';
import { STRING_KEYS } from '@/constants/localization';
import { TRADE_TYPE_STRINGS, TradeTypes } from '@/constants/trade';
import { ORDER_TYPE_STRINGS, TradeTypes } from '@/constants/trade';
import { useStringGetter } from '@/hooks';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -48,7 +48,7 @@ export const TradeNotification = ({ isToast, data, notification }: TradeNotifica
const { assetId } = marketData ?? {};
const orderType = ORDER_TYPE as KotlinIrEnumValues<typeof AbacusOrderType>;
const tradeType = TRADE_TYPES[orderType];
const titleKey = tradeType && TRADE_TYPE_STRINGS[tradeType]?.tradeTypeKey;
const titleKey = tradeType && ORDER_TYPE_STRINGS[tradeType]?.orderTypeKey;
const orderStatus = ORDER_STATUS as KotlinIrEnumValues<typeof AbacusOrderStatus>;
return (
@@ -1,18 +1,21 @@
import { useMemo } from 'react';
import { useSelector } from 'react-redux';
import styled, { css, type AnyStyledComponent } from 'styled-components';
import { StatusResponse } from '@0xsquid/sdk';
import { useStringGetter, useSelectedNetwork, useURLConfigs } from '@/hooks';
import { STRING_KEYS } from '@/constants/localization';
import { TransferNotificationTypes } from '@/constants/notifications';
import { useStringGetter, useURLConfigs } from '@/hooks';
import { layoutMixins } from '@/styles/layoutMixins';
import { Link } from '@/components/Link';
import { Icon, IconName } from '@/components/Icon';
import { LoadingDots } from '@/components/Loading/LoadingDots';
import { LoadingSpinner } from '@/components/Loading/LoadingSpinner';
import { layoutMixins } from '@/styles/layoutMixins';
import { STRING_KEYS } from '@/constants/localization';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { TransferNotificationTypes } from '@/constants/notifications';
import { getSelectedDydxChainId } from '@/state/appSelectors';
type ElementProps = {
status?: StatusResponse;
@@ -32,9 +35,8 @@ enum TransferStatusStep {
export const TransferStatusSteps = ({ className, status, type }: ElementProps & StyleProps) => {
const stringGetter = useStringGetter();
const { selectedNetwork } = useSelectedNetwork();
const selectedDydxChainId = useSelector(getSelectedDydxChainId);
const { mintscan: mintscanTxUrl } = useURLConfigs();
const dydxChainId = ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId;
const { currentStep, steps } = useMemo(() => {
const routeStatus = status?.routeStatus;
@@ -55,7 +57,7 @@ export const TransferStatusSteps = ({ className, status, type }: ElementProps &
link:
type === TransferNotificationTypes.Deposit
? status?.fromChain?.transactionUrl
: routeStatus?.[0]?.chainId === dydxChainId && routeStatus[0].txHash
: routeStatus?.[0]?.chainId === selectedDydxChainId && routeStatus[0].txHash
? `${mintscanTxUrl?.replace('{tx_hash}', routeStatus[0].txHash.replace('0x', ''))}`
: undefined,
},
@@ -81,7 +83,7 @@ export const TransferStatusSteps = ({ className, status, type }: ElementProps &
link:
type === TransferNotificationTypes.Withdrawal
? status?.toChain?.transactionUrl
: currentStatus?.chainId === dydxChainId && currentStatus?.txHash
: currentStatus?.chainId === selectedDydxChainId && currentStatus?.txHash
? `${mintscanTxUrl?.replace('{tx_hash}', currentStatus.txHash.replace('0x', ''))}`
: undefined,
},
Binary file not shown.