From 793b522487e06499b3fccc8b30ea267c432e90ea Mon Sep 17 00:00:00 2001 From: Jared Vu Date: Tue, 30 Jan 2024 11:59:16 -0800 Subject: [PATCH] New Market Widget (#234) * :construction: New Market Form * use dev-5 as default * Additional UI work * Add mock data * :lipstick: More UI items * :lipstick: add preview step * :lipstick: Disable proposal button if not enough native tokens * :pencil2: Add disclaimer * :pencil2: fix combobox search * :construction: clean up components * Add filters, modify, button * :sparkles: feat: Add details to New Market Dialog * add assetName * add helper method - spagetti code * Update NewMarketMessageDetailsDialog, attempt to hook up client call * :rotating_light: fix mobile safari overflow * update init deposit to 10_001 whole token * reduce delay block to 5 * Update mock data * :construction: SO FRIGGIN CLOSE * :lipstick: style/ux nits * add gov to registry * PLS * IT FUCKING WORKS * Add assets * FIX TICKER * ADD NEW ASSETICON * button width * change default env to dev * Remove mention of Impersonation dialog * Market Search entry point * uncomment feature * Clean up NewMarketStep components * Restore env.json * Add space T.T * useGlobalCommands fix types * :construction: feat: useNextClobPairId hook WIP * Add potentialMarkets hook to parse CSV and hide new market entrypoints * Use updated stringKeys * Update localization, import nits * bump v4-client * add gov vars * new useGovernanceVariables * Add validator client calls: proposal fetch/submission * Update token usage, utilize gov vars * remove console log * import nits * NewMarketMessageDetailsDialog: Fix initial_deposit_amount * NewMarketAgreement Dialog * confirm flow * Remove initialDepositAmount from mainnet env * NewMarket: Add stringParams to step3 * Update csv * update env.json add localization changes * cleanup initialDepositAmountBN and decimals * ^ * use undefined in place of 0 for DiffOutput * remove hardcoded string * Remove potentialMarket from csv * Ensure user is out of liquidity tier modification * bump localization, add additional details to receipts * feedback addressed * Add margin instead of space * margin/padding nits, shorten filter method, remove ?. chaining * additional feedback --------- Co-authored-by: Taehoon Lee <19664986+ttl33@users.noreply.github.com> --- package.json | 5 +- pnpm-lock.yaml | 186 ++--- public/configs/env.json | 118 ++- public/configs/markets.json | 7 + .../configs/potentialMarketExchangeConfig.csv | 704 ++++++++++++++++++ public/configs/potentialMarketParameters.csv | 68 ++ public/currencies/bonk.png | Bin 0 -> 112037 bytes src/App.tsx | 10 +- src/components/AssetIcon.tsx | 1 + src/components/ComboboxMenu.tsx | 5 +- src/components/FormInput.tsx | 6 +- src/components/Loading/LoadingSpinner.tsx | 1 + src/components/Output.tsx | 1 + src/components/WithDetailsReceipt.tsx | 2 +- src/constants/dialogs.ts | 2 + src/constants/indexer.ts | 23 + src/constants/potentialMarkets.ts | 85 +++ src/constants/routes.ts | 4 + src/constants/tooltips/trade.ts | 7 +- src/hooks/index.ts | 4 + src/hooks/useDydxClient.tsx | 48 +- src/hooks/useGovernanceVariables.ts | 16 + src/hooks/useNextClobPairId.ts | 118 +++ src/hooks/usePotentialMarkets.tsx | 135 ++++ src/hooks/useSubaccount.tsx | 55 +- src/layout/DialogManager.tsx | 4 + src/lib/csvToArray.ts | 16 + src/pages/markets/Markets.tsx | 15 +- src/pages/markets/NewMarket.tsx | 259 +++++++ src/pages/rewards/NewMarketsPanel.tsx | 103 +++ src/pages/rewards/RewardsPage.tsx | 5 +- src/views/MarketsDropdown.tsx | 33 +- .../dialogs/NewMarketAgreementDialog.tsx | 105 +++ .../dialogs/NewMarketMessageDetailsDialog.tsx | 361 +++++++++ .../NewMarketForm/NewMarketPreviewStep.tsx | 396 ++++++++++ .../NewMarketForm/NewMarketSelectionStep.tsx | 466 ++++++++++++ .../NewMarketForm/NewMarketSuccessStep.tsx | 81 ++ src/views/forms/NewMarketForm/index.tsx | 80 ++ src/views/menus/useGlobalCommands.tsx | 9 +- 39 files changed, 3397 insertions(+), 147 deletions(-) create mode 100644 public/configs/potentialMarketExchangeConfig.csv create mode 100644 public/configs/potentialMarketParameters.csv create mode 100644 public/currencies/bonk.png create mode 100644 src/constants/indexer.ts create mode 100644 src/constants/potentialMarkets.ts create mode 100644 src/hooks/useGovernanceVariables.ts create mode 100644 src/hooks/useNextClobPairId.ts create mode 100644 src/hooks/usePotentialMarkets.tsx create mode 100644 src/lib/csvToArray.ts create mode 100644 src/pages/markets/NewMarket.tsx create mode 100644 src/pages/rewards/NewMarketsPanel.tsx create mode 100644 src/views/dialogs/NewMarketAgreementDialog.tsx create mode 100644 src/views/dialogs/NewMarketMessageDetailsDialog.tsx create mode 100644 src/views/forms/NewMarketForm/NewMarketPreviewStep.tsx create mode 100644 src/views/forms/NewMarketForm/NewMarketSelectionStep.tsx create mode 100644 src/views/forms/NewMarketForm/NewMarketSuccessStep.tsx create mode 100644 src/views/forms/NewMarketForm/index.tsx diff --git a/package.json b/package.json index 19c4fb8..23e4030 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@cosmjs/tendermint-rpc": "^0.32.1", "@dydxprotocol/v4-abacus": "^1.3.2", "@dydxprotocol/v4-client-js": "^1.0.17", - "@dydxprotocol/v4-localization": "^1.1.17", + "@dydxprotocol/v4-localization": "^1.1.19", "@ethersproject/providers": "^5.7.2", "@js-joda/core": "^5.5.3", "@radix-ui/react-accordion": "^1.1.2", @@ -92,6 +92,7 @@ "buffer": "^6.0.3", "cmdk": "^0.2.0", "color": "^4.2.3", + "cosmjs-types": "^0.9.0", "crypto-js": "^4.1.1", "ethers": "^6.6.1", "graz": "^0.0.43", @@ -161,4 +162,4 @@ "follow-redirects": "1.15.3" } } -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c41990a..684cfd2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + overrides: follow-redirects: 1.15.3 @@ -9,22 +13,22 @@ dependencies: version: 1.10.0 '@cosmjs/amino': specifier: ^0.32.1 - version: 0.32.2 + version: 0.32.1 '@cosmjs/crypto': specifier: ^0.32.1 - version: 0.32.2 + version: 0.32.1 '@cosmjs/encoding': specifier: ^0.32.1 - version: 0.32.2 + version: 0.32.1 '@cosmjs/proto-signing': specifier: ^0.32.1 - version: 0.32.2 + version: 0.32.1 '@cosmjs/stargate': specifier: ^0.32.1 - version: 0.32.2 + version: 0.32.1 '@cosmjs/tendermint-rpc': specifier: ^0.32.1 - version: 0.32.2 + version: 0.32.1 '@dydxprotocol/v4-abacus': specifier: ^1.3.2 version: 1.3.2 @@ -32,8 +36,8 @@ dependencies: specifier: ^1.0.17 version: 1.0.17 '@dydxprotocol/v4-localization': - specifier: ^1.1.17 - version: 1.1.17 + specifier: ^1.1.19 + version: 1.1.19 '@ethersproject/providers': specifier: ^5.7.2 version: 5.7.2 @@ -184,6 +188,9 @@ dependencies: color: specifier: ^4.2.3 version: 4.2.3 + cosmjs-types: + specifier: ^0.9.0 + version: 0.9.0 crypto-js: specifier: ^4.1.1 version: 4.1.1 @@ -375,7 +382,7 @@ packages: /@0xsquid/sdk@1.10.0: resolution: {integrity: sha512-NKxHYB+g/TMPY+XmCHs+LuhyfbhH4KvAbGpVBOBPXM9Q5FsKcKrDJpTd5YnGYCLF9B3qXAzVTR0XhiC73GmOOA==} dependencies: - '@cosmjs/encoding': 0.31.0 + '@cosmjs/encoding': 0.31.1 '@cosmjs/stargate': 0.31.0 axios: 0.27.2 cosmjs-types: 0.8.0 @@ -682,16 +689,16 @@ packages: resolution: {integrity: sha512-xJ5CCEK7H79FTpOuEmlpSzVI+ZeYESTVvO3wHDgbnceIyAne3C68SvyaKqLUR4uJB0Z4q4+DZHbqW6itUiv4lA==} dependencies: '@cosmjs/crypto': 0.31.0 - '@cosmjs/encoding': 0.31.0 - '@cosmjs/math': 0.31.0 - '@cosmjs/utils': 0.31.0 + '@cosmjs/encoding': 0.31.1 + '@cosmjs/math': 0.31.1 + '@cosmjs/utils': 0.31.1 dev: false - /@cosmjs/amino@0.32.2: - resolution: {integrity: sha512-lcK5RCVm4OfdAooxKcF2+NwaDVVpghOq6o/A40c2mHXDUzUoRZ33VAHjVJ9Me6vOFxshrw/XEFn1f4KObntjYA==} + /@cosmjs/amino@0.32.1: + resolution: {integrity: sha512-5l2xQ2XuAhV/B3kTIMPBcVZ/OQ+9Yyddzw/lIVs4qE5e/oBI0PVNWXw1oyR0wgfGHrMUxgKjsoOOqE2IbXVyCw==} dependencies: - '@cosmjs/crypto': 0.32.2 - '@cosmjs/encoding': 0.32.2 + '@cosmjs/crypto': 0.32.1 + '@cosmjs/encoding': 0.32.1 '@cosmjs/math': 0.32.2 '@cosmjs/utils': 0.32.2 dev: false @@ -746,19 +753,19 @@ packages: /@cosmjs/crypto@0.31.0: resolution: {integrity: sha512-UaqCe6Tgh0pe1QlZ66E13t6FlIF86QrnBXXq+EN7Xe1Rouza3fJ1ojGlPleJZkBoq3tAyYVIOOqdZIxtVj/sIQ==} dependencies: - '@cosmjs/encoding': 0.31.0 - '@cosmjs/math': 0.31.0 - '@cosmjs/utils': 0.31.0 + '@cosmjs/encoding': 0.31.1 + '@cosmjs/math': 0.31.1 + '@cosmjs/utils': 0.31.1 '@noble/hashes': 1.3.3 bn.js: 5.2.1 elliptic: 6.5.4 libsodium-wrappers-sumo: 0.7.11 dev: false - /@cosmjs/crypto@0.32.2: - resolution: {integrity: sha512-RuxrYKzhrPF9g6NmU7VEq++Hn1vZJjqqJpZ9Tmw9lOYOV8BUsv+j/0BE86kmWi7xVJ7EwxiuxYsKuM8IR18CIA==} + /@cosmjs/crypto@0.32.1: + resolution: {integrity: sha512-AsKucEg5o8evU0wXF/lDwX+ZSwCKF4bbc57nFzraHywlp3sNu4dfPPURoMrT0r7kT7wQZAy4Pdnvmm9nnCCm/Q==} dependencies: - '@cosmjs/encoding': 0.32.2 + '@cosmjs/encoding': 0.32.1 '@cosmjs/math': 0.32.2 '@cosmjs/utils': 0.32.2 '@noble/hashes': 1.3.3 @@ -783,16 +790,16 @@ packages: readonly-date: 1.0.0 dev: false - /@cosmjs/encoding@0.31.0: - resolution: {integrity: sha512-NYGQDRxT7MIRSlcbAezwxK0FqnaSPKCH7O32cmfpHNWorFxhy9lwmBoCvoe59Kd0HmArI4h+NGzLEfX3OLnA4Q==} + /@cosmjs/encoding@0.31.1: + resolution: {integrity: sha512-IuxP6ewwX6vg9sUJ8ocJD92pkerI4lyG8J5ynAM3NaX3q+n+uMoPRSQXNeL9bnlrv01FF1kIm8if/f5F7ZPtkA==} dependencies: base64-js: 1.5.1 bech32: 1.1.4 readonly-date: 1.0.0 dev: false - /@cosmjs/encoding@0.32.2: - resolution: {integrity: sha512-WX7m1wLpA9V/zH0zRcz4EmgZdAv1F44g4dbXOgNj1eXZw1PIGR12p58OEkLN51Ha3S4DKRtCv5CkhK1KHEvQtg==} + /@cosmjs/encoding@0.32.1: + resolution: {integrity: sha512-x60Lfds+Eq42rVV29NaoIAson3kBhATBI3zPp7X3GJTryBc5HFHQ6L/976tE1WB2DrvkfUdWS3ayCMVOY/qm1g==} dependencies: base64-js: 1.5.1 bech32: 1.1.4 @@ -852,6 +859,12 @@ packages: bn.js: 5.2.1 dev: false + /@cosmjs/math@0.31.1: + resolution: {integrity: sha512-kiuHV6m6DSB8/4UV1qpFhlc4ul8SgLXTGRlYkYiIIP4l0YNeJ+OpPYaOlEgx4Unk2mW3/O2FWYj7Jc93+BWXng==} + dependencies: + bn.js: 5.2.1 + dev: false + /@cosmjs/math@0.32.2: resolution: {integrity: sha512-b8+ruAAY8aKtVKWSft2IvtCVCUH1LigIlf9ALIiY8n9jtM4kMASiaRbQ/27etnSAInV88IaezKK9rQZrtxTjcw==} dependencies: @@ -875,19 +888,19 @@ packages: dependencies: '@cosmjs/amino': 0.31.0 '@cosmjs/crypto': 0.31.0 - '@cosmjs/encoding': 0.31.0 - '@cosmjs/math': 0.31.0 - '@cosmjs/utils': 0.31.0 + '@cosmjs/encoding': 0.31.1 + '@cosmjs/math': 0.31.1 + '@cosmjs/utils': 0.31.1 cosmjs-types: 0.8.0 long: 4.0.0 dev: false - /@cosmjs/proto-signing@0.32.2: - resolution: {integrity: sha512-UV4WwkE3W3G3s7wwU9rizNcUEz2g0W8jQZS5J6/3fiN0mRPwtPKQ6EinPN9ASqcAJ7/VQH4/9EPOw7d6XQGnqw==} + /@cosmjs/proto-signing@0.32.1: + resolution: {integrity: sha512-IHJMXQ8XnfzR5K1hWb8VV/jEfJof6BL2mgGIA7X4hSPegwoVfb9hnFKPEPgFjGCTTvGZ8SfnCdXxpsOjianVIA==} dependencies: - '@cosmjs/amino': 0.32.2 - '@cosmjs/crypto': 0.32.2 - '@cosmjs/encoding': 0.32.2 + '@cosmjs/amino': 0.32.1 + '@cosmjs/crypto': 0.32.1 + '@cosmjs/encoding': 0.32.1 '@cosmjs/math': 0.32.2 '@cosmjs/utils': 0.32.2 cosmjs-types: 0.9.0 @@ -955,7 +968,7 @@ packages: dependencies: '@confio/ics23': 0.6.8 '@cosmjs/amino': 0.31.0 - '@cosmjs/encoding': 0.31.0 + '@cosmjs/encoding': 0.31.1 '@cosmjs/math': 0.31.0 '@cosmjs/proto-signing': 0.31.0 '@cosmjs/stream': 0.31.0 @@ -971,16 +984,16 @@ packages: - utf-8-validate dev: false - /@cosmjs/stargate@0.32.2: - resolution: {integrity: sha512-AsJa29fT7Jd4xt9Ai+HMqhyj7UQu7fyYKdXj/8+/9PD74xe6lZSYhQPcitUmMLJ1ckKPgXSk5Dd2LbsQT0IhZg==} + /@cosmjs/stargate@0.32.1: + resolution: {integrity: sha512-S0E1qKQ2CMJU79G8bQTquTyrbU03gFsvCkbo3RvK8v2OltVCByjFNh+0nGN5do+uDOzwwmDvnNLhR+SaIyNQoQ==} dependencies: '@confio/ics23': 0.6.8 - '@cosmjs/amino': 0.32.2 - '@cosmjs/encoding': 0.32.2 + '@cosmjs/amino': 0.32.1 + '@cosmjs/encoding': 0.32.1 '@cosmjs/math': 0.32.2 - '@cosmjs/proto-signing': 0.32.2 + '@cosmjs/proto-signing': 0.32.1 '@cosmjs/stream': 0.32.2 - '@cosmjs/tendermint-rpc': 0.32.2 + '@cosmjs/tendermint-rpc': 0.32.1 '@cosmjs/utils': 0.32.2 cosmjs-types: 0.9.0 xstream: 11.14.0 @@ -1031,12 +1044,12 @@ packages: resolution: {integrity: sha512-yo9xbeuI6UoEKIhFZ9g0dvUKLqnBzwdpEc/uldQygQc51j38gQVwFko+6sjmhieJqRYYvrYumcbJMiV6GFM9aA==} dependencies: '@cosmjs/crypto': 0.31.0 - '@cosmjs/encoding': 0.31.0 + '@cosmjs/encoding': 0.31.1 '@cosmjs/json-rpc': 0.31.0 - '@cosmjs/math': 0.31.0 + '@cosmjs/math': 0.31.1 '@cosmjs/socket': 0.31.0 '@cosmjs/stream': 0.31.0 - '@cosmjs/utils': 0.31.0 + '@cosmjs/utils': 0.31.1 axios: 0.21.4 readonly-date: 1.0.0 xstream: 11.14.0 @@ -1046,11 +1059,11 @@ packages: - utf-8-validate dev: false - /@cosmjs/tendermint-rpc@0.32.2: - resolution: {integrity: sha512-DXyJHDmcAfCix4H/7/dKR0UMdshP01KxJOXHdHxBCbLIpck94BsWD3B2ZTXwfA6sv98so9wOzhp7qGQa5malxg==} + /@cosmjs/tendermint-rpc@0.32.1: + resolution: {integrity: sha512-4uGSxB2JejWhwBUgxca4GqcK/BGnCFMIP7ptwEledrC3AY/shPeIYcPXWEBwO7sfwCta8DhAOCLrc9zhVC+VAQ==} dependencies: - '@cosmjs/crypto': 0.32.2 - '@cosmjs/encoding': 0.32.2 + '@cosmjs/crypto': 0.32.1 + '@cosmjs/encoding': 0.32.1 '@cosmjs/json-rpc': 0.32.2 '@cosmjs/math': 0.32.2 '@cosmjs/socket': 0.32.2 @@ -1077,6 +1090,10 @@ packages: resolution: {integrity: sha512-nNcycZWUYLNJlrIXgpcgVRqdl6BXjF4YlXdxobQWpW9Tikk61bEGeAFhDYtC0PwHlokCNw0KxWiHGJL4nL7Q5A==} dev: false + /@cosmjs/utils@0.31.1: + resolution: {integrity: sha512-n4Se1wu4GnKwztQHNFfJvUeWcpvx3o8cWhSbNs9JQShEuB3nv3R5lqFBtDCgHZF/emFQAP+ZjF8bTfCs9UBGhA==} + dev: false + /@cosmjs/utils@0.32.2: resolution: {integrity: sha512-Gg5t+eR7vPJMAmhkFt6CZrzPd0EKpAslWwk5rFVYZpJsM8JG5KT9XQ99hgNM3Ov6ScNoIWbXkpX27F6A9cXR4Q==} dev: false @@ -1092,22 +1109,22 @@ packages: /@dydxprotocol/v4-client-js@1.0.17: resolution: {integrity: sha512-PbTKbzcS7VapuFRofkirUxkF9ThNS2tWYyr0asFOMUfebsQWMvTC1sYC/s1NZIiBeq3cFz9vKdZFbfsKi7Z1bw==} dependencies: - '@cosmjs/amino': 0.32.2 - '@cosmjs/encoding': 0.32.2 + '@cosmjs/amino': 0.32.1 + '@cosmjs/encoding': 0.32.1 '@cosmjs/math': 0.32.2 - '@cosmjs/proto-signing': 0.32.2 - '@cosmjs/stargate': 0.32.2 - '@cosmjs/tendermint-rpc': 0.32.2 + '@cosmjs/proto-signing': 0.32.1 + '@cosmjs/stargate': 0.32.1 + '@cosmjs/tendermint-rpc': 0.32.1 '@cosmjs/utils': 0.32.2 '@dydxprotocol/v4-proto': 3.0.0-dev.0 '@osmonauts/lcd': 0.6.0 - '@scure/bip32': 1.3.2 - '@scure/bip39': 1.2.1 + '@scure/bip32': 1.3.3 + '@scure/bip39': 1.2.2 axios: 1.1.3 bech32: 1.1.4 bignumber.js: 9.1.1 cosmjs-types: 0.9.0 - ethereum-cryptography: 2.1.2 + ethereum-cryptography: 2.1.3 ethers: 6.6.1 long: 4.0.0 protobufjs: 6.11.4 @@ -1118,8 +1135,8 @@ packages: - utf-8-validate dev: false - /@dydxprotocol/v4-localization@1.1.17: - resolution: {integrity: sha512-kal1LrcihLMEv5YxaA/hd6Zl10Mp3x6jicoXDcXvtyNdrczAl3YapyI2nmeifRAPvfueOaY3W/sKkm2BiSKSsA==} + /@dydxprotocol/v4-localization@1.1.19: + resolution: {integrity: sha512-EA0J5dXyjFoAuSaEYOt066wEMJAXpSb1+ByAcxnEW1PbRznJ9LwrwNDlRtHQk0lkcWC5vdi+UtmSV8D2TsS+vQ==} dev: false /@dydxprotocol/v4-proto@3.0.0-dev.0: @@ -2141,18 +2158,18 @@ packages: '@noble/hashes': 1.3.0 dev: false - /@noble/curves@1.1.0: - resolution: {integrity: sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==} - dependencies: - '@noble/hashes': 1.3.1 - dev: false - /@noble/curves@1.2.0: resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} dependencies: '@noble/hashes': 1.3.2 dev: false + /@noble/curves@1.3.0: + resolution: {integrity: sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==} + dependencies: + '@noble/hashes': 1.3.3 + dev: false + /@noble/ed25519@1.7.3: resolution: {integrity: sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==} dev: true @@ -5018,14 +5035,6 @@ packages: '@scure/base': 1.1.1 dev: false - /@scure/bip32@1.3.1: - resolution: {integrity: sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==} - dependencies: - '@noble/curves': 1.1.0 - '@noble/hashes': 1.3.3 - '@scure/base': 1.1.5 - dev: false - /@scure/bip32@1.3.2: resolution: {integrity: sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==} dependencies: @@ -5034,6 +5043,14 @@ packages: '@scure/base': 1.1.5 dev: false + /@scure/bip32@1.3.3: + resolution: {integrity: sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==} + dependencies: + '@noble/curves': 1.3.0 + '@noble/hashes': 1.3.3 + '@scure/base': 1.1.5 + dev: false + /@scure/bip39@1.2.0: resolution: {integrity: sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==} dependencies: @@ -5048,6 +5065,13 @@ packages: '@scure/base': 1.1.5 dev: false + /@scure/bip39@1.2.2: + resolution: {integrity: sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==} + dependencies: + '@noble/hashes': 1.3.3 + '@scure/base': 1.1.5 + dev: false + /@solana/buffer-layout@4.0.1: resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} engines: {node: '>=5.10'} @@ -5059,7 +5083,7 @@ packages: resolution: {integrity: sha512-up5VG1dK+GPhykmuMIozJZBbVqpm77vbOG6/r5dS7NBGZonwHfTLdBbsYc3rjmaQ4DpCXUa3tUc4RZHRORvZrw==} dependencies: '@babel/runtime': 7.22.10 - '@noble/curves': 1.2.0 + '@noble/curves': 1.3.0 '@noble/hashes': 1.3.3 '@solana/buffer-layout': 4.0.1 agentkeepalive: 4.5.0 @@ -9283,13 +9307,13 @@ packages: fast-safe-stringify: 2.1.1 dev: false - /ethereum-cryptography@2.1.2: - resolution: {integrity: sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==} + /ethereum-cryptography@2.1.3: + resolution: {integrity: sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==} dependencies: - '@noble/curves': 1.1.0 - '@noble/hashes': 1.3.1 - '@scure/bip32': 1.3.1 - '@scure/bip39': 1.2.1 + '@noble/curves': 1.3.0 + '@noble/hashes': 1.3.3 + '@scure/bip32': 1.3.3 + '@scure/bip39': 1.2.2 dev: false /ethers@5.7.2: @@ -14909,7 +14933,3 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} dev: true - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false diff --git a/public/configs/env.json b/public/configs/env.json index e4ef9ba..ce84f7a 100644 --- a/public/configs/env.json +++ b/public/configs/env.json @@ -88,7 +88,6 @@ "blogs": "https://www.dydx.foundation/blog", "foundation": "https://www.dydx.foundation", "help": "https://help.dydx.exchange/", - "initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes", "reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders", "mintscanBase": "https://testnet.mintscan.io/dydx-testnet", "documentation": "https://docs.dydx.exchange/", @@ -116,6 +115,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX Chain" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-dev-2": { @@ -161,7 +167,6 @@ "blogs": "https://www.dydx.foundation/blog", "foundation": "https://www.dydx.foundation", "help": "https://help.dydx.exchange/", - "initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes", "reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders", "mintscanBase": "https://testnet.mintscan.io/dydx-testnet", "documentation": "https://docs.dydx.exchange/", @@ -189,6 +194,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX Chain" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-dev-4": { @@ -235,7 +247,6 @@ "blogs": "https://www.dydx.foundation/blog", "foundation": "https://www.dydx.foundation", "help": "https://help.dydx.exchange/", - "initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes", "reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders", "mintscanBase": "https://testnet.mintscan.io/dydx-testnet", "documentation": "https://docs.dydx.exchange/", @@ -263,6 +274,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX Chain" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-dev-5": { @@ -308,7 +326,6 @@ "blogs": "https://www.dydx.foundation/blog", "foundation": "https://www.dydx.foundation", "help": "https://help.dydx.exchange/", - "initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes", "reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders", "mintscanBase": "https://testnet.mintscan.io/dydx-testnet", "documentation": "https://docs.dydx.exchange/", @@ -336,6 +353,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX Chain" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-staging": { @@ -385,7 +409,6 @@ "blogs": "https://www.dydx.foundation/blog", "help": "https://help.dydx.exchange", "foundation": "https://www.dydx.foundation", - "initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes", "reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders", "mintscanBase": "https://testnet.mintscan.io/dydx-testnet", "governanceLearnMore": "https://help.dydx.exchange", @@ -411,6 +434,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX Chain" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-staging-forced-update": { @@ -484,6 +514,13 @@ "build": 40000, "url": "https://apps.apple.com/app/dydx/id1564787350" } + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-staging-west": { @@ -533,7 +570,6 @@ "blogs": "https://www.dydx.foundation/blog", "help": "https://help.dydx.exchange", "foundation": "https://www.dydx.foundation", - "initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes", "reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders", "mintscanBase": "https://testnet.mintscan.io/dydx-testnet", "governanceLearnMore": "https://help.dydx.exchange", @@ -559,6 +595,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX Chain" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-testnet": { @@ -612,7 +655,6 @@ "blogs": "https://www.dydx.foundation/blog", "foundation": "https://www.dydx.foundation", "help": "https://help.dydx.exchange/", - "initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes", "reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders", "mintscanBase": "https://testnet.mintscan.io/dydx-testnet", "governanceLearnMore": "https://help.dydx.exchange", @@ -638,6 +680,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX V4" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-testnet-dydx": { @@ -688,7 +737,6 @@ "blogs": "https://www.dydx.foundation/blog", "foundation": "https://www.dydx.foundation", "help": "https://help.dydx.exchange/", - "initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes", "reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders", "mintscanBase": "https://testnet.mintscan.io/dydx-testnet", "governanceLearnMore": "https://help.dydx.exchange", @@ -714,6 +762,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX V4" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-testnet-nodefleet": { @@ -764,7 +819,6 @@ "blogs": "https://www.dydx.foundation/blog", "foundation": "https://www.dydx.foundation", "help": "https://help.dydx.exchange/", - "initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes", "reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders", "mintscanBase": "https://testnet.mintscan.io/dydx-testnet", "governanceLearnMore": "https://help.dydx.exchange", @@ -790,6 +844,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX V4" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-testnet-kingnodes": { @@ -840,7 +901,6 @@ "blogs": "https://www.dydx.foundation/blog", "foundation": "https://www.dydx.foundation", "help": "https://help.dydx.exchange/", - "initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes", "reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders", "mintscanBase": "https://testnet.mintscan.io/dydx-testnet", "governanceLearnMore": "https://help.dydx.exchange", @@ -866,6 +926,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX V4" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-testnet-liquify": { @@ -916,7 +983,6 @@ "blogs": "https://www.dydx.foundation/blog", "foundation": "https://www.dydx.foundation", "help": "https://help.dydx.exchange/", - "initialMarginFractionLearnMore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes", "reduceOnlyLearnMore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders", "mintscanBase": "https://testnet.mintscan.io/dydx-testnet", "governanceLearnMore": "https://help.dydx.exchange", @@ -942,6 +1008,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX V4" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-testnet-polkachu": { @@ -1009,6 +1082,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX V4" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-testnet-bware": { @@ -1059,7 +1139,6 @@ "blogs": "https://www.dydx.foundation/blog", "foundation": "https://www.dydx.foundation", "help": "https://help.dydx.exchange/", - "initialMarginFractionLearnmore": "https://help.dydx.exchange/articles/5232637-maximum-position-sizes", "reduceOnlyLearnmore": "https://help.dydx.exchange/articles/6345793-reduce-only-orders", "mintscanBase": "https://testnet.mintscan.io/dydx-testnet", "governanceLearnmore": "https://help.dydx.exchange", @@ -1085,6 +1164,13 @@ "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX V4" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 10000000, + "delayBlocks": 900, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" + } } }, "dydxprotocol-mainnet": { @@ -1133,7 +1219,6 @@ "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]", - "initialMarginFractionLearnMore": "[HTTP link to initial margin fraction learn more, 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]", @@ -1161,6 +1246,13 @@ "images": "[Relative URL for wallet images]", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX Chain" + }, + "governance": { + "newMarketProposal": { + "initialDepositAmount": 0, + "delayBlocks": 0, + "newMarketsMethodology": "[URL to spreadsheet or document that explains methodology]" + } } } } diff --git a/public/configs/markets.json b/public/configs/markets.json index e81e812..f743aa3 100644 --- a/public/configs/markets.json +++ b/public/configs/markets.json @@ -69,6 +69,13 @@ "whitepaperLink": "https://bitcoincash.org/", "coinMarketCapsLink": "https://coinmarketcap.com/currencies/bitcoin-cash/" }, + "BONK-USD": { + "name": "BONK COIN", + "tags": [], + "websiteLink": "https://bonkcoin.com/", + "whitepaperLink": "https://bonkcoin.com/", + "coinMarketCapsLink": "https://coinmarketcap.com/currencies/bonk1/" + }, "BLUR-USD": { "name": "Blur", "tags": [], diff --git a/public/configs/potentialMarketExchangeConfig.csv b/public/configs/potentialMarketExchangeConfig.csv new file mode 100644 index 0000000..ddb12d2 --- /dev/null +++ b/public/configs/potentialMarketExchangeConfig.csv @@ -0,0 +1,704 @@ +base_asset,exchange,pair,min_2_depth,avg_30d_vol,reference_price,risk_assessment,num_oracles,liquidity_tier,asset_name,adjust_by_market +AAVE,Mexc,AAVE_USDT,403707.603,299498.6587,88.46188619,A,7,2,AAVE,USDT-USD +AAVE,Huobi,aaveusdt,49562.27661,34092101.66,88.52768881,A,7,2,AAVE,USDT-USD +AAVE,Kraken,AAVEUSD,84969.1289,732237.4435,88.21901516,A,7,2,AAVE, +AAVE,Okx,AAVE-USDT,120824.3981,5483819.403,88.48717486,A,7,2,AAVE,USDT-USD +AAVE,Kucoin,AAVE-USDT,60134.45372,1454001.73,88.41847956,A,7,2,AAVE,USDT-USD +AAVE,Binance,AAVEUSDT,336646.7802,17941167.87,88.40806057,A,7,2,AAVE,USDT-USD +AAVE,CoinbasePro,AAVE-USD,162207.2275,7955414.095,88.41304215,A,7,2,AAVE, +ADA,Okx,ADA-USDT,303911.146,12693505.79,0.4718322348,A,9,1,Cardano,USDT-USD +ADA,CoinbasePro,ADA-USD,611511.2428,18323224.07,0.4703816721,A,9,1,Cardano, +ADA,Huobi,adausdt,149750.1588,18688486.68,0.470293013,A,9,1,Cardano,USDT-USD +ADA,Kucoin,ADA-USDT,204346.5493,11339662.31,0.470650622,A,9,1,Cardano,USDT-USD +ADA,Bitstamp,ADA/USD,111141.4265,495063.9401,0.4732612949,A,9,1,Cardano, +ADA,Mexc,ADA_USDT,1480561.883,34705754.08,0.4706681442,A,9,1,Cardano,USDT-USD +ADA,Bybit,ADAUSDT,261755.7266,15267158.53,0.4715127504,A,9,1,Cardano,USDT-USD +ADA,Kraken,ADAUSD,631495.1952,4783679.81,0.4728831552,A,9,1,Cardano, +ADA,Binance,ADAUSDT,1014519.017,74913609.68,0.4709109462,A,9,1,Cardano,USDT-USD +AGIX,Okx,AGIX-USDT,144402.4677,1230616.692,0.2534299858,A,6,2,SingularityNET,USDT-USD +AGIX,Bybit,AGIXUSDT,72731.67454,2177116.497,0.2534800192,A,6,2,SingularityNET,USDT-USD +AGIX,Kucoin,AGIX-USDT,86823.62761,4637581.791,0.2531545743,A,6,2,SingularityNET,USDT-USD +AGIX,Mexc,AGIX_USDT,114261.8075,179945.4082,0.2532243225,A,6,2,SingularityNET,USDT-USD +AGIX,Binance,AGIXUSDT,181499.5614,6601700.149,0.2535772917,A,6,2,SingularityNET,USDT-USD +AGIX,Gate,AGIX_USDT,50000,100000,0,A,6,2,SingularityNET,USDT-USD +ALGO,Kucoin,ALGO-USDT,125172.0507,2774508.432,0.1612760665,A,6,2,Algorand,USDT-USD +ALGO,Mexc,ALGO_USDT,471722.5569,391031.4403,0.1615972948,A,6,2,Algorand,USDT-USD +ALGO,Okx,ALGO-USDT,84724.99655,3001155.055,0.1614784231,A,6,2,Algorand,USDT-USD +ALGO,CoinbasePro,ALGO-USD,137293.3037,3626194.058,0.1612613776,A,6,2,Algorand, +ALGO,Kraken,ALGOUSD,94239.46899,856438.0736,0.1611316036,A,6,2,Algorand, +ALGO,Binance,ALGOUSDT,240363.9844,10216526.81,0.1613137606,A,6,2,Algorand,USDT-USD +APE,Mexc,APE_USDT,845830.979,329116.5427,1.31149687,A,7,2,ApeCoin,USDT-USD +APE,Kucoin,APE-USDT,74830.83223,1527594.928,1.306893397,A,7,2,ApeCoin,USDT-USD +APE,CoinbasePro,APE-USD,79825.96928,1765569.337,1.310147807,A,7,2,ApeCoin, +APE,Okx,APE-USDT,127038.7774,4931009.134,1.310171735,A,7,2,ApeCoin,USDT-USD +APE,Binance,APEUSDT,295540.0092,16809984.56,1.309457667,A,7,2,ApeCoin,USDT-USD +APE,Kraken,APEUSD,47261.34196,350969.3303,1.302436726,A,7,2,ApeCoin, +APE,Gate,APE_USDT,50000,100000,0,A,7,2,ApeCoin,USDT-USD +APT,Binance,APTUSDT,970622.772,42662112,8.365109058,A,8,2,Aptos,USDT-USD +APT,Kraken,APTUSD,95252.8507,687239.9038,8.373953519,A,8,2,Aptos, +APT,Bybit,APTUSDT,421662.7604,13658424.61,8.360517459,A,8,2,Aptos,USDT-USD +APT,Kucoin,APT-USDT,59781.95498,3012611.094,8.371347497,A,8,2,Aptos,USDT-USD +APT,Mexc,APT_USDT,188448.7027,6995386.772,8.37360865,A,8,2,Aptos,USDT-USD +APT,CoinbasePro,APT-USD,158248.5255,5176336.024,8.369192123,A,8,2,Aptos, +APT,Okx,APT-USDT,596052.5515,20209030.67,8.37385096,A,8,2,Aptos,USDT-USD +APT,Gate,APT_USDT,50000,100000,0,A,8,2,Aptos,USDT-USD +ARB,Kraken,ARBUSD,100206.2199,4381943.143,1.705803002,A,8,1,Arbitrum, +ARB,Mexc,ARB_USDT,563395.9496,70966050.57,1.700151185,A,8,1,Arbitrum,USDT-USD +ARB,CoinbasePro,ARB-USD,323984.7248,25023919.67,1.706804349,A,8,1,Arbitrum, +ARB,Binance,ARBUSDT,1448064.308,225490594,1.700534337,A,8,1,Arbitrum,USDT-USD +ARB,Bybit,ARBUSDT,188544.697,49644508.17,1.697965318,A,8,1,Arbitrum,USDT-USD +ARB,Okx,ARB-USDT,619050.2317,56911723.48,1.700105696,A,8,1,Arbitrum,USDT-USD +ARB,Kucoin,ARB-USDT,244278.1403,15751598.26,1.705204466,A,8,1,Arbitrum,USDT-USD +ARB,Huobi,arbusdt,111073.3497,24106121.68,1.696818375,A,8,1,Arbitrum,USDT-USD +ATOM,Kucoin,ATOM-USDT,122511.6105,4164205.618,9.196821466,A,8,2,Cosmos,USDT-USD +ATOM,CoinbasePro,ATOM-USD,205758.8309,4244575.601,9.188194158,A,8,2,Cosmos, +ATOM,Binance,ATOMUSDT,500205.8745,32707609.21,9.19886839,A,8,2,Cosmos,USDT-USD +ATOM,Kraken,ATOMUSD,228688.3729,1024035.956,9.218557996,A,8,2,Cosmos, +ATOM,Okx,ATOM-USDT,147209.9881,6727992.679,9.196235185,A,8,2,Cosmos,USDT-USD +ATOM,Mexc,ATOM_USDT,396797.5433,1008586.239,9.21317801,A,8,2,Cosmos,USDT-USD +ATOM,Bybit,ATOMUSDT,100035.0706,5523700.635,9.191262868,A,8,2,Cosmos,USDT-USD +ATOM,Gate,ATOM_USDT,50000,100000,0,A,8,2,Cosmos,USDT-USD +AVAX,Okx,AVAX-USDT,459223.0249,27191336.53,30.3671387,A,9,1,Avalanche,USDT-USD +AVAX,Mexc,AVAX_USDT,2630410.171,40197237.8,30.31335915,A,9,1,Avalanche,USDT-USD +AVAX,CoinbasePro,AVAX-USD,710189.1641,41234008.85,30.43579342,A,9,1,Avalanche, +AVAX,Kraken,AVAXUSD,455749.7351,5083869.862,30.36461631,A,9,1,Avalanche, +AVAX,Huobi,avaxusdt,83674.34414,20197355.5,30.38713582,A,9,1,Avalanche,USDT-USD +AVAX,Bitstamp,AVAX/USD,78931.59345,492591.779,30.51926775,A,9,1,Avalanche, +AVAX,Binance,AVAXUSDT,1424442.662,110228072.3,30.31927119,A,9,1,Avalanche,USDT-USD +AVAX,Bybit,AVAXUSDT,266594.6447,19032772.46,30.37667694,A,9,1,Avalanche,USDT-USD +AVAX,Kucoin,AVAX-USDT,256007.3589,13423273.72,30.36129437,A,9,1,Avalanche,USDT-USD +BCH,Kraken,BCHUSD,203340.9953,1163173.528,236.4383838,A,9,1,Bitcoin Cash, +BCH,Bitstamp,BCH/USD,133890.8622,1113055.48,236.3834073,A,9,1,Bitcoin Cash, +BCH,Kucoin,BCH-USDT,153403.2244,1766025.88,236.2130317,A,9,1,Bitcoin Cash,USDT-USD +BCH,Mexc,BCH_USDT,1688109.018,340077.5421,236.974317,A,9,1,Bitcoin Cash,USDT-USD +BCH,Binance,BCHUSDT,672821.7917,32395763.97,236.0220829,A,9,1,Bitcoin Cash,USDT-USD +BCH,Bybit,BCHUSDT,156013.3525,7323063.446,236.304741,A,9,1,Bitcoin Cash,USDT-USD +BCH,Huobi,bchusdt,65221.14333,14976246.74,236.1401006,A,9,1,Bitcoin Cash,USDT-USD +BCH,Okx,BCH-USDT,351452.4549,15579827.1,236.1496084,A,9,1,Bitcoin Cash,USDT-USD +BCH,CoinbasePro,BCH-USD,448678.0454,10694749.58,236.3332929,A,9,1,Bitcoin Cash, +BLUR,Kraken,BLURUSD,99075.46212,1216513.285,0.6025188372,A,7,2,Blur, +BLUR,Bybit,BLURUSDT,68313.916,6461469.994,0.60531087,A,7,2,Blur,USDT-USD +BLUR,Binance,BLURUSDT,523824.0691,49785352.29,0.6085401119,A,7,2,Blur,USDT-USD +BLUR,Kucoin,BLUR-USDT,114279.3879,3580944.358,0.6060076016,A,7,2,Blur,USDT-USD +BLUR,Okx,BLUR-USDT,242440.7708,21042871.79,0.6072397492,A,7,2,Blur,USDT-USD +BLUR,CoinbasePro,BLUR-USD,156092.3813,8736803.112,0.6038877368,A,7,2,Blur, +BLUR,Mexc,BLUR_USDT,845700.0176,614271.1779,0.6015683969,A,7,2,Blur,USDT-USD +BNB,Okx,BNB-USDT,171035.3871,10049830.17,291.7391615,A,6,2,Binance Coin,USDT-USD +BNB,Kucoin,BNB-USDT,172933.5367,7563235.244,291.8671543,A,6,2,Binance Coin,USDT-USD +BNB,Mexc,BNB_USDT,2668302.204,2095942.424,291.3317029,A,6,2,Binance Coin,USDT-USD +BNB,Binance,BNBUSDT,2315487.589,299938471.1,292.0261567,A,6,2,Binance Coin,USDT-USD +BNB,Bybit,BNBUSDT,73840.12419,11584488.51,291.812684,A,6,2,Binance Coin,USDT-USD +BNB,Gate,BNB_USDT,50000,100000,0,A,6,2,Binance Coin,USDT-USD +BONK,Bybit,BONKUSDT,91223.30674,10108782.84,1.09E-05,A,6,2,Bonk Token,USDT-USD +BONK,Mexc,BONK_USDT,880507.727,1996432.036,1.10E-05,A,6,2,Bonk Token,USDT-USD +BONK,Binance,BONKUSDT,496236.8093,63520367.26,1.09E-05,A,6,2,Bonk Token,USDT-USD +BONK,Okx,BONK-USDT,84194.41757,4939704.699,1.09E-05,A,6,2,Bonk Token,USDT-USD +BONK,CoinbasePro,BONK-USD,291120.8766,24041618.38,1.10E-05,A,6,2,Bonk Token, +BONK,Kucoin,BONK-USDT,104413.0879,5795566.827,1.09E-05,A,6,2,Bonk Token,USDT-USD +BTC,Kucoin,BTC-USDT,1385049.373,192647255.8,39920.8141,A,9,1,Bitcoin,USDT-USD +BTC,Mexc,BTC_USDT,6055794.786,468890338.6,39929.87241,A,9,1,Bitcoin,USDT-USD +BTC,Bybit,BTCUSDT,1934000.115,501075059.1,39905.40634,A,9,1,Bitcoin,USDT-USD +BTC,Okx,BTC-USDT,3216401.515,736570802.6,39910.57726,A,9,1,Bitcoin,USDT-USD +BTC,Bitstamp,BTC/USD,4904357.079,103847807.2,39898.51266,A,9,1,Bitcoin, +BTC,Huobi,btcusdt,1628523.051,85957777.78,39927.11023,A,9,1,Bitcoin,USDT-USD +BTC,CoinbasePro,BTC-USD,11838510.17,799998360.6,39872.42919,A,9,1,Bitcoin, +BTC,Kraken,BTCUSD,11254244.98,152725974.7,39905.34906,A,9,1,Bitcoin, +BTC,Binance,BTCUSDT,13081922.22,1943592587,39912.24136,A,9,1,Bitcoin,USDT-USD +CHZ,Okx,CHZ-USDT,76721.70261,9853334.361,0.1037356507,A,6,2,Chiliz,USDT-USD +CHZ,Mexc,CHZ_USDT,230477.9128,285408.6504,0.1038430482,A,6,2,Chiliz,USDT-USD +CHZ,CoinbasePro,CHZ-USD,51276.07653,1252645.033,0.1054762023,A,6,2,Chiliz, +CHZ,Kraken,CHZUSD,48524.85664,395637.5252,0.1050375877,A,6,2,Chiliz, +CHZ,Binance,CHZUSDT,249888.0127,28501304.85,0.1046721926,A,6,2,Chiliz,USDT-USD +CHZ,Gate,CHZ_USDT,50000,100000,0,A,6,2,Chiliz,USDT-USD +CRV,Kraken,CRVUSD,60416.85503,292275.2165,0.4482389055,A,6,2,Curve DAO Token, +CRV,Kucoin,CRV-USDT,50096.30378,680353.338,0.4434254994,A,6,2,Curve DAO Token,USDT-USD +CRV,Binance,CRVUSDT,265385.0097,9688519.274,0.443424373,A,6,2,Curve DAO Token,USDT-USD +CRV,CoinbasePro,CRV-USD,96582.28361,871025.6346,0.4446821049,A,6,2,Curve DAO Token, +CRV,Mexc,CRV_USDT,202941.3475,133320.8099,0.4438313683,A,6,2,Curve DAO Token,USDT-USD +CRV,Okx,CRV-USDT,109901.21,6873330.009,0.4425725114,A,6,2,Curve DAO Token,USDT-USD +DOGE,CoinbasePro,DOGE-USD,705184.7562,25424875.32,0.07793120656,A,9,1,Dogecoin, +DOGE,Okx,DOGE-USDT,565834.5118,33076839.3,0.07788150395,A,9,1,Dogecoin,USDT-USD +DOGE,Mexc,DOGE_USDT,1091538.578,22937578.29,0.0779243829,A,9,1,Dogecoin,USDT-USD +DOGE,Kraken,DOGEUSD,547998.0729,4621710.265,0.07778464129,A,9,1,Dogecoin, +DOGE,Bybit,DOGEUSDT,290256.381,15914185,0.07796760983,A,9,1,Dogecoin,USDT-USD +DOGE,Bitstamp,DOGE/USD,46447.64873,189541.7938,0.07799339803,A,9,1,Dogecoin, +DOGE,Binance,DOGEUSDT,1252926.134,84403824.56,0.07796643769,A,9,1,Dogecoin,USDT-USD +DOGE,Huobi,dogeusdt,269955.645,21525311.57,0.07794967908,A,9,1,Dogecoin,USDT-USD +DOGE,Kucoin,DOGE-USDT,365702.9014,7810505.65,0.07798714967,A,9,1,Dogecoin,USDT-USD +DOT,Kraken,DOTUSD,368701.8747,4429592.47,6.452188898,A,8,1,Polkadot, +DOT,Okx,DOT-USDT,222355.039,10742911.87,6.458175307,A,8,1,Polkadot,USDT-USD +DOT,Huobi,dotusdt,45783.29935,10974447.87,6.450317276,A,8,1,Polkadot,USDT-USD +DOT,Mexc,DOT_USDT,1098245.94,1339831.03,6.446585762,A,8,1,Polkadot,USDT-USD +DOT,Bybit,DOTUSDT,166496.7868,9913978.391,6.454271244,A,8,1,Polkadot,USDT-USD +DOT,CoinbasePro,DOT-USD,168119.2694,9778920.932,6.452749635,A,8,1,Polkadot, +DOT,Kucoin,DOT-USDT,124303.7984,5544103.268,6.453780538,A,8,1,Polkadot,USDT-USD +DOT,Binance,DOTUSDT,593806.1697,48873686.06,6.451243808,A,8,1,Polkadot,USDT-USD +ENS,Mexc,ENS_USDT,367658.849,670539.5241,17.98863652,A,6,2,Ethereum Name Service (ENS),USDT-USD +ENS,Kucoin,ENS-USDT,54724.81451,3676707.428,17.75880758,A,6,2,Ethereum Name Service (ENS),USDT-USD +ENS,Binance,ENSUSDT,291418.3232,62479176.65,17.81688813,A,6,2,Ethereum Name Service (ENS),USDT-USD +ENS,CoinbasePro,ENS-USD,91775.13594,7641723.902,17.79343763,A,6,2,Ethereum Name Service (ENS), +ENS,Okx,ENS-USDT,137796.003,17044833.9,17.78364476,A,6,2,Ethereum Name Service (ENS),USDT-USD +ENS,Gate,ENS_USDT,50000,100000,0,A,6,2,Ethereum Name Service (ENS),USDT-USD +EOS,Binance,EOSUSDT,372008.7468,8074383.692,0.6830128043,A,8,2,Eos,USDT-USD +EOS,Mexc,EOS_USDT,1199704.281,272102.5368,0.6840073934,A,8,2,Eos,USDT-USD +EOS,Kucoin,EOS-USDT,75854.21225,709014.6871,0.68384828,A,8,2,Eos,USDT-USD +EOS,CoinbasePro,EOS-USD,77320.52881,1313993.017,0.6822937779,A,8,2,Eos, +EOS,Kraken,EOSUSD,88673.50535,723904.186,0.6839062109,A,8,2,Eos, +EOS,Okx,EOS-USDT,139325.4759,9112853.76,0.6825281331,A,8,2,Eos,USDT-USD +EOS,Bybit,EOSUSDT,50578.19146,5841158.864,0.6822045569,A,8,2,Eos,USDT-USD +EOS,Gate,EOS_USDT,50000,100000,0,A,8,2,Eos,USDT-USD +ETC,Kucoin,ETC-USDT,113759.0808,3477554.997,22.85192736,A,8,1,Ethereum Classic,USDT-USD +ETC,Binance,ETCUSDT,655668.4981,60729272.86,22.86694828,A,8,1,Ethereum Classic,USDT-USD +ETC,Bybit,ETCUSDT,49561.58743,2838378.919,22.8367253,A,8,1,Ethereum Classic,USDT-USD +ETC,Kraken,ETCUSD,155878.8877,734888.778,22.88123977,A,8,1,Ethereum Classic, +ETC,CoinbasePro,ETC-USD,584427.6111,7597750.664,22.83725611,A,8,1,Ethereum Classic, +ETC,Huobi,etcusdt,81646.91108,13533193.91,22.77483439,A,8,1,Ethereum Classic,USDT-USD +ETC,Okx,ETC-USDT,338589.5466,23459446.52,22.81594291,A,8,1,Ethereum Classic,USDT-USD +ETC,Mexc,ETC_USDT,1378585.921,911135.813,22.92403344,A,8,1,Ethereum Classic,USDT-USD +ETH,Bitstamp,ETH/USD,1786424.201,19272496.97,2212.492226,A,9,1,Ethereum, +ETH,Okx,ETH-USDT,2444418.764,388934350.5,2210.16441,A,9,1,Ethereum,USDT-USD +ETH,Huobi,ethusdt,1695970.121,34272154.83,2212.288729,A,9,1,Ethereum,USDT-USD +ETH,Kucoin,ETH-USDT,1037412.076,119386693.6,2211.480181,A,9,1,Ethereum,USDT-USD +ETH,Bybit,ETHUSDT,1345249.473,304189767.2,2211.399676,A,9,1,Ethereum,USDT-USD +ETH,Kraken,ETHUSD,5075383.05,56853252.58,2212.377288,A,9,1,Ethereum, +ETH,Mexc,ETH_USDT,4484321.007,210359167.7,2214.032265,A,9,1,Ethereum,USDT-USD +ETH,CoinbasePro,ETH-USD,7298871.343,296252747.3,2210.07616,A,9,1,Ethereum, +ETH,Binance,ETHUSDT,10324165.63,1060630897,2211.179573,A,9,1,Ethereum,USDT-USD +FET,Mexc,FET_USDT,494656.0995,559935.8786,0.5882081836,A,6,2,Fetch AI,USDT-USD +FET,Binance,FETUSDT,465708.0914,22769357.29,0.5862566061,A,6,2,Fetch AI,USDT-USD +FET,Kucoin,FET-USDT,96173.26242,4354855.944,0.5872583338,A,6,2,Fetch AI,USDT-USD +FET,Okx,FET-USDT,80416.82548,1578553.143,0.587271404,A,6,2,Fetch AI,USDT-USD +FET,Kraken,FETUSD,80688.82031,1386327.677,0.5848580771,A,6,2,Fetch AI, +FET,CoinbasePro,FET-USD,241779.2529,9092328.77,0.5848723328,A,6,2,Fetch AI, +FIL,Kucoin,FIL-USDT,136368.2949,7410428.74,4.93172295,A,8,1,Filecoin,USDT-USD +FIL,Kraken,FILUSD,133991.2228,1832800.962,4.933693054,A,8,1,Filecoin, +FIL,CoinbasePro,FIL-USD,258870.6985,11530932.48,4.934286612,A,8,1,Filecoin, +FIL,Bybit,FILUSDT,86576.25386,7525363.033,4.91922609,A,8,1,Filecoin,USDT-USD +FIL,Mexc,FIL_USDT,1094874.372,1819214.992,4.927851525,A,8,1,Filecoin,USDT-USD +FIL,Okx,FIL-USDT,646778.4394,55504900,4.9289709,A,8,1,Filecoin,USDT-USD +FIL,Binance,FILUSDT,844740.0409,75887089.73,4.930605871,A,8,1,Filecoin,USDT-USD +FIL,Huobi,filusdt,68173.55527,16793194.38,4.936018668,A,8,1,Filecoin,USDT-USD +FTM,Bybit,FTMUSDT,71346.61591,4128311.729,0.3352808917,A,6,2,Fantom,USDT-USD +FTM,Kraken,FTMUSD,87646.51897,1176507.833,0.3346537706,A,6,2,Fantom, +FTM,Kucoin,FTM-USDT,106225.8231,4400742.84,0.3358058793,A,6,2,Fantom,USDT-USD +FTM,Mexc,FTM_USDT,632339.7399,1081199.831,0.3365010633,A,6,2,Fantom,USDT-USD +FTM,Binance,FTMUSDT,424997.2126,25764943.66,0.3360637395,A,6,2,Fantom,USDT-USD +FTM,Okx,FTM-USDT,98090.82999,4900885.095,0.3376845609,A,6,2,Fantom,USDT-USD +GALA,Okx,GALA-USDT,189873.4137,6654005.649,0.02204820477,A,6,2,Gala,USDT-USD +GALA,Mexc,GALA_USDT,674173.1073,662194.7213,0.02211283071,A,6,2,Gala,USDT-USD +GALA,Bybit,GALAUSDT,81233.95423,2802651.478,0.02204724605,A,6,2,Gala,USDT-USD +GALA,Kraken,GALAUSD,81853.15768,971887.7737,0.02213452999,A,6,2,Gala, +GALA,Binance,GALAUSDT,415969.0247,23466983.63,0.02205812128,A,6,2,Gala,USDT-USD +GALA,Gate,GALA_USDT,50000,100000,0,A,6,2,Gala,USDT-USD +GRT,CoinbasePro,GRT-USD,212787.1065,5275612.932,0.1493811838,A,7,2,The Graph, +GRT,Okx,GRT-USDT,65342.41311,2506599.164,0.1492456221,A,7,2,The Graph,USDT-USD +GRT,Mexc,GRT_USDT,598125.0805,479952.4649,0.1491757716,A,7,2,The Graph,USDT-USD +GRT,Kraken,GRTUSD,75871.99326,633740.4267,0.1498390276,A,7,2,The Graph, +GRT,Binance,GRTUSDT,326438.7018,17403725.33,0.1491240716,A,7,2,The Graph,USDT-USD +GRT,Kucoin,GRT-USDT,81544.85738,1753762.597,0.1493661616,A,7,2,The Graph,USDT-USD +GRT,Gate,GRT_USDT,50000,100000,0,A,7,2,The Graph,USDT-USD +HBAR,Kucoin,HBAR-USDT,114290.7661,2775278.488,0.07132025496,A,7,2,Hedera Hashgraph,USDT-USD +HBAR,Mexc,HBAR_USDT,460300.1662,483877.2872,0.07108943658,A,7,2,Hedera Hashgraph,USDT-USD +HBAR,CoinbasePro,HBAR-USD,214294.0589,7087561.93,0.07116005717,A,7,2,Hedera Hashgraph, +HBAR,Okx,HBAR-USDT,112689.0708,4026461.082,0.07125365623,A,7,2,Hedera Hashgraph,USDT-USD +HBAR,Huobi,hbarusdt,46422.78344,12502601.52,0.07144363395,A,7,2,Hedera Hashgraph,USDT-USD +HBAR,Binance,HBARUSDT,342801.5964,14209768.84,0.07132722883,A,7,2,Hedera Hashgraph,USDT-USD +HBAR,Bybit,HBARUSDT,45261.49627,1258321.041,0.07136344216,A,7,2,Hedera Hashgraph,USDT-USD +ICP,Binance,ICPUSDT,501774.1138,77170682.6,11.52804787,A,7,2,Internet Computer,USDT-USD +ICP,Okx,ICP-USDT,297422.7336,20593859.34,11.59386803,A,7,2,Internet Computer,USDT-USD +ICP,Mexc,ICP_USDT,229038.0671,2659248.459,11.29959518,A,7,2,Internet Computer,USDT-USD +ICP,Bybit,ICPUSDT,145658.1104,13815502.64,11.47155514,A,7,2,Internet Computer,USDT-USD +ICP,CoinbasePro,ICP-USD,481694.0934,22919263.78,11.51929241,A,7,2,Internet Computer, +ICP,Kucoin,ICP-USDT,243799.5596,21281791.71,11.4267898,A,7,2,Internet Computer,USDT-USD +ICP,Kraken,ICPUSD,152510.8207,4230646.898,11.48180455,A,7,2,Internet Computer, +INJ,Binance,INJUSDT,761854.6344,75471268.13,31.75641906,A,7,2,Injective Protocol,USDT-USD +INJ,Bybit,INJUSDT,46259.03266,8671297.48,31.81868206,A,7,2,Injective Protocol,USDT-USD +INJ,Mexc,INJ_USDT,195130.7785,2547540.558,31.75180875,A,7,2,Injective Protocol,USDT-USD +INJ,Kraken,INJUSD,110554.9597,4615214.653,31.81822066,A,7,2,Injective Protocol, +INJ,CoinbasePro,INJ-USD,263574.9589,21960083.14,31.75834432,A,7,2,Injective Protocol, +INJ,Kucoin,INJ-USDT,112763.3848,13043315.83,31.73964964,A,7,2,Injective Protocol,USDT-USD +INJ,Okx,INJ-USDT,156547.4276,6879780.129,31.838232,A,7,2,Injective Protocol,USDT-USD +JTO,CoinbasePro,JTO-USD,209989.3821,10018464.73,1.887681028,A,6,2,Jito, +JTO,Binance,JTOUSDT,350644.6827,47762160.17,1.883291251,A,6,2,Jito,USDT-USD +JTO,Bybit,JTOUSDT,74864.14695,4967573.71,1.886557933,A,6,2,Jito,USDT-USD +JTO,Mexc,JTO_USDT,138559.5351,998743.8255,1.88425904,A,6,2,Jito,USDT-USD +JTO,Okx,JTO-USDT,96745.66258,8928569.193,1.884792183,A,6,2,Jito,USDT-USD +JTO,Kucoin,JTO-USDT,87953.5565,3015273.183,1.890669659,A,6,2,Jito,USDT-USD +KAVA,CoinbasePro,KAVA-USD,176534.8573,385485.2501,0.6919030037,A,6,2,Kava, +KAVA,Mexc,KAVA_USDT,1176186.319,270495.2643,0.6895330959,A,6,2,Kava,USDT-USD +KAVA,Kucoin,KAVA-USDT,89752.19321,596070.2703,0.6890117656,A,6,2,Kava,USDT-USD +KAVA,Binance,KAVAUSDT,646090.2324,11218433.99,0.6895853325,A,6,2,Kava,USDT-USD +KAVA,Kraken,KAVAUSD,85320.83296,641014.1765,0.6908946014,A,6,2,Kava, +KAVA,Gate,KAVA_USDT,50000,100000,0,A,6,2,Kava,USDT-USD +LDO,Okx,LDO-USDT,181894.181,10111578.42,2.88714217,A,8,2,Lido DAO,USDT-USD +LDO,Binance,LDOUSDT,387738.82,41043700.87,2.883611792,A,8,2,Lido DAO,USDT-USD +LDO,CoinbasePro,LDO-USD,220300.8676,11976409.69,2.884625596,A,8,2,Lido DAO, +LDO,Kraken,LDOUSD,100447.1249,2150960.494,2.887488478,A,8,2,Lido DAO, +LDO,Mexc,LDO_USDT,588930.053,638809.6967,2.882180527,A,8,2,Lido DAO,USDT-USD +LDO,Kucoin,LDO-USDT,91009.30345,4468563.248,2.885880042,A,8,2,Lido DAO,USDT-USD +LDO,Bybit,LDOUSDT,71154.49236,6463827.135,2.885385432,A,8,2,Lido DAO,USDT-USD +LDO,Gate,LDO_USDT,50000,100000,0,A,8,2,Lido DAO,USDT-USD +LINK,Kraken,LINKUSD,552242.3853,5755261.063,13.82357462,A,8,1,ChainLink, +LINK,CoinbasePro,LINK-USD,680356.4439,32122820.26,13.80640803,A,8,1,ChainLink, +LINK,Mexc,LINK_USDT,1218298.471,49003625.57,13.80057366,A,8,1,ChainLink,USDT-USD +LINK,Binance,LINKUSDT,1057623.562,91375865.04,13.7948244,A,8,1,ChainLink,USDT-USD +LINK,Okx,LINK-USDT,275176.1551,13565986.64,13.79776617,A,8,1,ChainLink,USDT-USD +LINK,Bitstamp,LINK/USD,151182.7984,1359533.87,13.84044633,A,8,1,ChainLink, +LINK,Kucoin,LINK-USDT,196203.2947,9579617.943,13.81059009,A,8,1,ChainLink,USDT-USD +LINK,Bybit,LINKUSDT,180315.7755,14220162.33,13.85826731,A,8,1,ChainLink,USDT-USD +LTC,CoinbasePro,LTC-USD,543451.3689,13785634.51,65.4631381,A,9,1,Litecoin, +LTC,Mexc,LTC_USDT,1879096.824,17331806.29,65.43634611,A,9,1,Litecoin,USDT-USD +LTC,Okx,LTC-USDT,507929.3471,26530065.91,65.41225491,A,9,1,Litecoin,USDT-USD +LTC,Kucoin,LTC-USDT,290350.1634,6126387.388,65.4318351,A,9,1,Litecoin,USDT-USD +LTC,Bybit,LTCUSDT,201299.6733,12383937.05,65.45086009,A,9,1,Litecoin,USDT-USD +LTC,Bitstamp,LTC/USD,71302.43935,837193.57,65.38819428,A,9,1,Litecoin, +LTC,Huobi,ltcusdt,150004.7632,4614143.66,65.4369822,A,9,1,Litecoin,USDT-USD +LTC,Kraken,LTCUSD,485564.9077,2601077.121,65.43280684,A,9,1,Litecoin, +LTC,Binance,LTCUSDT,975861.6282,46447198.76,65.43597402,A,9,1,Litecoin,USDT-USD +MANA,Binance,MANAUSDT,161539.8083,8060438.22,0.4335988613,A,7,2,Decentraland,USDT-USD +MANA,Kucoin,MANA-USDT,58087.72222,503402.4757,0.4338408816,A,7,2,Decentraland,USDT-USD +MANA,Kraken,MANAUSD,84924.79935,272373.0049,0.432452467,A,7,2,Decentraland, +MANA,Mexc,MANA_USDT,253761.7046,145519.6743,0.4345951497,A,7,2,Decentraland,USDT-USD +MANA,Okx,MANA-USDT,68844.47795,1431443.961,0.4338122156,A,7,2,Decentraland,USDT-USD +MANA,CoinbasePro,MANA-USD,69142.62162,865483.8728,0.4332575848,A,7,2,Decentraland, +MANA,Gate,MANA_USDT,50000,100000,0,A,7,2,Decentraland,USDT-USD +MASK,Binance,MASKUSDT,527334.4347,29606345.22,3.252034856,A,7,2,Mask Network,USDT-USD +MASK,Okx,MASK-USDT,164626.3439,17425407.01,3.247435343,A,7,2,Mask Network,USDT-USD +MASK,Kucoin,MASK-USDT,68471.50785,2787550.55,3.250394924,A,7,2,Mask Network,USDT-USD +MASK,Mexc,MASK_USDT,551854.5319,340523.7233,3.255251096,A,7,2,Mask Network,USDT-USD +MASK,CoinbasePro,MASK-USD,76371.2574,1172479.2,3.257449365,A,7,2,Mask Network, +MASK,Bybit,MASKUSDT,55836.09372,3549089.841,3.251526238,A,7,2,Mask Network,USDT-USD +MASK,Gate,MASK_USDT,50000,100000,0,A,7,2,Mask Network,USDT-USD +MATIC,Okx,MATIC-USDT,286529.4599,19272111.96,0.7282054395,A,9,1,Matic Network,USDT-USD +MATIC,CoinbasePro,MATIC-USD,392683.598,14444572.98,0.7281953324,A,9,1,Matic Network, +MATIC,Binance,MATICUSDT,880166.8053,97986293.13,0.7281469424,A,9,1,Matic Network,USDT-USD +MATIC,Huobi,maticusdt,109573.122,15234696.66,0.7286294763,A,9,1,Matic Network,USDT-USD +MATIC,Bybit,MATICUSDT,253953.798,21099460.02,0.7281887236,A,9,1,Matic Network,USDT-USD +MATIC,Mexc,MATIC_USDT,985242.4337,45954909.9,0.7282376458,A,9,1,Matic Network,USDT-USD +MATIC,Kraken,MATICUSD,478478.4995,4510025.126,0.7294573007,A,9,1,Matic Network, +MATIC,Bitstamp,MATIC/USD,77920.84684,344911.6889,0.733080163,A,9,1,Matic Network, +MATIC,Kucoin,MATIC-USDT,356785.0871,8215026.183,0.7274795596,A,9,1,Matic Network,USDT-USD +MKR,CoinbasePro,MKR-USD,189657.3728,7901151.839,2113.462825,A,6,2,Maker, +MKR,Mexc,MKR_USDT,659686.2959,230714.6623,2119.293037,A,6,2,Maker,USDT-USD +MKR,Binance,MKRUSDT,368523.4153,23448263.7,2114.219678,A,6,2,Maker,USDT-USD +MKR,Kraken,MKRUSD,49658.74142,622993.922,2107.930364,A,6,2,Maker, +MKR,Okx,MKR-USDT,81342.70903,3487712.056,2111.932327,A,6,2,Maker,USDT-USD +MKR,Kucoin,MKR-USDT,45425.02507,675263.6294,2112.071675,A,6,2,Maker,USDT-USD +NEAR,Kucoin,NEAR-USDT,124294.3172,5843254.667,2.674161205,A,8,1,Near,USDT-USD +NEAR,Bybit,NEARUSDT,58206.62204,4630072.987,2.678918634,A,8,1,Near,USDT-USD +NEAR,CoinbasePro,NEAR-USD,185291.8636,5187550.998,2.67843549,A,8,1,Near, +NEAR,Kraken,NEARUSD,191549.9708,3360632.501,2.667463339,A,8,1,Near, +NEAR,Okx,NEAR-USDT,311377.3773,15382244.05,2.672818299,A,8,1,Near,USDT-USD +NEAR,Binance,NEARUSDT,578778.0911,61784058.07,2.676081404,A,8,1,Near,USDT-USD +NEAR,Mexc,NEAR_USDT,871096.6953,1184958.966,2.678323491,A,8,1,Near,USDT-USD +NEAR,Huobi,nearusdt,74787.28484,6999178.627,2.67181076,A,8,1,Near,USDT-USD +OP,Mexc,OP_USDT,1987545.663,1684136.999,2.871032553,A,7,2,Optimism,USDT-USD +OP,Okx,OP-USDT,456470.0968,40684606.93,2.865726402,A,7,2,Optimism,USDT-USD +OP,Bybit,OPUSDT,121956.4932,12754054.86,2.863599682,A,7,2,Optimism,USDT-USD +OP,Binance,OPUSDT,1189317.678,120606269.7,2.866861935,A,7,2,Optimism,USDT-USD +OP,Kucoin,OP-USDT,151102.3965,7514893.178,2.86647468,A,7,2,Optimism,USDT-USD +OP,CoinbasePro,OP-USD,351393.8984,22928210.76,2.864965623,A,7,2,Optimism, +OP,Gate,OP_USDT,50000,100000,0,A,7,2,Optimism,USDT-USD +ORDI,Kucoin,ORDI-USDT,110936.0169,7517594.63,51.5460857,A,6,2,Ordinals,USDT-USD +ORDI,Bybit,ORDIUSDT,119439.2682,9142897.563,51.46062583,A,6,2,Ordinals,USDT-USD +ORDI,Binance,ORDIUSDT,1816384.797,157536421.3,51.50890555,A,6,2,Ordinals,USDT-USD +ORDI,Okx,ORDI-USDT,897255.021,111729885.1,51.56285708,A,6,2,Ordinals,USDT-USD +ORDI,Huobi,ordiusdt,90017.00367,6939659.846,52.21823543,A,6,2,Ordinals,USDT-USD +ORDI,Gate,ORDI_USDT,50000,100000,0,A,6,2,Ordinals,USDT-USD +PEPE,Binance,PEPEUSDT,1854338.485,21983200.56,1.02E-06,A,6,2,Pepe,USDT-USD +PEPE,Kraken,PEPEUSD,66383.09612,339921.3126,1.02E-06,A,6,2,Pepe, +PEPE,Bybit,PEPEUSDT,70662.28564,5776041.599,1.02E-06,A,6,2,Pepe,USDT-USD +PEPE,Kucoin,PEPE-USDT,117845.5631,6320839.499,1.02E-06,A,6,2,Pepe,USDT-USD +PEPE,Mexc,PEPE_USDT,576088.0345,1051367.142,1.02E-06,A,6,2,Pepe,USDT-USD +PEPE,Okx,PEPE-USDT,253199.6634,10378463.48,1.02E-06,A,6,2,Pepe,USDT-USD +RNDR,Kucoin,RNDR-USDT,93245.66824,3389990.196,3.78277704,A,6,2,Render Token,USDT-USD +RNDR,Binance,RNDRUSDT,456778.1853,34499985.8,3.781059636,A,6,2,Render Token,USDT-USD +RNDR,CoinbasePro,RNDR-USD,180418.0343,11691967.24,3.767943401,A,6,2,Render Token, +RNDR,Kraken,RNDRUSD,62255.2913,1176061.236,3.788017753,A,6,2,Render Token, +RNDR,Mexc,RNDR_USDT,627963.3038,617023.2409,3.770998381,A,6,2,Render Token,USDT-USD +RNDR,Okx,RNDR-USDT,122198.2874,5319549.855,3.772653723,A,6,2,Render Token,USDT-USD +SAND,Okx,SAND-USDT,100469.8264,3508230.948,0.4373225476,A,7,2,SAND,USDT-USD +SAND,Kucoin,SAND-USDT,64668.48254,997968.9032,0.4371193254,A,7,2,SAND,USDT-USD +SAND,Kraken,SANDUSD,47650.66542,278973.929,0.4395664881,A,7,2,SAND, +SAND,CoinbasePro,SAND-USD,54744.16281,731889.0885,0.437434037,A,7,2,SAND, +SAND,Binance,SANDUSDT,263841.1812,14105685.55,0.4370122624,A,7,2,SAND,USDT-USD +SAND,Mexc,SAND_USDT,380990.8836,209883.4311,0.437304002,A,7,2,SAND,USDT-USD +SAND,Gate,SAND_USDT,50000,100000,0,A,7,2,SAND,USDT-USD +SEI,Binance,SEIUSDT,960266.1108,147580247.1,0.613207501,A,7,2,Sei,USDT-USD +SEI,CoinbasePro,SEI-USD,501975.7126,44992922.16,0.6149800585,A,7,2,Sei, +SEI,Huobi,seiusdt,58169.10057,38375753.16,0.6146183588,A,7,2,Sei,USDT-USD +SEI,Bybit,SEIUSDT,131815.1551,20617259.61,0.6146716564,A,7,2,Sei,USDT-USD +SEI,Kraken,SEIUSD,60743.57825,6077393.643,0.6142689745,A,7,2,Sei, +SEI,Kucoin,SEI-USDT,178642.4194,10251443.59,0.6122370319,A,7,2,Sei,USDT-USD +SEI,Mexc,SEI_USDT,456994.8627,3721782.454,0.6209961106,A,7,2,Sei,USDT-USD +SHIB,Okx,SHIB-USDT,186962.879,5752876.108,8.84E-06,A,8,1,Shiba Inu,USDT-USD +SHIB,Bybit,SHIBUSDT,97654.78678,2621562.66,8.84E-06,A,8,1,Shiba Inu,USDT-USD +SHIB,Kucoin,SHIB-USDT,214053.7893,4620710.046,8.84E-06,A,8,1,Shiba Inu,USDT-USD +SHIB,CoinbasePro,SHIB-USD,472915.9234,9834603.706,8.84E-06,A,8,1,Shiba Inu, +SHIB,Binance,SHIBUSDT,711743.4514,34409618.31,8.84E-06,A,8,1,Shiba Inu,USDT-USD +SHIB,Kraken,SHIBUSD,104567.4626,420513.5586,8.84E-06,A,8,1,Shiba Inu, +SHIB,Mexc,SHIB_USDT,1940827.945,796547.7524,8.84E-06,A,8,1,Shiba Inu,USDT-USD +SHIB,Huobi,shibusdt,67117.45039,363334.4836,8.84E-06,A,8,1,Shiba Inu,USDT-USD +SNX,Mexc,SNX_USDT,310714.3857,335052.6602,3.112944227,A,6,2,Synthetix Network Token,USDT-USD +SNX,Kraken,SNXUSD,63489.12006,606793.6628,3.13979134,A,6,2,Synthetix Network Token, +SNX,Okx,SNX-USDT,103282.8979,3298762.932,3.135011753,A,6,2,Synthetix Network Token,USDT-USD +SNX,Bybit,SNXUSDT,60753.04211,1293350.734,3.125053636,A,6,2,Synthetix Network Token,USDT-USD +SNX,Binance,SNXUSDT,287994.4111,12367152.42,3.133185754,A,6,2,Synthetix Network Token,USDT-USD +SNX,CoinbasePro,SNX-USD,138260.8807,3807927.897,3.137731528,A,6,2,Synthetix Network Token, +SOL,Kucoin,SOL-USDT,374442.0549,56433240.02,87.53739207,A,9,1,Solana,USDT-USD +SOL,CoinbasePro,SOL-USD,2257090.149,145521917.4,87.38247282,A,9,1,Solana, +SOL,Okx,SOL-USDT,1397468.011,135207705.4,87.4902174,A,9,1,Solana,USDT-USD +SOL,Mexc,SOL_USDT,1779392.262,299329951.9,87.49495206,A,9,1,Solana,USDT-USD +SOL,Kraken,SOLUSD,2251190.633,64593290.11,87.67728718,A,9,1,Solana, +SOL,Binance,SOLUSDT,3741601.199,607947665.6,87.49377311,A,9,1,Solana,USDT-USD +SOL,Bitstamp,SOL/USD,109890.2738,2646819.043,87.31111501,A,9,1,Solana, +SOL,Bybit,SOLUSDT,831770.3877,120667847.4,87.36083166,A,9,1,Solana,USDT-USD +SOL,Huobi,solusdt,275163.2969,41233952.41,87.4809317,A,9,1,Solana,USDT-USD +STX,Okx,STX-USDT,180203.7241,13352549.39,1.463485107,A,7,2,Stacks,USDT-USD +STX,Kraken,STXUSD,58949.55711,1353219.917,1.468122483,A,7,2,Stacks, +STX,CoinbasePro,STX-USD,258400.6869,14123894.62,1.463175003,A,7,2,Stacks, +STX,Kucoin,STX-USDT,152358.5064,5233980.249,1.465347379,A,7,2,Stacks,USDT-USD +STX,Binance,STXUSDT,584610.0183,45329052.16,1.462632266,A,7,2,Stacks,USDT-USD +STX,Mexc,STX_USDT,227354.8541,915054.5567,1.463303254,A,7,2,Stacks,USDT-USD +STX,Gate,STX_USDT,50000,100000,0,A,7,2,Stacks,USDT-USD +SUI,Kucoin,SUI-USDT,157119.1,12511155.03,1.224163869,A,6,2,SuiNetwork,USDT-USD +SUI,Mexc,SUI_USDT,233548.7548,2056662.292,1.222993101,A,6,2,SuiNetwork,USDT-USD +SUI,Binance,SUIUSDT,1262079.981,111516956.8,1.223930951,A,6,2,SuiNetwork,USDT-USD +SUI,CoinbasePro,SUI-USD,164063.7043,14862283.81,1.225266393,A,6,2,SuiNetwork, +SUI,Bybit,SUIUSDT,212067.1354,19630489.94,1.225408738,A,6,2,SuiNetwork,USDT-USD +SUI,Okx,SUI-USDT,613217.7334,54191478.11,1.223865903,A,6,2,SuiNetwork,USDT-USD +SUSHI,Mexc,SUSHI_USDT,698897.3305,162827.6862,1.069891177,A,6,2,Sushi,USDT-USD +SUSHI,Binance,SUSHIUSDT,314905.5164,8301205.3,1.070356721,A,6,2,Sushi,USDT-USD +SUSHI,Okx,SUSHI-USDT,140667.711,3610840.809,1.067487683,A,6,2,Sushi,USDT-USD +SUSHI,Kraken,SUSHIUSD,60333.51362,206177.6733,1.075978241,A,6,2,Sushi, +SUSHI,CoinbasePro,SUSHI-USD,84615.09476,3085188.166,1.072066002,A,6,2,Sushi, +SUSHI,Gate,SUSHI_USDT,50000,100000,0,A,6,2,Sushi,USDT-USD +TIA,Bybit,TIAUSDT,187918.6442,14660427.8,15.52650347,A,7,2,Celestia,USDT-USD +TIA,Binance,TIAUSDT,841382.0946,102103230.5,15.53648038,A,7,2,Celestia,USDT-USD +TIA,CoinbasePro,TIA-USD,383069.4815,25165071.27,15.51546599,A,7,2,Celestia, +TIA,Kraken,TIAUSD,111097.8042,6238500.3,15.50599396,A,7,2,Celestia, +TIA,Kucoin,TIA-USDT,125355.6151,11079068.85,15.55654998,A,7,2,Celestia,USDT-USD +TIA,Mexc,TIA_USDT,100237.1437,2406206.399,15.72168637,A,7,2,Celestia,USDT-USD +TIA,Okx,TIA-USDT,552714.9757,23266716.08,15.50535992,A,7,2,Celestia,USDT-USD +TRX,Kraken,TRXUSD,256930.9396,749814.9748,0.1113946358,A,8,2,TRON, +TRX,Binance,TRXUSDT,613911.798,39811843.58,0.110779356,A,8,2,TRON,USDT-USD +TRX,Huobi,trxusdt,213398.1056,8135870.339,0.1107429915,A,8,2,TRON,USDT-USD +TRX,Okx,TRX-USDT,162323.4689,5484388.924,0.1107910725,A,8,2,TRON,USDT-USD +TRX,Bybit,TRXUSDT,137021.0481,4074633.26,0.1107581644,A,8,2,TRON,USDT-USD +TRX,Kucoin,TRX-USDT,129267.4773,2807145.376,0.1109288304,A,8,2,TRON,USDT-USD +TRX,Mexc,TRX_USDT,676244.1047,18412701.3,0.1107773897,A,8,2,TRON,USDT-USD +TRX,Gate,TRX_USDT,50000,100000,0,A,8,2,TRON,USDT-USD +UNI,Mexc,UNI_USDT,764302.9979,247466.3051,5.761766722,A,7,2,Uniswap,USDT-USD +UNI,Binance,UNIUSDT,399637.0021,17327263.14,5.766455246,A,7,2,Uniswap,USDT-USD +UNI,Bybit,UNIUSDT,67657.94054,2493651.981,5.759751567,A,7,2,Uniswap,USDT-USD +UNI,Kucoin,UNI-USDT,62238.34996,915687.2194,5.769731774,A,7,2,Uniswap,USDT-USD +UNI,Kraken,UNIUSD,110184.576,575064.438,5.744322919,A,7,2,Uniswap, +UNI,Okx,UNI-USDT,188134.5271,8636195.728,5.755593059,A,7,2,Uniswap,USDT-USD +UNI,CoinbasePro,UNI-USD,136046.1025,4933014.237,5.766666815,A,7,2,Uniswap, +WLD,Okx,WLD-USDT,251129.2683,9586681.603,2.292928825,A,6,2,Worldcoin WLD,USDT-USD +WLD,Mexc,WLD_USDT,487737.0114,273829.0676,2.273495768,A,6,2,Worldcoin WLD,USDT-USD +WLD,Bybit,WLDUSDT,56863.91933,3194845.195,2.293914994,A,6,2,Worldcoin WLD,USDT-USD +WLD,Binance,WLDUSDT,309841.6575,26594366.07,2.291594044,A,6,2,Worldcoin WLD,USDT-USD +WLD,Kucoin,WLD-USDT,82240.3581,1301628.522,2.294060237,A,6,2,Worldcoin WLD,USDT-USD +WLD,Gate,WLD_USDT,50000,100000,0,A,6,2,Worldcoin WLD,USDT-USD +XLM,Kucoin,XLM-USDT,85927.31243,1417810.596,0.1117112483,A,8,1,Stellar,USDT-USD +XLM,CoinbasePro,XLM-USD,225276.1032,8883356.851,0.1117142784,A,8,1,Stellar, +XLM,Okx,XLM-USDT,118111.3781,1765770.66,0.1116885221,A,8,1,Stellar,USDT-USD +XLM,Kraken,XLMUSD,176811.499,408089.0655,0.1115158801,A,8,1,Stellar, +XLM,Bitstamp,XLM/USD,72720.87116,733454.4667,0.1113217575,A,8,1,Stellar, +XLM,Mexc,XLM_USDT,1132933.24,618310.8309,0.1117266616,A,8,1,Stellar,USDT-USD +XLM,Bybit,XLMUSDT,88709.74889,3151890.822,0.111753146,A,8,1,Stellar,USDT-USD +XLM,Binance,XLMUSDT,345297.9107,8403369.953,0.1117183159,A,8,1,Stellar,USDT-USD +XRP,Kraken,XRPUSD,814559.1334,6616229.004,0.5113032699,A,9,1,Ripple, +XRP,Binance,XRPUSDT,1884848.243,189067323.1,0.5112663149,A,9,1,Ripple,USDT-USD +XRP,Okx,XRP-USDT,563822.8277,34832795.43,0.5114652914,A,9,1,Ripple,USDT-USD +XRP,CoinbasePro,XRP-USD,730290.9717,38862484.52,0.5115428632,A,9,1,Ripple, +XRP,Huobi,xrpusdt,130799.1755,30764931.78,0.5116267728,A,9,1,Ripple,USDT-USD +XRP,Kucoin,XRP-USDT,711262.8242,17611337.65,0.5113220721,A,9,1,Ripple,USDT-USD +XRP,Bybit,XRPUSDT,574200.8828,60341501.96,0.511381899,A,9,1,Ripple,USDT-USD +XRP,Bitstamp,XRP/USD,893779.877,8546572.012,0.5101769016,A,9,1,Ripple, +XRP,Mexc,XRP_USDT,2253802.257,64063212.39,0.5113602624,A,9,1,Ripple,USDT-USD +CFX,Mexc,CFX_USDT,741948.4908,377232.5696,0.1828636419,B,5,2,Conflux Token,USDT-USD +CFX,Kucoin,CFX-USDT,55943.9793,3166120.044,0.1814791365,B,5,2,Conflux Token,USDT-USD +CFX,Binance,CFXUSDT,425985.235,21370941.25,0.1814141679,B,5,2,Conflux Token,USDT-USD +CFX,Okx,CFX-USDT,225570.4218,11740974.87,0.1814352472,B,5,2,Conflux Token,USDT-USD +CFX,Gate,CFX_USDT,50000,100000,0,B,5,2,Conflux Token,USDT-USD +COMP,Kraken,COMPUSD,53754.17258,243932.5958,53.11057205,B,5,2,Compound Coin, +COMP,Mexc,COMP_USDT,230873.8911,180053.2444,52.64207051,B,5,2,Compound Coin,USDT-USD +COMP,Okx,COMP-USDT,66721.14412,2254113.721,52.63991084,B,5,2,Compound Coin,USDT-USD +COMP,CoinbasePro,COMP-USD,62085.28523,1437341.815,52.63084228,B,5,2,Compound Coin, +COMP,Binance,COMPUSDT,121785.3724,8389374.272,52.68915121,B,5,2,Compound Coin,USDT-USD +EGLD,Kucoin,EGLD-USDT,65252.11559,1177346.419,48.76618226,B,5,2,MultiversX,USDT-USD +EGLD,Binance,EGLDUSDT,271211.9052,11875041.97,48.79330927,B,5,2,MultiversX,USDT-USD +EGLD,Mexc,EGLD_USDT,376293.4565,276441.7792,48.74594483,B,5,2,MultiversX,USDT-USD +EGLD,CoinbasePro,EGLD-USD,52835.82668,917429.1077,48.88945848,B,5,2,MultiversX, +EGLD,Gate,EGLD_USDT,50000,100000,0,B,5,2,MultiversX,USDT-USD +FLOW,Kraken,FLOWUSD,51916.27241,275346.5158,0.7242278161,B,5,2,Flow - Dapper Labs, +FLOW,Binance,FLOWUSDT,293656.6338,9552308.898,0.7291395058,B,5,2,Flow - Dapper Labs,USDT-USD +FLOW,Mexc,FLOW_USDT,483739.2177,113468.7798,0.7323395177,B,5,2,Flow - Dapper Labs,USDT-USD +FLOW,Okx,FLOW-USDT,80766.53137,9510373.237,0.7285897993,B,5,2,Flow - Dapper Labs,USDT-USD +FLOW,Gate,FLOW_USDT,50000,100000,0,B,5,2,Flow - Dapper Labs,USDT-USD +GMT,CoinbasePro,GMT-USD,67428.76141,2248881.711,0.2560028014,B,5,2,STEPN, +GMT,Binance,GMTUSDT,462665.2276,38705519.52,0.2555371175,B,5,2,STEPN,USDT-USD +GMT,Kucoin,GMT-USDT,72869.96385,2005043.366,0.2557195795,B,5,2,STEPN,USDT-USD +GMT,Okx,GMT-USDT,152103.8921,8914015.232,0.2554599347,B,5,2,STEPN,USDT-USD +GMT,Gate,GMT_USDT,50000,100000,0,B,5,2,STEPN,USDT-USD +MEME,Bybit,MEMEUSDT,74659.94612,1660599.611,0.02253908946,B,5,2,Memecoin Price,USDT-USD +MEME,Binance,MEMEUSDT,489840.1554,31554049.74,0.02249870307,B,5,2,Memecoin Price,USDT-USD +MEME,Kucoin,MEME-USDT,50201.45759,1498743.96,0.02243463802,B,5,2,Memecoin Price,USDT-USD +MEME,Mexc,MEME_USDT,184005.5762,478785.4964,0.02260242467,B,5,2,Memecoin Price,USDT-USD +MEME,Gate,MEME_USDT,50000,100000,0,B,5,2,Memecoin Price,USDT-USD +MINA,Mexc,MINA_USDT,110130.5009,610463.4036,1.00715717,B,5,2,Mina,USDT-USD +MINA,CoinbasePro,MINA-USD,59277.03658,6118487.412,1.008738919,B,5,2,Mina, +MINA,Kraken,MINAUSD,104251.6176,1744827.397,1.002235423,B,5,2,Mina, +MINA,Binance,MINAUSDT,163902.8209,27632789.9,1.009175349,B,5,2,Mina,USDT-USD +MINA,Okx,MINA-USDT,58811.29263,5177907.38,1.013323303,B,5,2,Mina,USDT-USD +PEOPLE,Okx,PEOPLE-USDT,318441.9026,37806408.11,0.02743487292,B,5,2,ConstitutionDAO,USDT-USD +PEOPLE,Kucoin,PEOPLE-USDT,64922.56302,3574827.52,0.0273835447,B,5,2,ConstitutionDAO,USDT-USD +PEOPLE,Mexc,PEOPLE_USDT,168543.6372,757272.2515,0.02744498423,B,5,2,ConstitutionDAO,USDT-USD +PEOPLE,Binance,PEOPLEUSDT,192342.5961,85366302.35,0.02746617133,B,5,2,ConstitutionDAO,USDT-USD +PEOPLE,Gate,PEOPLE_USDT,50000,100000,0,B,5,2,ConstitutionDAO,USDT-USD +WAVES,Okx,WAVES-USDT,91892.84196,2741667.219,2.144997825,B,5,2,Waves,USDT-USD +WAVES,Binance,WAVESUSDT,272620.4813,9543737.677,2.143624016,B,5,2,Waves,USDT-USD +WAVES,Mexc,WAVES_USDT,558956.9951,168193.854,2.142261269,B,5,2,Waves,USDT-USD +WAVES,Kucoin,WAVES-USDT,55367.18425,769644.5638,2.142747289,B,5,2,Waves,USDT-USD +WAVES,Kraken,WAVESUSD,45555.16136,112134.6183,2.154872324,B,5,2,Waves, +1INCH,Binance,1INCHUSDT,223047.9107,10123584.48,0.3759697336,C,4,2,1INCH,USDT-USD +1INCH,CoinbasePro,1INCH-USD,63433.64579,1220856.095,0.3761909036,C,4,2,1INCH, +1INCH,Mexc,1INCH_USDT,220805.8565,397303.2595,0.3751712747,C,4,2,1INCH,USDT-USD +1INCH,Okx,1INCH-USDT,87382.44268,4403164.462,0.375964926,C,4,2,1INCH,USDT-USD +ACE,Binance,ACEUSDT,219186.3365,36291711.39,9.125489437,C,2,2,Fusionist,USDT-USD +ACE,Okx,ACE-USDT,120509.3158,8941538.795,9.092071496,C,2,2,Fusionist,USDT-USD +ACH,CoinbasePro,ACH-USD,97110.58491,894158.4549,0.01675701504,C,3,2,Alchemy Pay, +ACH,Binance,ACHUSDT,84700.65638,4414398.216,0.01675085779,C,3,2,Alchemy Pay,USDT-USD +ACH,Mexc,ACH_USDT,192469.0915,100559.3076,0.01679041985,C,3,2,Alchemy Pay,USDT-USD +AEUR,Binance,AEURUSDT,1270915.824,759036.3652,1.085248864,C,1,2,Anchored Coins AEUR,USDT-USD +API3,Mexc,API3_USDT,152284.022,205441.5,2.043375234,C,2,2,API3,USDT-USD +API3,Binance,API3USDT,90101.84241,17128907.56,2.048019395,C,2,2,API3,USDT-USD +AR,Okx,AR-USDT,49845.96145,2809779.829,8.610082522,C,2,2,Arweave,USDT-USD +AR,Binance,ARUSDT,118756.107,5634710.58,8.603353236,C,2,2,Arweave,USDT-USD +ARKM,Binance,ARKMUSDT,101600.3693,9290971.501,0.5035873534,C,2,2,Arkham,USDT-USD +ARKM,Mexc,ARKM_USDT,104313.7334,237646.8392,0.502258142,C,2,2,Arkham,USDT-USD +ARPA,Binance,ARPAUSDT,141483.7342,6962539.152,0.05938416152,C,1,2,ArpaCoin,USDT-USD +ASTR,Mexc,ASTR_USDT,337777.2363,556571.4433,0.1714246019,C,3,2,ASTR,USDT-USD +ASTR,Binance,ASTRUSDT,272250.3728,29115614.2,0.1710438223,C,3,2,ASTR,USDT-USD +ASTR,Okx,ASTR-USDT,61040.31153,7741218.973,0.1712013965,C,3,2,ASTR,USDT-USD +AUCTION,Mexc,AUCTION_USDT,205068.2365,269845.2565,24.64750337,C,3,2,Auction,USDT-USD +AUCTION,Binance,AUCTIONUSDT,141766.5502,24443787.65,24.52525957,C,3,2,Auction,USDT-USD +AUCTION,Okx,AUCTION-USDT,64014.51076,7264691.478,24.43296353,C,3,2,Auction,USDT-USD +AXS,Mexc,AXS_USDT,262075.6017,132406.1769,7.065952702,C,3,2,Axie Infinity,USDT-USD +AXS,Binance,AXSUSDT,231000.3653,12333785.24,7.054601867,C,3,2,Axie Infinity,USDT-USD +AXS,CoinbasePro,AXS-USD,46520.7417,953800.4786,7.063964044,C,3,2,Axie Infinity, +BAKE,Binance,BAKEUSDT,182011.4866,35921179.76,0.3094882759,C,2,2,Bakery Token,USDT-USD +BAKE,Mexc,BAKE_USDT,185326.3247,583699.372,0.3068157366,C,2,2,Bakery Token,USDT-USD +BAND,Binance,BANDUSDT,55086.31129,6612180.017,1.592617506,C,1,2,Band Protocol,USDT-USD +BEAM,Binance,BEAMUSDT,152991.9166,15969226.65,0.01691214062,C,1,2,BEAM (Merit Circle),USDT-USD +BLZ,Binance,BLZUSDT,108417.3522,5588057.361,0.2904520078,C,2,2,Bluzelle,USDT-USD +BLZ,CoinbasePro,BLZ-USD,58365.73324,369664.6277,0.2910902264,C,2,2,Bluzelle, +BOND,Binance,BONDUSDT,101881.7077,6611834.75,3.051545382,C,1,2,BarnBridge,USDT-USD +BSW,Binance,BSWUSDT,46034.40658,4599238.929,0.08886586012,C,1,2,Biswap (BSW),USDT-USD +C98,Mexc,C98_USDT,285083.0197,153443.734,0.2185707406,C,2,2,Coin98,USDT-USD +C98,Binance,C98USDT,189878.1329,5558051.461,0.2185832922,C,2,2,Coin98,USDT-USD +CAKE,Mexc,CAKE_USDT,405312.078,551396.0436,2.447890968,C,2,2,PancakeSwap,USDT-USD +CAKE,Binance,CAKEUSDT,195778.7099,23654981.25,2.454039405,C,2,2,PancakeSwap,USDT-USD +CELO,Mexc,CELO_USDT,125444.7762,302663.9345,0.6476452305,C,3,2,Celo,USDT-USD +CELO,Okx,CELO-USDT,74867.9216,2248910.392,0.6477003752,C,3,2,Celo,USDT-USD +CELO,Binance,CELOUSDT,188957.1416,10478656.48,0.6474077901,C,3,2,Celo,USDT-USD +CHR,Binance,CHRUSDT,98985.18915,8983410.231,0.2454323105,C,1,2,Chromia,USDT-USD +CTSI,Binance,CTSIUSDT,61529.46969,13400594.76,0.211724629,C,1,2,Cartesi,USDT-USD +CYBER,Binance,CYBERUSDT,157494.8313,21582311.99,6.891553463,C,2,2,CyberConnect,USDT-USD +CYBER,Mexc,CYBER_USDT,245967.0815,775034.3955,6.894934361,C,2,2,CyberConnect,USDT-USD +DATA,Binance,DATAUSDT,56436.38905,6577080.731,0.04655652469,C,1,2,Streamr DATAcoin,USDT-USD +DEGO,Binance,DEGOUSDT,49442.4569,6918692.999,2.058938225,C,2,2,Dego Finance,USDT-USD +DEGO,Mexc,DEGO_USDT,47063.22126,145028.8291,2.061702998,C,2,2,Dego Finance,USDT-USD +DIA,Binance,DIAUSDT,46415.86926,5008591.814,0.398446883,C,1,2,DIAToken,USDT-USD +DUSK,Binance,DUSKUSDT,89726.44858,5994345.592,0.24835762,C,1,2,Dusk Network,USDT-USD +EUR,Binance,EURUSDT,914754.1506,25453392.79,1.086238407,C,3,2,Euro,USDT-USD +EUR,Bitstamp,EUR/USD,161923.2853,2925912.624,1.085974486,C,3,2,Euro, +EUR,Kraken,EURUSD,973749.5483,17562785.59,1.087181078,C,3,2,Euro, +FDUSD,Binance,FDUSDUSDT,20819829.91,791868072.3,0.9982990251,C,1,2,First Digital USD,USDT-USD +FRONT,Binance,FRONTUSDT,116592.5536,8033362.547,0.4244166096,C,1,2,Frontier,USDT-USD +FTT,Binance,FTTUSDT,85361.25321,18918457.67,2.637355962,C,2,2,FTX Token,USDT-USD +FTT,Mexc,FTT_USDT,61679.15314,885931.1891,2.625461927,C,2,2,FTX Token,USDT-USD +FXS,Binance,FXSUSDT,76687.07914,7919284.862,9.870999715,C,1,2,Frax Share,USDT-USD +GAL,Binance,GALUSDT,123198.1518,6183386.884,1.713442116,C,1,2,Project Galaxy,USDT-USD +GAS,Okx,GAS-USDT,71550.26438,3589890.498,5.559745992,C,2,2,Gas,USDT-USD +GAS,Binance,GASUSDT,143459.5949,16249734.4,5.551653689,C,2,2,Gas,USDT-USD +GLMR,Binance,GLMRUSDT,66465.37977,5440648.9,0.351519818,C,2,2,Moonbeam Network Glimmer Token,USDT-USD +GLMR,Mexc,GLMR_USDT,132937.7799,226967.7255,0.3519219251,C,2,2,Moonbeam Network Glimmer Token,USDT-USD +GMX,Binance,GMXUSDT,86050.25266,8488792.893,41.68565019,C,1,2,GMX,USDT-USD +GTC,Binance,GTCUSDT,63833.57202,5559771.674,1.109504239,C,1,2,Gitcoin,USDT-USD +HFT,Mexc,HFT_USDT,92867.50229,155840.9593,0.3163831693,C,3,2,Hashflow,USDT-USD +HFT,CoinbasePro,HFT-USD,67639.33185,1082720.501,0.3166013692,C,3,2,Hashflow, +HFT,Binance,HFTUSDT,86389.41028,4335472.459,0.3155912724,C,3,2,Hashflow,USDT-USD +HIFI,Binance,HIFIUSDT,65279.10529,4308106.952,0.5695358478,C,1,2,Hifi Finance,USDT-USD +HIGH,Binance,HIGHUSDT,94832.54951,5568886.461,1.416275081,C,1,2,Highstreet,USDT-USD +HOOK,Binance,HOOKUSDT,125566.4187,10904796.41,0.8514358619,C,1,2,Hooked Protocol,USDT-USD +HOT,Binance,HOTUSDT,88284.00246,4898150.064,0.00182001891,C,1,2,Holo,USDT-USD +ID,Binance,IDUSDT,105739.9887,10529785.09,0.2642775002,C,2,2,Space ID,USDT-USD +ID,Mexc,ID_USDT,99019.7159,293195.7436,0.2653625693,C,2,2,Space ID,USDT-USD +ILV,Binance,ILVUSDT,65967.97711,4756421.779,72.43485363,C,2,2,Illuvium,USDT-USD +ILV,Mexc,ILV_USDT,101351.5141,124582.7065,72.49241072,C,2,2,Illuvium,USDT-USD +IMX,Binance,IMXUSDT,159306.9212,9773348.424,1.833882485,C,4,2,Immutable X,USDT-USD +IMX,Mexc,IMX_USDT,125843.6309,288710.9571,1.831721582,C,4,2,Immutable X,USDT-USD +IMX,CoinbasePro,IMX-USD,63576.38536,3545209.657,1.832415885,C,4,2,Immutable X, +IMX,Okx,IMX-USDT,63231.7586,4815890.341,1.835477545,C,4,2,Immutable X,USDT-USD +IOTA,Binance,IOTAUSDT,156813.2627,9448427.026,0.2404979188,C,2,2,IOTA,USDT-USD +IOTA,Okx,IOTA-USDT,81364.86526,1422701.965,0.240249504,C,2,2,IOTA,USDT-USD +IOTX,Mexc,IOTX_USDT,63717.81113,114944.2482,0.04098756361,C,2,2,IoTeX,USDT-USD +IOTX,Binance,IOTXUSDT,118425.8892,5645105.663,0.04116999109,C,2,2,IoTeX,USDT-USD +JASMY,CoinbasePro,JASMY-USD,106938.7996,2456750.498,0.004883328831,C,4,2,Jasmy, +JASMY,Kucoin,JASMY-USDT,46532.2408,878234.3701,0.004897641967,C,4,2,Jasmy,USDT-USD +JASMY,Binance,JASMYUSDT,103914.894,4638424.246,0.004895538164,C,4,2,Jasmy,USDT-USD +JASMY,Mexc,JASMY_USDT,118057.5456,426212.9186,0.004900948254,C,4,2,Jasmy,USDT-USD +JOE,Binance,JOEUSDT,95891.84261,4986487.55,0.4210333582,C,2,2,TraderJoe,USDT-USD +JOE,Mexc,JOE_USDT,106334.2549,155616.5895,0.4240505807,C,2,2,TraderJoe,USDT-USD +KDA,Binance,KDAUSDT,52068.57953,6603653.169,0.9864134387,C,1,2,Kadena,USDT-USD +KLAY,Mexc,KLAY_USDT,198792.0879,193094.4612,0.1935774129,C,2,2,Klaytn,USDT-USD +KLAY,Binance,KLAYUSDT,102537.9319,8166690.792,0.1947100267,C,2,2,Klaytn,USDT-USD +KP3R,Binance,KP3RUSDT,54560.4206,6827068.529,68.97052078,C,1,2,Keep3rV1,USDT-USD +KSM,Okx,KSM-USDT,49131.02426,2272156.7,35.8946584,C,4,2,Kusama,USDT-USD +KSM,Kraken,KSMUSD,82906.03275,662412.7086,35.91468468,C,4,2,Kusama, +KSM,Mexc,KSM_USDT,51623.03643,146361.7075,35.99359072,C,4,2,Kusama,USDT-USD +KSM,Binance,KSMUSDT,104173.4084,6749163.486,35.92864815,C,4,2,Kusama,USDT-USD +LEVER,Binance,LEVERUSDT,103584.2033,8631452.701,0.001297870719,C,2,2,leverfi,USDT-USD +LEVER,Mexc,LEVER_USDT,269243.6154,100150.2478,0.001297685532,C,2,2,leverfi,USDT-USD +LOOM,Binance,LOOMUSDT,72863.84961,6250861.053,0.08656430192,C,1,2,Loom Network,USDT-USD +LPT,Binance,LPTUSDT,124147.244,4976570.721,6.65831672,C,1,2,Livepeer,USDT-USD +LQTY,Mexc,LQTY_USDT,289158.432,110300.6315,1.195620223,C,2,2,Liquity,USDT-USD +LQTY,Binance,LQTYUSDT,127715.2767,7023298.015,1.191924708,C,2,2,Liquity,USDT-USD +LRC,CoinbasePro,LRC-USD,59174.11432,3383810.585,0.2285031455,C,3,2,Loopring, +LRC,Mexc,LRC_USDT,45956.53557,124278.9266,0.2288337603,C,3,2,Loopring,USDT-USD +LRC,Binance,LRCUSDT,146930.5688,6969566.753,0.2286497941,C,3,2,Loopring,USDT-USD +LUNA,Okx,LUNA-USDT,140979.1409,2806262.42,9.33E-05,C,4,2,Terra Luna Classic,USDT-USD +LUNA,Mexc,LUNA_USDT,285530.9676,548675.4766,9.33E-05,C,4,2,Terra Luna Classic,USDT-USD +LUNA,Binance,LUNAUSDT,327295.5899,25245311.88,9.32E-05,C,4,2,Terra Luna Classic,USDT-USD +LUNA,Kucoin,LUNA-USDT,162730.8732,2161850.295,9.34E-05,C,4,2,Terra Luna Classic,USDT-USD +LUNA2,Okx,LUNA2-USDT,116714.2838,5214721.607,0.5862913961,C,4,2,Terra Luna 2,USDT-USD +LUNA2,Binance,LUNA2USDT,283182.821,12663702.95,0.5867542898,C,4,2,Terra Luna 2,USDT-USD +LUNA2,Kucoin,LUNA2-USDT,83502.73597,2063709.03,0.586261171,C,4,2,Terra Luna 2,USDT-USD +LUNA2,Mexc,LUNA2_USDT,108379.4362,339907.5678,0.5861178482,C,4,2,Terra Luna 2,USDT-USD +MAGIC,Mexc,MAGIC_USDT,264533.7207,290531.8239,0.9620408497,C,4,2,MAGIC,USDT-USD +MAGIC,Binance,MAGICUSDT,220494.1405,15191286.46,0.9583392892,C,4,2,MAGIC,USDT-USD +MAGIC,Okx,MAGIC-USDT,105405.7972,5401719.867,0.9595420314,C,4,2,MAGIC,USDT-USD +MAGIC,Gate,MAGIC_USDT,50000,100000,0,C,4,2,MAGIC,USDT-USD +MANTA,Bybit,MANTAUSDT,53885.15969,18009025.51,3.063765317,C,2,2,Manta,USDT-USD +MANTA,Binance,MANTAUSDT,403816.6432,259161217.8,3.08167379,C,2,2,Manta,USDT-USD +MAV,Mexc,MAV_USDT,185736.3436,457436.4408,0.5373792545,C,2,2,Maverick Protocol,USDT-USD +MAV,Binance,MAVUSDT,99388.71969,22924519.05,0.536668425,C,2,2,Maverick Protocol,USDT-USD +MOVR,Binance,MOVRUSDT,140137.8354,34228440.2,22.26851193,C,1,2,Moonriver,USDT-USD +NEO,Binance,NEOUSDT,174759.4944,6735135.997,10.50592939,C,2,2,NEO,USDT-USD +NEO,Mexc,NEO_USDT,285086.2477,101306.1126,10.51571434,C,2,2,NEO,USDT-USD +NFP,Binance,NFPUSDT,136224.0611,40056163.12,0.4984980965,C,1,2,NFPrompt,USDT-USD +NMR,Mexc,NMR_USDT,56441.59171,117950.3206,20.80947578,C,1,2,Numeraire,USDT-USD +NTRN,Binance,NTRNUSDT,190762.7558,22412232.21,1.043698576,C,3,2,Neutron,USDT-USD +NTRN,Kucoin,NTRN-USDT,61322.46516,4357183.961,1.0429518,C,3,2,Neutron,USDT-USD +NTRN,Mexc,NTRN_USDT,85753.64033,420380.4134,1.049013149,C,3,2,Neutron,USDT-USD +OGN,Mexc,OGN_USDT,133395.5319,153105.7316,0.1506897838,C,2,2,Origin Protocol,USDT-USD +OGN,Binance,OGNUSDT,114751.9375,8567467.491,0.1509501147,C,2,2,Origin Protocol,USDT-USD +ONE,Mexc,ONE_USDT,103633.3233,169389.5422,0.01381296016,C,1,2,Harmony,USDT-USD +ONT,Binance,ONTUSDT,101745.7079,6573307.838,0.2378290263,C,2,2,Ontology,USDT-USD +ONT,Mexc,ONT_USDT,134099.6108,119281.0604,0.2328763351,C,2,2,Ontology,USDT-USD +OSMO,CoinbasePro,OSMO-USD,45573.4572,505627.9592,1.434332792,C,2,2,osmosis, +OSMO,Binance,OSMOUSDT,184069.0761,6248594.99,1.436154852,C,2,2,osmosis,USDT-USD +OXT,Binance,OXTUSDT,121674.5039,4092402.317,0.08759780776,C,1,2,Orchid,USDT-USD +PENDLE,Mexc,PENDLE_USDT,94363.66432,302375.5024,2.414568281,C,2,2,Pendle,USDT-USD +PENDLE,Binance,PENDLEUSDT,198805.1833,19093374.54,2.411570446,C,2,2,Pendle,USDT-USD +PERP,Mexc,PERP_USDT,70959.09524,263694.8546,1.108616603,C,2,2,Perpetual Protocol,USDT-USD +PERP,Binance,PERPUSDT,97699.23947,18395585.05,1.101367961,C,2,2,Perpetual Protocol,USDT-USD +PHB,Binance,PHBUSDT,87353.37405,5541104.607,0.8191750331,C,1,2,Phoenix Global,USDT-USD +POLYX,Binance,POLYXUSDT,77106.52126,4877840.89,0.1556027116,C,1,2,Polymex,USDT-USD +POWR,Binance,POWRUSDT,101684.5648,32858394.18,0.3110983216,C,1,2,Power Ledger,USDT-USD +PROS,Binance,PROSUSDT,47335.53338,6601983.056,0.4958016306,C,1,2,Prosper,USDT-USD +PYR,Mexc,PYR_USDT,136917.2423,282019.549,5.525717506,C,2,2,Vulcan Forged,USDT-USD +PYR,Binance,PYRUSDT,67837.28685,6095379.499,5.513382639,C,2,2,Vulcan Forged,USDT-USD +QI,Binance,QIUSDT,65705.70399,4479686.822,0.01492820908,C,1,2,Benqi,USDT-USD +QNT,Binance,QNTUSDT,150130.1919,4958738.066,105.1210689,C,3,2,Quant,USDT-USD +QNT,CoinbasePro,QNT-USD,77932.07738,2702196.734,104.8651886,C,3,2,Quant, +QNT,Mexc,QNT_USDT,319187.1936,283469.3662,105.6252627,C,3,2,Quant,USDT-USD +RAD,Binance,RADUSDT,64303.27111,13728893.14,1.863131994,C,1,2,Radicle,USDT-USD +RAY,Binance,RAYUSDT,49059.70839,10476697.73,1.086883488,C,1,2,Raydium,USDT-USD +RDNT,Okx,RDNT-USDT,99487.73444,4908849.751,0.2781249382,C,2,2,Radiant Capital,USDT-USD +RDNT,Binance,RDNTUSDT,202234.405,19676252.31,0.27834352,C,2,2,Radiant Capital,USDT-USD +RIF,Binance,RIFUSDT,102720.0668,5575326.551,0.126668978,C,1,2,RIF Token,USDT-USD +RLC,CoinbasePro,RLC-USD,45038.78592,956263.9594,2.193508506,C,2,2,iExec RLC, +RLC,Binance,RLCUSDT,113296.5214,10458930.76,2.240062189,C,2,2,iExec RLC,USDT-USD +ROSE,CoinbasePro,ROSE-USD,94865.22605,2007709.124,0.09853848605,C,4,2,Oasis Network, +ROSE,Kucoin,ROSE-USDT,60914.79989,2255011.858,0.09829991324,C,4,2,Oasis Network,USDT-USD +ROSE,Binance,ROSEUSDT,188268.4384,13037035.32,0.09827645727,C,4,2,Oasis Network,USDT-USD +ROSE,Mexc,ROSE_USDT,87574.57166,553950.1122,0.09824638256,C,4,2,Oasis Network,USDT-USD +RUNE,Kucoin,RUNE-USDT,150957.3196,4886709.369,4.034373849,C,3,2,Thorchain,USDT-USD +RUNE,Kraken,RUNEUSD,64699.56261,918799.2368,4.070013999,C,3,2,Thorchain, +RUNE,Binance,RUNEUSDT,380276.4214,62447654.52,4.036291948,C,3,2,Thorchain,USDT-USD +SANTOS,Binance,SANTOSUSDT,48414.7599,10421735.09,4.748221741,C,1,2,Santos FC Fan Token,USDT-USD +SATS,Binance,SATSUSDT,270661.8914,65862844.2,0.0003862181853,C,2,2,SATS (Ordinals),USDT-USD +SATS,Okx,SATS-USDT,186918.757,23374134.77,3.87E-07,C,2,2,SATS (Ordinals),USDT-USD +SC,Binance,SCUSDT,56737.90689,11988942.85,0.008758778298,C,2,2,Siacoin,USDT-USD +SC,Kraken,SCUSD,72897.05559,939274.4661,0.009133476567,C,2,2,Siacoin, +SKL,CoinbasePro,SKL-USD,89253.48802,7106650.138,0.07392654734,C,2,2,SKALE Network, +SKL,Binance,SKLUSDT,245593.9026,14952643.43,0.07413113803,C,2,2,SKALE Network,USDT-USD +SLEEPAI,Binance,SLEEPAIUSDT,226926.639,75074601.74,1.03330556,C,1,2,Sleepless AI,USDT-USD +SLP,Binance,SLPUSDT,75829.29241,4740257.278,0.002835530307,C,1,2,Smooth Love Potion,USDT-USD +SSV,Binance,SSVUSDT,323731.8901,22076581.02,28.20046712,C,3,2,SSV Token,USDT-USD +SSV,Okx,SSV-USDT,138780.4853,10437857.38,28.20537722,C,3,2,SSV Token,USDT-USD +SSV,Mexc,SSV_USDT,72456.44543,262132.0541,28.25282324,C,3,2,SSV Token,USDT-USD +STG,Binance,STGUSDT,108865.1255,5746995.142,0.5045724388,C,2,2,Stargate Finance,USDT-USD +STG,Mexc,STG_USDT,84129.48408,141951.2826,0.503347766,C,2,2,Stargate Finance,USDT-USD +STORJ,Okx,STORJ-USDT,107087.3563,3141734.853,0.5481481935,C,4,2,Storj,USDT-USD +STORJ,Mexc,STORJ_USDT,379448.5526,135570.0261,0.542814224,C,4,2,Storj,USDT-USD +STORJ,Binance,STORJUSDT,231654.1428,10131073.03,0.5507150911,C,4,2,Storj,USDT-USD +STORJ,CoinbasePro,STORJ-USD,51027.83869,779419.6502,0.5473696668,C,4,2,Storj, +STRAX,Binance,STRAXUSDT,52905.44524,8603073.461,0.859584148,C,1,2,STRAX Token,USDT-USD +SUPER,CoinbasePro,SUPER-USD,50756.77233,2582255.195,0.5798868417,C,2,2,SuperCoin, +SUPER,Binance,SUPERUSDT,118810.403,6113031.497,0.5750921405,C,2,2,SuperCoin,USDT-USD +SYN,Binance,SYNUSDT,47988.72934,8355559.222,0.8286535512,C,1,2,Synapse,USDT-USD +T,Binance,TUSDT,67613.62552,15650726.81,0.0266303701,C,1,2,Threshold Network Token,USDT-USD +THETA,Okx,THETA-USDT,45307.20349,1748100.687,0.9536451092,C,3,2,Theta Token,USDT-USD +THETA,Kucoin,THETA-USDT,50799.11682,953331.377,0.9531037657,C,3,2,Theta Token,USDT-USD +THETA,Binance,THETAUSDT,124500.3519,6901396.198,0.9509138016,C,3,2,Theta Token,USDT-USD +TRB,Binance,TRBUSDT,390984.8389,100946113.2,103.9610988,C,3,2,Tellor Tributes,USDT-USD +TRB,CoinbasePro,TRB-USD,88075.97643,17801109.2,104.1184355,C,3,2,Tellor Tributes, +TRB,Okx,TRB-USDT,186073.443,21824721.52,104.3779998,C,3,2,Tellor Tributes,USDT-USD +TUSD,Mexc,TUSD_USDT,3321290.381,438627.3706,0.9834745064,C,2,2,TrueUSD,USDT-USD +TUSD,Binance,TUSDUSDT,8528624.338,127150976.8,0.983448235,C,2,2,TrueUSD,USDT-USD +TWT,Mexc,TWT_USDT,53326.82705,174132.0743,1.098094178,C,2,2,Trust Wallet Token,USDT-USD +TWT,Binance,TWTUSDT,82499.98134,4322265.177,1.095769461,C,2,2,Trust Wallet Token,USDT-USD +UMA,Binance,UMAUSDT,59739.75936,40479668.6,4.951798234,C,1,2,UMA,USDT-USD +UNFI,Binance,UNFIUSDT,131780.4267,7051952.799,5.639134191,C,2,2,Unifi Protocol DAO,USDT-USD +UNFI,Mexc,UNFI_USDT,130778.7414,110299.8533,5.64795796,C,2,2,Unifi Protocol DAO,USDT-USD +USTC,Binance,USTCUSDT,104193.9018,15652520.83,0.02414702556,C,3,2,TerraClassicUSD,USDT-USD +USTC,Okx,USTC-USDT,79755.13934,3789072.942,0.02416523268,C,3,2,TerraClassicUSD,USDT-USD +USTC,Mexc,USTC_USDT,160428.8833,291642.1385,0.02413599889,C,3,2,TerraClassicUSD,USDT-USD +VANRY,Binance,VANRYUSDT,52749.63014,6196670.624,0.05698171548,C,1,2,VANAR,USDT-USD +VENUS,Binance,VENUSUSDT,142572.1277,4451222.365,11.45017461,C,1,2,VENUS,USDT-USD +VET,Kucoin,VET-USDT,47075.4841,1459523.548,0.02683736035,C,4,2,VeChain Thor Blockchain,USDT-USD +VET,Binance,VETUSDT,156275.2048,10448229.43,0.02681801761,C,4,2,VeChain Thor Blockchain,USDT-USD +VET,CoinbasePro,VET-USD,76873.43971,1778291.301,0.02682562648,C,4,2,VeChain Thor Blockchain, +VET,Mexc,VET_USDT,206314.8694,264812.6117,0.02680541699,C,4,2,VeChain Thor Blockchain,USDT-USD +WBTC,Binance,WBTCUSDT,112200.2527,1683109.194,39963.72177,C,1,2,Wrapped Bitcoin,USDT-USD +WING,Binance,WINGUSDT,62333.07274,6305353.437,8.576492466,C,2,2,Wing Finance,USDT-USD +WING,Mexc,WING_USDT,145609.7828,144300.5718,8.312628247,C,2,2,Wing Finance,USDT-USD +WOO,Kucoin,WOO-USDT,56843.55491,2278027.521,0.3371057009,C,4,2,Wootrade Network,USDT-USD +WOO,Binance,WOOUSDT,151442.7656,10671160.74,0.3366437512,C,4,2,Wootrade Network,USDT-USD +WOO,Okx,WOO-USDT,69348.19917,2025176.877,0.3367207662,C,4,2,Wootrade Network,USDT-USD +WOO,Mexc,WOO_USDT,199456.2006,304849.2574,0.3360550686,C,4,2,Wootrade Network,USDT-USD +XAI,Binance,XAIUSDT,364809.2616,121646517.1,0.7172651447,C,3,2,Xai,USDT-USD +XAI,Kucoin,XAI-USDT,80369.25096,6679818.276,0.7140484103,C,3,2,Xai,USDT-USD +XAI,Mexc,XAI_USDT,62519.5629,2089596.926,0.7163100149,C,3,2,Xai,USDT-USD +XMR,Mexc,XMR_USDT,637929.6215,5399712.779,155.4816876,C,4,2,Monero,USDT-USD +XMR,Kucoin,XMR-USDT,75861.34173,8391529.693,155.526225,C,4,2,Monero,USDT-USD +XMR,Kraken,XMRUSD,152433.9495,1066363.955,155.8084502,C,4,2,Monero, +XMR,Binance,XMRUSDT,325239.0746,14167130.57,155.4210491,C,4,2,Monero,USDT-USD +XTZ,Binance,XTZUSDT,74018.47298,6036351.412,0.9344370358,C,2,2,Tezos,USDT-USD +XTZ,Kraken,XTZUSD,115428.0625,918276.8649,0.9324110152,C,2,2,Tezos, +YFI,Binance,YFIUSDT,106489.0261,4283188.193,7008.442394,C,2,2,yearn.finance,USDT-USD +YFI,CoinbasePro,YFI-USD,69803.71322,2485716.132,7006.499518,C,2,2,yearn.finance, +YGG,Binance,YGGUSDT,255512.6937,15978592.67,0.4253489864,C,3,2,Yield Guild Games,USDT-USD +YGG,Okx,YGG-USDT,112564.4286,8795935.186,0.4242942872,C,3,2,Yield Guild Games,USDT-USD +YGG,Mexc,YGG_USDT,291214.2319,384654.8937,0.4279915233,C,3,2,Yield Guild Games,USDT-USD +ZEC,Mexc,ZEC_USDT,508650.6599,287365.0153,21.96116327,C,2,2,Zcash,USDT-USD +ZEC,Binance,ZECUSDT,107748.7569,6231023.464,22.06774527,C,2,2,Zcash,USDT-USD +ZEN,Binance,ZENUSDT,121239.4862,5983871.133,7.622205603,C,1,2,Horizen,USDT-USD +ZIL,Binance,ZILUSDT,78122.06511,5951041.305,0.01981457877,C,3,2,Zilliqa,USDT-USD +ZIL,Mexc,ZIL_USDT,164288.1689,136450.7828,0.01983149916,C,3,2,Zilliqa,USDT-USD +ZIL,Kucoin,ZIL-USDT,51622.45768,620061.2048,0.0198240821,C,3,2,Zilliqa,USDT-U diff --git a/public/configs/potentialMarketParameters.csv b/public/configs/potentialMarketParameters.csv new file mode 100644 index 0000000..4be255e --- /dev/null +++ b/public/configs/potentialMarketParameters.csv @@ -0,0 +1,68 @@ +base_asset,reference_price,num_oracles,liquidity_tier,asset_name,p,atomic_resolution,min_exchanges,min_price_change_ppm,price_exponent,step_base_quantum,ticksize_exponent,subticks_per_tick,min_order_size,quantum_conversion_exponent +AAVE,88.41933533,7,2,AAVE,1,-7,3,4000,-8,1000000,-3,1000000,1000000,-9 +ADA,0.4713770925,9,1,Cardano,-1,-5,3,2500,-10,1000000,-3,1000000,1000000,-9 +AGIX,0.2111443656,6,2,SingularityNET,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +ALGO,0.1613430877,6,2,Algorand,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +APE,1.121514886,7,2,ApeCoin,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +APT,7.323447408,8,2,Aptos,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +ARB,1.701673341,8,1,Arbitrum,0,-6,3,2500,-9,1000000,-3,1000000,1000000,-9 +ATOM,8.050389759,8,2,Cosmos,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +AVAX,30.38272818,9,1,Avalanche,1,-7,3,2500,-8,1000000,-3,1000000,1000000,-9 +BCH,236.328774,9,1,Bitcoin Cash,2,-8,3,2500,-7,1000000,-3,1000000,1000000,-9 +BLUR,0.6050104719,7,2,Blur,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +BNB,243.1294766,6,2,Binance Coin,2,-8,3,4000,-7,1000000,-3,1000000,1000000,-9 +BONK,1.09E-05,6,2,Bonk Token,-5,-1,3,4000,-14,1000000,-3,1000000,1000000,-9 +BTC,39909.14585,9,1,Bitcoin,4,-10,3,2500,-5,1000000,-3,1000000,1000000,-9 +CFX,0.1454384387,5,2,Conflux Token,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +CHZ,0.08712744693,6,2,Chiliz,-2,-4,3,4000,-11,1000000,-3,1000000,1000000,-9 +COMP,52.74250938,5,2,Compound Coin,1,-7,3,4000,-8,1000000,-3,1000000,1000000,-9 +CRV,0.4443624604,6,2,Curve DAO Token,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +DOGE,0.07793177878,9,1,Dogecoin,-2,-4,3,2500,-11,1000000,-3,1000000,1000000,-9 +DOT,6.452414058,8,1,Polkadot,0,-6,3,2500,-9,1000000,-3,1000000,1000000,-9 +EGLD,39.03897897,5,2,MultiversX,1,-7,3,4000,-8,1000000,-3,1000000,1000000,-9 +ENS,14.85690244,6,2,Ethereum Name Service (ENS),1,-7,3,4000,-8,1000000,-3,1000000,1000000,-9 +EOS,0.5977251446,8,2,Eos,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +ETC,22.84861344,8,1,Ethereum Classic,1,-7,3,2500,-8,1000000,-3,1000000,1000000,-9 +ETH,2211.721168,9,1,Ethereum,3,-9,3,2500,-6,1000000,-3,1000000,1000000,-9 +FET,0.5864541562,6,2,Fetch AI,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +FIL,4.930296959,8,1,Filecoin,0,-6,3,2500,-9,1000000,-3,1000000,1000000,-9 +FLOW,0.5828593278,5,2,Flow - Dapper Labs,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +FTM,0.3359983176,6,2,Fantom,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +GALA,0.01840015547,6,2,Gala,-2,-4,3,4000,-11,1000000,-3,1000000,1000000,-9 +GMT,0.2045438866,5,2,STEPN,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +GRT,0.128018834,7,2,The Graph,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +HBAR,0.07127967284,7,2,Hedera Hashgraph,-2,-4,3,4000,-11,1000000,-3,1000000,1000000,-9 +ICP,11.47442186,7,2,Internet Computer,1,-7,3,4000,-8,1000000,-3,1000000,1000000,-9 +INJ,31.78305093,7,2,Injective Protocol,1,-7,3,4000,-8,1000000,-3,1000000,1000000,-9 +JTO,1.886208515,6,2,Jito,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +KAVA,0.5751546332,6,2,Kava,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +LDO,2.524539255,8,2,Lido DAO,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +LINK,13.81655633,8,1,ChainLink,1,-7,3,2500,-8,1000000,-3,1000000,1000000,-9 +LTC,65.43204352,9,1,Litecoin,1,-7,3,2500,-8,1000000,-3,1000000,1000000,-9 +MANA,0.3716510229,7,2,Decentraland,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +MASK,2.787727403,7,2,Mask Network,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +MATIC,0.7288467315,9,1,Matic Network,-1,-5,3,2500,-10,1000000,-3,1000000,1000000,-9 +MEME,0.01801497104,5,2,Memecoin Price,-2,-4,3,4000,-11,1000000,-3,1000000,1000000,-9 +MINA,1.008126033,5,2,Mina,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +MKR,2113.151651,6,2,Maker,3,-9,3,4000,-6,1000000,-3,1000000,1000000,-9 +NEAR,2.674751578,8,1,Near,0,-6,3,2500,-9,1000000,-3,1000000,1000000,-9 +OP,2.456951554,7,2,Optimism,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +ORDI,43.0494516,6,2,Ordinals,1,-7,3,4000,-8,1000000,-3,1000000,1000000,-9 +PEOPLE,0.02194591464,5,2,ConstitutionDAO,-2,-4,3,4000,-11,1000000,-3,1000000,1000000,-9 +PEPE,1.02E-06,6,2,Pepe,-6,0,3,4000,-15,1000000,-3,1000000,1000000,-9 +RNDR,3.777241656,6,2,Render Token,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +SAND,0.3751083804,7,2,SAND,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +SEI,0.6149970988,7,2,Sei,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +SHIB,8.84E-06,8,1,Shiba Inu,-6,0,3,2500,-15,1000000,-3,1000000,1000000,-9 +SNX,3.130619706,6,2,Synthetix Network Token,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +SOL,87.46988589,9,1,Solana,1,-7,3,2500,-8,1000000,-3,1000000,1000000,-9 +STX,1.255152213,7,2,Stacks,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +SUI,1.224271493,6,2,SuiNetwork,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +SUSHI,0.8926299706,6,2,Sushi,-1,-5,3,4000,-10,1000000,-3,1000000,1000000,-9 +TIA,15.55257715,7,2,Celestia,1,-7,3,4000,-8,1000000,-3,1000000,1000000,-9 +TRX,0.09702155504,8,2,TRON,-2,-4,3,4000,-11,1000000,-3,1000000,1000000,-9 +UNI,5.760612586,7,2,Uniswap,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +WAVES,2.145700544,5,2,Waves,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +WLD,1.907665645,6,2,Worldcoin WLD,0,-6,3,4000,-9,1000000,-3,1000000,1000000,-9 +XLM,0.1116437262,8,1,Stellar,-1,-5,3,2500,-10,1000000,-3,1000000,1000000,-9 +XRP,0.5112717386,9,1,Ripple,-1,-5,3,2500,-10,1000000,-3,1000000,1000000,-9 diff --git a/public/currencies/bonk.png b/public/currencies/bonk.png new file mode 100644 index 0000000000000000000000000000000000000000..2f1f9f833c2b3934d20b2b85429a539d573805a8 GIT binary patch literal 112037 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 import('@/pages/markets/NewMarket')); const MarketsPage = lazy(() => import('@/pages/markets/Markets')); const PortfolioPage = lazy(() => import('@/pages/portfolio/Portfolio')); const AlertsPage = lazy(() => import('@/pages/AlertsPage')); @@ -81,7 +83,10 @@ const Content = () => { } /> - } /> + + } /> + } /> + } /> {isTablet && ( <> @@ -136,6 +141,7 @@ const providers = [ wrapProvider(LocalNotificationsProvider), wrapProvider(NotificationsProvider), wrapProvider(DialogAreaProvider), + wrapProvider(PotentialMarketsProvider), wrapProvider(AppThemeProvider), ]; diff --git a/src/components/AssetIcon.tsx b/src/components/AssetIcon.tsx index 1ea994b..9d30239 100644 --- a/src/components/AssetIcon.tsx +++ b/src/components/AssetIcon.tsx @@ -16,6 +16,7 @@ const assetIcons = { AVAX: '/currencies/avax.png', BCH: '/currencies/bch.png', BLUR: '/currencies/blur.png', + BONK: '/currencies/bonk.png', BTC: '/currencies/btc.png', CELO: '/currencies/celo.png', COMP: '/currencies/comp.png', diff --git a/src/components/ComboboxMenu.tsx b/src/components/ComboboxMenu.tsx index 8009145..e322047 100644 --- a/src/components/ComboboxMenu.tsx +++ b/src/components/ComboboxMenu.tsx @@ -51,8 +51,9 @@ export const ComboboxMenu = { - if (value.replace(/ /g, '').includes(search.replace(/ /g, ''))) return 1; - return 0; + value.replace(/ /g, '').toLowerCase().includes(search.replace(/ /g, '').toLowerCase()) + ? 1 + : 0; }} className={className} $withStickyLayout={withStickyLayout} diff --git a/src/components/FormInput.tsx b/src/components/FormInput.tsx index da0591f..588c5df 100644 --- a/src/components/FormInput.tsx +++ b/src/components/FormInput.tsx @@ -32,7 +32,7 @@ export const FormInput = forwardRef( isValidationAttached={validationConfig?.attached} > - + {slotRight} @@ -85,11 +85,11 @@ Styled.InputContainer = styled.div<{ hasSlotRight?: boolean }>` `} `; -Styled.WithLabel = styled(WithLabel)` +Styled.WithLabel = styled(WithLabel)<{ disabled?: boolean }>` ${formMixins.inputLabel} label { - cursor: text; + ${({ disabled }) => !disabled && 'cursor: text;'} padding: var(--form-input-paddingY) var(--form-input-paddingX) 0; } `; diff --git a/src/components/Loading/LoadingSpinner.tsx b/src/components/Loading/LoadingSpinner.tsx index d4bb299..400438e 100644 --- a/src/components/Loading/LoadingSpinner.tsx +++ b/src/components/Loading/LoadingSpinner.tsx @@ -11,6 +11,7 @@ export const LoadingSpinner: React.FC<{ return ( {tag}} + {slotRight} ); } diff --git a/src/components/WithDetailsReceipt.tsx b/src/components/WithDetailsReceipt.tsx index 6f733cd..44fb64e 100644 --- a/src/components/WithDetailsReceipt.tsx +++ b/src/components/WithDetailsReceipt.tsx @@ -40,5 +40,5 @@ Styled.Details = styled(Details)` padding: 0.375rem 0.75rem 0.25rem; - font-size: 0.8125em; + font-size: var(--details-item-fontSize, 0.8125em); `; diff --git a/src/constants/dialogs.ts b/src/constants/dialogs.ts index 7ce2904..e5cf8fd 100644 --- a/src/constants/dialogs.ts +++ b/src/constants/dialogs.ts @@ -19,6 +19,8 @@ export enum DialogTypes { Transfer = 'Transfer', Withdraw = 'Withdraw', ManageFunds = 'ManageFunds', + NewMarketMessageDetails = 'NewMarketMessageDetails', + NewMarketAgreement = 'NewMarketAgreement', } export enum TradeBoxDialogTypes { diff --git a/src/constants/indexer.ts b/src/constants/indexer.ts new file mode 100644 index 0000000..12c2f02 --- /dev/null +++ b/src/constants/indexer.ts @@ -0,0 +1,23 @@ +/** + * Temporary Indexer types + * remove when Indexer type lib is available through @dydxprotocol/v4-client-js + */ +export type PerpetualMarketResponse = { + clobPairId: string; + ticker: string; + status: string; + oraclePrice: string; + priceChange24H: string; + volume24H: string; + trades24H: number; + nextFundingRate: string; + initialMarginFraction: string; + maintenanceMarginFraction: string; + openInterest: string; + atomicResolution: number; + quantumConversionExponent: number; + tickSize: string; + stepSize: string; + stepBaseQuantums: number; + subticksPerTick: number; +}; diff --git a/src/constants/potentialMarkets.ts b/src/constants/potentialMarkets.ts new file mode 100644 index 0000000..da2707d --- /dev/null +++ b/src/constants/potentialMarkets.ts @@ -0,0 +1,85 @@ +export type ExchangeConfigParsedCsv = Array<{ + base_asset: string; + exchange: string; + pair: string; + + adjust_by_market: string; + min_2_depth: string; + avg_30d_vol: string; + reference_price: string; + risk_assessment: string; + num_oracles: string; + liquidity_tier: string; + asset_name: string; +}>; + +export type ExchangeConfigItem = { + exchangeName: string; + ticker: string; + adjustByMarket?: string; +}; + +export type PotentialMarketParsedCsv = Array<{ + base_asset: string; + reference_price: string; + num_oracles: string; + liquidity_tier: string; + asset_name: string; + p: string; + atomic_resolution: string; + min_exchanges: string; + min_price_change_ppm: string; + price_exponent: string; + step_base_quantum: string; + ticksize_exponent: string; + subticks_per_tick: string; + min_order_size: string; + quantum_conversion_exponent: string; +}>; + +export type PotentialMarketItem = { + baseAsset: string; + referencePrice: string; + numOracles: number; + liquidityTier: number; + assetName: string; + p: number; + atomicResolution: number; + minExchanges: number; + minPriceChangePpm: number; + priceExponent: number; + stepBaseQuantum: number; + ticksizeExponent: number; + subticksPerTick: number; + minOrderSize: number; + quantumConversionExponent: number; +}; + +export const NUM_ORACLES_TO_QUALIFY_AS_SAFE = 6; + +export const LIQUIDITY_TIERS = { + 0: { + label: 'Large-cap', + initialMarginFraction: 0.05, + maintenanceMarginFraction: 0.03, + impactNotional: 10_000, + }, + 1: { + label: 'Mid-cap', + initialMarginFraction: 0.1, + maintenanceMarginFraction: 0.05, + impactNotional: 5_000, + }, + 2: { + label: 'Long-tail', + initialMarginFraction: 0.2, + maintenanceMarginFraction: 0.1, + impactNotional: 2_500, + }, + 3: { + label: 'Safety', + initialMarginFraction: 1, + maintenanceMarginFraction: 0.2, + impactNotional: 2_500, + }, +}; diff --git a/src/constants/routes.ts b/src/constants/routes.ts index 529efae..5c86896 100644 --- a/src/constants/routes.ts +++ b/src/constants/routes.ts @@ -11,6 +11,10 @@ export enum AppRoute { Privacy = '/privacy', } +export enum MarketsRoute { + New = 'new', +} + export enum PortfolioRoute { Fees = 'fees', History = 'history', diff --git a/src/constants/tooltips/trade.ts b/src/constants/tooltips/trade.ts index 84724b9..081e3f0 100644 --- a/src/constants/tooltips/trade.ts +++ b/src/constants/tooltips/trade.ts @@ -57,10 +57,9 @@ export const tradeTooltips: TooltipStrings = { title: stringGetter({ key: TOOLTIP_STRING_KEYS.INDEX_PRICE_TITLE }), body: stringGetter({ key: TOOLTIP_STRING_KEYS.INDEX_PRICE_BODY }), }), - 'initial-margin-fraction': ({ stringGetter, urlConfigs }) => ({ + 'initial-margin-fraction': ({ stringGetter }) => ({ title: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_MARGIN_FRACTION_TITLE }), body: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_MARGIN_FRACTION_BODY }), - learnMoreLink: urlConfigs?.initialMarginFractionLearnMore, }), 'initial-stop': ({ stringGetter }) => ({ title: stringGetter({ key: TOOLTIP_STRING_KEYS.INITIAL_STOP_TITLE }), @@ -163,6 +162,10 @@ export const tradeTooltips: TooltipStrings = { title: stringGetter({ key: TOOLTIP_STRING_KEYS.REDUCE_ONLY_TIMEINFORCE_IOC_FOK_TITLE }), body: stringGetter({ key: TOOLTIP_STRING_KEYS.REDUCE_ONLY_TIMEINFORCE_IOC_FOK_BODY }), }), + 'reference-price': ({ stringGetter }) => ({ + title: stringGetter({ key: TOOLTIP_STRING_KEYS.REFERENCE_PRICE_TITLE }), + body: stringGetter({ key: TOOLTIP_STRING_KEYS.REFERENCE_PRICE_BODY }), + }), spread: () => ({ title: 'Spread', body: 'The difference in price between the highest bid (the price a buyer is willing to buy for) and lowest ask (the price a seller is willing to sell for) an asset.', diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 1d2ed1e..fc985a8 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -7,6 +7,7 @@ import { useDebounce } from './useDebounce'; import { useInterval } from './useInterval'; import { useDocumentTitle } from './useDocumentTitle'; import { useDydxClient } from './useDydxClient'; +import { useGovernanceVariables } from './useGovernanceVariables'; import { useAccountBalance } from './useAccountBalance'; import { useAccounts } from './useAccounts'; import { useAnalytics } from './useAnalytics'; @@ -14,6 +15,7 @@ import { useInitializePage } from './useInitializePage'; import { useIsFirstRender } from './useIsFirstRender'; import { useLocaleSeparators } from './useLocaleSeparators'; import { useLocalStorage } from './useLocalStorage'; +import { useNextClobPairId } from './useNextClobPairId'; import { useNow } from './useNow'; import { useOnClickOutside } from './useOnClickOutside'; import { usePageTitlePriceUpdates } from './usePageTitlePriceUpdates'; @@ -34,6 +36,7 @@ export { useDebounce, useDocumentTitle, useDydxClient, + useGovernanceVariables, useAccountBalance, useAccounts, useAnalytics, @@ -42,6 +45,7 @@ export { useIsFirstRender, useLocaleSeparators, useLocalStorage, + useNextClobPairId, useNow, useOnClickOutside, usePageTitlePriceUpdates, diff --git a/src/hooks/useDydxClient.tsx b/src/hooks/useDydxClient.tsx index cf3d7d2..581dd58 100644 --- a/src/hooks/useDydxClient.tsx +++ b/src/hooks/useDydxClient.tsx @@ -1,5 +1,6 @@ import { createContext, useCallback, useContext, useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; + import { BECH32_PREFIX, CompositeClient, @@ -9,6 +10,7 @@ import { onboarding, Network, ValidatorConfig, + type ProposalStatus, } from '@dydxprotocol/v4-client-js'; import type { ResolutionString } from 'public/tradingview/charting_library'; @@ -68,17 +70,21 @@ const useDydxClientContext = () => { new Network( selectedNetwork, new IndexerConfig(networkConfig.indexerUrl, networkConfig.websocketUrl), - new ValidatorConfig(networkConfig.validatorUrl, networkConfig.chainId, + new ValidatorConfig( + 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, - }, { - broadcastPollIntervalMs: 3_000, - broadcastTimeoutMs: 60_000, - }) + }, + { + broadcastPollIntervalMs: 3_000, + broadcastTimeoutMs: 60_000, + } + ) ) ); setCompositeClient(initializedClient); @@ -111,6 +117,36 @@ const useDydxClientContext = () => { }; // ------ Public Methods ------ // + const requestAllPerpetualMarkets = useCallback(async () => { + try { + const { markets } = + (await compositeClient?.indexerClient.markets.getPerpetualMarkets()) || {}; + return markets || []; + } catch (error) { + log('useDydxClient/getPerpetualMarkets', error); + return []; + } + }, [compositeClient]); + + /** + * @param proposalStatus - Optional filter for proposal status. If not provided, all proposals in ProposalStatus.VotingPeriod will be returned. + */ + const requestAllGovernanceProposals = useCallback( + async (proposalStatus?: ProposalStatus) => { + try { + const allGovProposals = await compositeClient?.validatorClient.get.getAllGovProposals( + proposalStatus + ); + + return allGovProposals; + } catch (error) { + log('useDydxClient/getProposals', error); + return undefined; + } + }, + [compositeClient] + ); + const requestCandles = useCallback( async ({ marketId, @@ -225,6 +261,8 @@ const useDydxClientContext = () => { getWalletFromEvmSignature, // Public Methods + requestAllPerpetualMarkets, + requestAllGovernanceProposals, getCandlesForDatafeed, screenAddresses, }; diff --git a/src/hooks/useGovernanceVariables.ts b/src/hooks/useGovernanceVariables.ts new file mode 100644 index 0000000..0234ea0 --- /dev/null +++ b/src/hooks/useGovernanceVariables.ts @@ -0,0 +1,16 @@ +import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks'; +import { useSelectedNetwork } from '@/hooks'; + +export interface GovernanceVariables { + newMarketProposal: { + initialDepositAmount: number; + delayBlocks: number; + newMarketsMethodology: string; + }; +} + +export const useGovernanceVariables = (): GovernanceVariables => { + const { selectedNetwork } = useSelectedNetwork(); + const governanceVars = ENVIRONMENT_CONFIG_MAP[selectedNetwork].governance as GovernanceVariables; + return governanceVars; +}; diff --git a/src/hooks/useNextClobPairId.ts b/src/hooks/useNextClobPairId.ts new file mode 100644 index 0000000..f2c74e6 --- /dev/null +++ b/src/hooks/useNextClobPairId.ts @@ -0,0 +1,118 @@ +import { useMemo } from 'react'; +import { useQuery } from 'react-query'; + +import { + MsgCreateClobPair, + MsgCreateOracleMarket, + MsgCreatePerpetual, + MsgDelayMessage, + MsgUpdateClobPair, + TYPE_URL_MSG_CREATE_CLOB_PAIR, + TYPE_URL_MSG_CREATE_ORACLE_MARKET, + TYPE_URL_MSG_CREATE_PERPETUAL, + TYPE_URL_MSG_DELAY_MESSAGE, + TYPE_URL_MSG_UPDATE_CLOB_PAIR, +} from '@dydxprotocol/v4-client-js'; + +import type { PerpetualMarketResponse } from '@/constants/indexer'; +import { useDydxClient } from '@/hooks/useDydxClient'; + +export const useNextClobPairId = () => { + const { isConnected, requestAllPerpetualMarkets, requestAllGovernanceProposals } = + useDydxClient(); + + const { data: perpetualMarkets, status: perpetualMarketsStatus } = useQuery({ + enabled: isConnected, + queryKey: 'requestAllPerpetualMarkets', + queryFn: requestAllPerpetualMarkets, + refetchInterval: 60_000, + staleTime: 60_000, + }); + + const { data: allGovProposals, status: allGovProposalsStatus } = useQuery({ + enabled: isConnected, + queryKey: 'requestAllActiveGovernanceProposals', + queryFn: () => requestAllGovernanceProposals(), + refetchInterval: 10_000, + staleTime: 10_000, + }); + + /** + * + * @param message from proposal. Each message is wrapped in a type any (on purpose). + * @param callback method used to compile all clobPairIds, perpetualIds, marketIds, etc. + */ + const decodeMsgForClobPairId = (message: any, callback: (id?: number) => void): any => { + const { typeUrl, value } = message; + + switch (typeUrl) { + case TYPE_URL_MSG_CREATE_ORACLE_MARKET: { + const decodedValue = MsgCreateOracleMarket.decode(value); + callback(decodedValue.params?.id); + break; + } + case TYPE_URL_MSG_CREATE_PERPETUAL: { + const decodedValue = MsgCreatePerpetual.decode(value); + callback(decodedValue.params?.id); + callback(decodedValue.params?.marketId); + break; + } + case TYPE_URL_MSG_CREATE_CLOB_PAIR: { + const decodedValue = MsgCreateClobPair.decode(value); + callback(decodedValue.clobPair?.id); + callback(decodedValue.clobPair?.perpetualClobMetadata?.perpetualId); + break; + } + case TYPE_URL_MSG_UPDATE_CLOB_PAIR: { + const decodedValue = MsgUpdateClobPair.decode(value); + callback(decodedValue.clobPair?.id); + callback(decodedValue.clobPair?.perpetualClobMetadata?.perpetualId); + break; + } + case TYPE_URL_MSG_DELAY_MESSAGE: { + const decodedValue = MsgDelayMessage.decode(value); + decodeMsgForClobPairId(decodedValue.msg, callback); + break; + } + default: { + break; + } + } + }; + + const nextAvailableClobPairId = useMemo(() => { + const idsFromProposals: number[] = []; + + if (allGovProposals && Object.values(allGovProposals.proposals).length > 0) { + const proposals = allGovProposals.proposals; + proposals.forEach((proposal) => { + if (proposal.messages) { + proposal.messages.map((message) => { + decodeMsgForClobPairId(message, (id?: number) => { + if (id) { + idsFromProposals.push(id); + } + }); + }); + } + }); + } + + if (perpetualMarkets && Object.values(perpetualMarkets).length > 0) { + const clobPairIds = Object.values(perpetualMarkets)?.map((perpetualMarket) => + Number((perpetualMarket as PerpetualMarketResponse).clobPairId) + ); + + const nextAvailableClobPairId = Math.max(...[...clobPairIds, ...idsFromProposals]) + 1; + return nextAvailableClobPairId; + } + + return undefined; + }, [perpetualMarkets, allGovProposals]); + + return { + allGovProposalsStatus, + perpetualMarketsStatus, + nextAvailableClobPairId, + }; +}; diff --git a/src/hooks/usePotentialMarkets.tsx b/src/hooks/usePotentialMarkets.tsx new file mode 100644 index 0000000..0708486 --- /dev/null +++ b/src/hooks/usePotentialMarkets.tsx @@ -0,0 +1,135 @@ +import { createContext, useContext, useEffect, useState } from 'react'; + +import type { + ExchangeConfigItem, + ExchangeConfigParsedCsv, + PotentialMarketItem, + PotentialMarketParsedCsv, +} from '@/constants/potentialMarkets'; + +import csvToArray from '@/lib/csvToArray'; +import { log } from '@/lib/telemetry'; + +const PotentialMarketsContext = createContext>({ + potentialMarkets: undefined, + exchangeConfigs: undefined, + hasPotentialMarketsData: false, +}); + +PotentialMarketsContext.displayName = 'PotentialMarkets'; + +export const PotentialMarketsProvider = ({ ...props }) => ( + +); + +export const usePotentialMarkets = () => useContext(PotentialMarketsContext); + +const EXCHANGE_CONFIG_FILE_PATH = '/configs/potentialMarketExchangeConfig.csv'; +const POTENTIAL_MARKETS_FILE_PATH = '/configs/potentialMarketParameters.csv'; + +export const usePotentialMarketsContext = () => { + const [potentialMarkets, setPotentialMarkets] = useState(); + const [exchangeConfigs, setExchangeConfigs] = useState>(); + + useEffect(() => { + try { + fetch(POTENTIAL_MARKETS_FILE_PATH) + .then((response) => response.text()) + .then((data) => { + const parsedData = csvToArray({ + stringVal: data, + splitter: ',', + }); + const parsedPotentialMarkets = parsedData.map( + ({ + base_asset, + reference_price, + num_oracles, + liquidity_tier, + asset_name, + p, + atomic_resolution, + min_exchanges, + min_price_change_ppm, + price_exponent, + step_base_quantum, + ticksize_exponent, + subticks_per_tick, + min_order_size, + quantum_conversion_exponent, + }) => ({ + // convert to camelCase + baseAsset: base_asset, + referencePrice: reference_price, + numOracles: Number(num_oracles), + liquidityTier: Number(liquidity_tier), + assetName: asset_name, + p: Number(p), + atomicResolution: Number(atomic_resolution), + minExchanges: Number(min_exchanges), + minPriceChangePpm: Number(min_price_change_ppm), + priceExponent: Number(price_exponent), + stepBaseQuantum: Number(step_base_quantum), + ticksizeExponent: Number(ticksize_exponent), + subticksPerTick: Number(subticks_per_tick), + minOrderSize: Number(min_order_size), + quantumConversionExponent: Number(quantum_conversion_exponent), + }) + ); + + setPotentialMarkets(parsedPotentialMarkets); + }); + } catch (error) { + log('usePotentialMarkets/potentialMarkets', error); + setPotentialMarkets(undefined); + } + + try { + fetch(EXCHANGE_CONFIG_FILE_PATH) + .then((response) => response.text()) + .then((data) => { + const parsedData = csvToArray({ + stringVal: data, + splitter: ',', + }); + // create an object with the base_asset as the key and the value as an array of exchanges + const exchangeConfigMap = parsedData.reduce( + (acc: Record, curr) => { + const { base_asset, exchange, pair, adjust_by_market } = curr; + if (!acc[base_asset]) { + acc[base_asset] = []; + } + + const exchangeItem: { + exchangeName: string; + ticker: string; + adjustByMarket?: string; + } = { + exchangeName: exchange, + ticker: pair, + }; + + if (adjust_by_market) { + exchangeItem.adjustByMarket = adjust_by_market; + } + + acc[base_asset].push(exchangeItem); + return acc; + }, + {} + ); + + setExchangeConfigs(exchangeConfigMap); + }); + } catch (error) { + log('usePotentialMarkets/exchangeConfigs', error); + setExchangeConfigs(undefined); + } + }, []); + + return { + potentialMarkets, + exchangeConfigs, + hasPotentialMarketsData: Boolean(potentialMarkets && exchangeConfigs), + }; +}; diff --git a/src/hooks/useSubaccount.tsx b/src/hooks/useSubaccount.tsx index 3189717..cfd2588 100644 --- a/src/hooks/useSubaccount.tsx +++ b/src/hooks/useSubaccount.tsx @@ -2,11 +2,16 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useState } import { shallowEqual, useSelector, useDispatch } from 'react-redux'; import type { Nullable } from '@dydxprotocol/v4-abacus'; import Long from 'long'; -import type { IndexedTx } from '@cosmjs/stargate'; +import { type IndexedTx } from '@cosmjs/stargate'; import type { EncodeObject } from '@cosmjs/proto-signing'; import { Method } from '@cosmjs/tendermint-rpc'; -import { type LocalWallet, SubaccountClient } from '@dydxprotocol/v4-client-js'; +import { + type LocalWallet, + SubaccountClient, + type GovAddNewMarketParams, + utils, +} from '@dydxprotocol/v4-client-js'; import type { AccountBalance, @@ -16,7 +21,6 @@ import type { } from '@/constants/abacus'; import { AMOUNT_RESERVED_FOR_GAS_USDC } from '@/constants/account'; -import { AnalyticsEvent } from '@/constants/analytics'; import { QUANTUM_MULTIPLIER } from '@/constants/numbers'; import { DydxAddress } from '@/constants/wallets'; @@ -24,14 +28,13 @@ import { setSubaccount, setHistoricalPnl, removeUncommittedOrderClientId } from import { getBalances } from '@/state/accountSelectors'; import abacusStateManager from '@/lib/abacus'; -import { track } from '@/lib/analytics'; -import { MustBigNumber } from '@/lib/numbers'; +import { hashFromTx } from '@/lib/hashfromTx'; import { log } from '@/lib/telemetry'; import { useAccounts } from './useAccounts'; import { useTokenConfigs } from './useTokenConfigs'; import { useDydxClient } from './useDydxClient'; -import { hashFromTx } from '@/lib/hashfromTx'; +import { useGovernanceVariables } from './useGovernanceVariables'; type SubaccountContextType = ReturnType; const SubaccountContext = createContext({} as SubaccountContextType); @@ -201,8 +204,8 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo value: { ...transaction.msg, timeoutTimestamp: transaction.msg.timeoutTimestamp - // Squid returns timeoutTimestamp as Long, but the signer expects BigInt - ? BigInt(Long.fromValue(transaction.msg.timeoutTimestamp).toString()) + ? // Squid returns timeoutTimestamp as Long, but the signer expects BigInt + BigInt(Long.fromValue(transaction.msg.timeoutTimestamp).toString()) : undefined, }, }; @@ -301,9 +304,8 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo const sendSquidWithdraw = useCallback( async (amount: number, payload: string, isCctp?: boolean) => { - const cctpWithdraw = () => { - return new Promise((resolve, reject) => + return new Promise((resolve, reject) => abacusStateManager.cctpWithdraw((success, error, data) => { const parsedData = JSON.parse(data); if (success && parsedData?.code == 0) { @@ -312,8 +314,8 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo reject(error); } }) - ) - } + ); + }; if (isCctp) { return await cctpWithdraw(); } @@ -413,6 +415,32 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo [subaccountClient] ); + const { newMarketProposal } = useGovernanceVariables(); + + // ------ Governance Methods ------ // + const submitNewMarketProposal = useCallback( + async (params: GovAddNewMarketParams) => { + if (!compositeClient) { + throw new Error('client not initialized'); + } else if (!localDydxWallet) { + throw new Error('wallet not initialized'); + } else if (!newMarketProposal) { + throw new Error('governance variables not initialized'); + } + + const response = await compositeClient.submitGovAddNewMarketProposal( + localDydxWallet, + params, + utils.getGovAddNewMarketTitle(params.ticker), + utils.getGovAddNewMarketSummary(params.ticker, newMarketProposal.delayBlocks), + newMarketProposal.initialDepositAmount + ); + + return response; + }, + [compositeClient, localDydxWallet] + ); + return { // Deposit/Withdraw/Faucet Methods deposit, @@ -427,5 +455,8 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo placeOrder, closePosition, cancelOrder, + + // Governance Methods + submitNewMarketProposal, }; }; diff --git a/src/layout/DialogManager.tsx b/src/layout/DialogManager.tsx index 49faff7..d7145ae 100644 --- a/src/layout/DialogManager.tsx +++ b/src/layout/DialogManager.tsx @@ -27,6 +27,8 @@ import { ManageFundsDialog } from '@/views/dialogs/ManageFundsDialog'; import { OrderDetailsDialog } from '@/views/dialogs/DetailsDialog/OrderDetailsDialog'; import { FillDetailsDialog } from '@/views/dialogs/DetailsDialog/FillDetailsDialog'; +import { NewMarketMessageDetailsDialog } from '@/views/dialogs/NewMarketMessageDetailsDialog'; +import { NewMarketAgreementDialog } from '@/views/dialogs/NewMarketAgreementDialog'; export const DialogManager = () => { const dispatch = useDispatch(); @@ -67,5 +69,7 @@ export const DialogManager = () => { [DialogTypes.Transfer]: , [DialogTypes.Withdraw]: , [DialogTypes.ManageFunds]: , + [DialogTypes.NewMarketMessageDetails]: , + [DialogTypes.NewMarketAgreement]: , }[type]; }; diff --git a/src/lib/csvToArray.ts b/src/lib/csvToArray.ts new file mode 100644 index 0000000..eb3dbf5 --- /dev/null +++ b/src/lib/csvToArray.ts @@ -0,0 +1,16 @@ +const csvToArray = ({ stringVal, splitter }: { stringVal: string; splitter: string }) => { + const [keys, ...rest] = stringVal + .trim() + .split('\n') + .map((item) => item.split(splitter)); + + const formedArr = rest.map((item) => { + const object: Record = {}; + keys.forEach((key, index) => (object[key] = item[index])); + return object; + }); + + return formedArr as T; +}; + +export default csvToArray; diff --git a/src/pages/markets/Markets.tsx b/src/pages/markets/Markets.tsx index 79a63e9..7644f8b 100644 --- a/src/pages/markets/Markets.tsx +++ b/src/pages/markets/Markets.tsx @@ -1,21 +1,25 @@ import styled, { AnyStyledComponent } from 'styled-components'; +import { useNavigate } from 'react-router-dom'; import { breakpoints } from '@/styles'; import { STRING_KEYS } from '@/constants/localization'; - +import { AppRoute, MarketsRoute } from '@/constants/routes'; import { useBreakpoints, useDocumentTitle, useStringGetter } from '@/hooks'; +import { usePotentialMarkets } from '@/hooks/usePotentialMarkets'; import { layoutMixins } from '@/styles/layoutMixins'; +import { Button } from '@/components/Button'; import { ContentSectionHeader } from '@/components/ContentSectionHeader'; - import { ExchangeBillboards } from '@/views/ExchangeBillboards'; import { MarketsTable } from '@/views/tables/MarketsTable'; const Markets = () => { const stringGetter = useStringGetter(); const { isNotTablet } = useBreakpoints(); + const navigate = useNavigate(); + const { hasPotentialMarketsData } = usePotentialMarkets(); useDocumentTitle(stringGetter({ key: STRING_KEYS.MARKETS })); @@ -25,6 +29,13 @@ const Markets = () => { navigate(`${AppRoute.Markets}/${MarketsRoute.New}`)}> + {stringGetter({ key: STRING_KEYS.ADD_A_MARKET })} + + ) + } /> diff --git a/src/pages/markets/NewMarket.tsx b/src/pages/markets/NewMarket.tsx new file mode 100644 index 0000000..0d722c9 --- /dev/null +++ b/src/pages/markets/NewMarket.tsx @@ -0,0 +1,259 @@ +import { useMemo, useState } from 'react'; +import styled, { AnyStyledComponent } from 'styled-components'; +import { useNavigate } from 'react-router-dom'; + +import { STRING_KEYS } from '@/constants/localization'; +import { isMainnet } from '@/constants/networks'; +import { AppRoute } from '@/constants/routes'; + +import { + useBreakpoints, + useDocumentTitle, + useGovernanceVariables, + useStringGetter, + useTokenConfigs, +} from '@/hooks'; + +import { breakpoints } from '@/styles'; +import { layoutMixins } from '@/styles/layoutMixins'; + +import { Button } from '@/components/Button'; +import { ContentSectionHeader } from '@/components/ContentSectionHeader'; +import { IconButton } from '@/components/IconButton'; +import { Icon, IconName } from '@/components/Icon'; +import { Link } from '@/components/Link'; +import { NewMarketForm } from '@/views/forms/NewMarketForm'; + +import { MustBigNumber } from '@/lib/numbers'; + +const StepItem = ({ step, subtitle, title }: { step: number; subtitle: string; title: string }) => ( + + {step} + + {title} + {subtitle} + + +); + +const NewMarket = () => { + const { isNotTablet } = useBreakpoints(); + const { newMarketProposal } = useGovernanceVariables(); + const navigate = useNavigate(); + const [displaySteps, setDisplaySteps] = useState(true); + const stringGetter = useStringGetter(); + const { chainTokenLabel, chainTokenDecimals } = useTokenConfigs(); + + useDocumentTitle(stringGetter({ key: STRING_KEYS.ADD_A_MARKET })); + + const steps = useMemo(() => { + return [ + { + step: 1, + title: stringGetter({ key: STRING_KEYS.ADD_MARKET_STEP_1_TITLE }), + subtitle: stringGetter({ + key: STRING_KEYS.ADD_MARKET_STEP_1_DESCRIPTION, + params: { + HERE: ( + + {stringGetter({ key: STRING_KEYS.HERE })} + + ), + }, + }), + }, + { + step: 2, + title: stringGetter({ key: STRING_KEYS.ADD_MARKET_STEP_2_TITLE }), + subtitle: stringGetter({ key: STRING_KEYS.ADD_MARKET_STEP_2_DESCRIPTION }), + }, + { + step: 3, + title: stringGetter({ key: STRING_KEYS.ADD_MARKET_STEP_3_TITLE }), + subtitle: stringGetter({ + key: STRING_KEYS.ADD_MARKET_STEP_3_DESCRIPTION, + params: { + REQUIRED_NUM_TOKENS: MustBigNumber(newMarketProposal?.initialDepositAmount) + .div(Number(`1e${chainTokenDecimals}`)) + .toFixed(isMainnet ? 0 : chainTokenDecimals), + NATIVE_TOKEN_DENOM: chainTokenLabel, + }, + }), + }, + ]; + }, [stringGetter, newMarketProposal, chainTokenLabel]); + + return ( + + + navigate(AppRoute.Markets)} /> + } + subtitle={isNotTablet && stringGetter({ key: STRING_KEYS.ADD_DETAILS_TO_LAUNCH_MARKET })} + /> + + +

+ + {displaySteps && ( + <> + + {stringGetter({ key: STRING_KEYS.STEPS_TO_CREATE })} + + {steps.map((item) => ( + + ))} + + )} +
+ + + + + + ); +}; + +const Styled: Record = {}; + +Styled.Page = styled.div` + ${layoutMixins.contentContainerPage} + gap: 1.5rem; + + > * { + --content-max-width: 80rem; + max-width: min(calc(100vw - 4rem), var(--content-max-width)); + } + + @media ${breakpoints.tablet} { + --stickyArea-topHeight: var(--page-header-height-mobile); + padding: 0 1rem 1rem; + + > * { + max-width: calc(100vw - 2rem); + width: 100%; + } + } +`; + +Styled.ContentSectionHeader = styled(ContentSectionHeader)` + @media ${breakpoints.notTablet} { + padding: 1rem 0; + } + + @media ${breakpoints.tablet} { + padding: 1.25rem 0; + + h3 { + font: var(--font-extra-medium); + } + } +`; + +Styled.HeaderSection = styled.section` + ${layoutMixins.contentSectionDetached} + + @media ${breakpoints.tablet} { + ${layoutMixins.flexColumn} + gap: 1rem; + + margin-bottom: 0.5rem; + } +`; + +Styled.Content = styled.div` + display: flex; + flex-direction: row; + gap: 2rem; + margin: 0 auto; + + @media ${breakpoints.tablet} { + display: flex; + flex-direction: column; + gap: 1rem; + margin: 0 auto; + } +`; + +Styled.StepsTitle = styled.h2` + font: var(--font-large-medium); + color: var(--color-text-2); + margin: 1rem; + + @media ${breakpoints.tablet} { + margin: 1rem 0; + } +`; + +Styled.Icon = styled(Icon)` + margin-right: 0.5ch; +`; + +Styled.StepItem = styled.div` + display: flex; + flex-direction: row; + gap: 1rem; + align-items: center; + margin-bottom: 1rem; +`; + +Styled.StepNumber = styled.div` + width: 2.5rem; + height: 2.5rem; + min-width: 2.5rem; + min-height: 2.5rem; + border-radius: 50%; + background-color: var(--color-layer-5); + display: flex; + align-items: center; + justify-content: center; + color: var(--color-text-2); +`; + +Styled.Column = styled.div` + display: flex; + flex-direction: column; +`; + +Styled.Title = styled.span` + color: var(--color-text-2); + font: var(--font-medium-book); +`; + +Styled.Subtitle = styled.span` + color: var(--color-text-0); +`; + +Styled.Link = styled(Link)` + --link-color: var(--color-accent); + display: inline-block; +`; + +Styled.FormContainer = styled.div` + min-width: 31.25rem; + height: fit-content; + border-radius: 1rem; + background-color: var(--color-layer-3); + padding: 1rem; + + @media ${breakpoints.tablet} { + width: 100%; + min-width: unset; + } +`; + +export default NewMarket; diff --git a/src/pages/rewards/NewMarketsPanel.tsx b/src/pages/rewards/NewMarketsPanel.tsx new file mode 100644 index 0000000..a88d80b --- /dev/null +++ b/src/pages/rewards/NewMarketsPanel.tsx @@ -0,0 +1,103 @@ +import styled, { AnyStyledComponent } from 'styled-components'; +import { useNavigate } from 'react-router-dom'; + +import { ButtonAction, ButtonSize } from '@/constants/buttons'; +import { STRING_KEYS } from '@/constants/localization'; +import { isMainnet } from '@/constants/networks'; +import { AppRoute, MarketsRoute } from '@/constants/routes'; + +import { useStringGetter, useTokenConfigs } from '@/hooks'; +import { usePotentialMarkets } from '@/hooks/usePotentialMarkets'; +import { useGovernanceVariables } from '@/hooks/useGovernanceVariables'; + +import { Panel } from '@/components/Panel'; +import { IconName } from '@/components/Icon'; +import { IconButton } from '@/components/IconButton'; +import { Output, OutputType } from '@/components/Output'; +import { Tag } from '@/components/Tag'; + +import { MustBigNumber } from '@/lib/numbers'; +import { layoutMixins } from '@/styles/layoutMixins'; + +export const NewMarketsPanel = () => { + const stringGetter = useStringGetter(); + const navigate = useNavigate(); + const { hasPotentialMarketsData } = usePotentialMarkets(); + const { chainTokenDecimals, chainTokenLabel } = useTokenConfigs(); + const { newMarketProposal } = useGovernanceVariables(); + const initialDepositAmountBN = MustBigNumber(newMarketProposal.initialDepositAmount).div( + Number(`1e${chainTokenDecimals}`) + ); + const initialDepositAmountDecimals = isMainnet ? 0 : chainTokenDecimals; + + if (!hasPotentialMarketsData) return null; + + return ( + + {stringGetter({ key: STRING_KEYS.ADD_A_MARKET })} + {stringGetter({ key: STRING_KEYS.NEW })} + + } + slotRight={ + + + + } + onClick={() => navigate(`${AppRoute.Markets}/${MarketsRoute.New}`)} + > + + {stringGetter({ + key: STRING_KEYS.NEW_MARKET_REWARDS_ENTRY_DESCRIPTION, + params: { + REQUIRED_NUM_TOKENS: ( + + ), + NATIVE_TOKEN_DENOM: chainTokenLabel, + }, + })} + + + ); +}; + +const Styled: Record = {}; + +Styled.Description = styled.div` + color: var(--color-text-0); +`; + +Styled.IconButton = styled(IconButton)` + color: var(--color-text-0); + --color-border: var(--color-layer-6); +`; + +Styled.Arrow = styled.div` + padding-right: 1.5rem; +`; + +Styled.Title = styled.h3` + font: var(--font-medium-book); + color: var(--color-text-2); + margin-bottom: -1rem; + ${layoutMixins.inlineRow} +`; + +Styled.Output = styled(Output)` + display: inline-block; +`; + +Styled.NewTag = styled(Tag)` + color: var(--color-accent); + background-color: var(--color-accent-faded); +`; diff --git a/src/pages/rewards/RewardsPage.tsx b/src/pages/rewards/RewardsPage.tsx index 0e4031a..4329ca6 100644 --- a/src/pages/rewards/RewardsPage.tsx +++ b/src/pages/rewards/RewardsPage.tsx @@ -14,11 +14,12 @@ import { BackButton } from '@/components/BackButton'; import { Panel } from '@/components/Panel'; import { DYDXBalancePanel } from './DYDXBalancePanel'; -import { MigratePanel } from './MigratePanel'; import { LaunchIncentivesPanel } from './LaunchIncentivesPanel'; +import { MigratePanel } from './MigratePanel'; import { RewardsHelpPanel } from './RewardsHelpPanel'; import { GovernancePanel } from './GovernancePanel'; import { StakingPanel } from './StakingPanel'; +import { NewMarketsPanel } from './NewMarketsPanel'; const RewardsPage = () => { const dispatch = useDispatch(); @@ -44,9 +45,9 @@ const RewardsPage = () => { )} - {isNotTablet && ( + diff --git a/src/views/MarketsDropdown.tsx b/src/views/MarketsDropdown.tsx index 2c2ba6b..8998944 100644 --- a/src/views/MarketsDropdown.tsx +++ b/src/views/MarketsDropdown.tsx @@ -3,23 +3,26 @@ import { useNavigate } from 'react-router-dom'; import styled, { type AnyStyledComponent, css, keyframes } from 'styled-components'; import { useSelector } from 'react-redux'; +import { ButtonSize } from '@/constants/buttons'; import { STRING_KEYS } from '@/constants/localization'; import { MarketFilters, type MarketData } from '@/constants/markets'; -import { AppRoute } from '@/constants/routes'; - +import { AppRoute, MarketsRoute } from '@/constants/routes'; import { useStringGetter } from '@/hooks'; +import { useMarketsData } from '@/hooks/useMarketsData'; +import { usePotentialMarkets } from '@/hooks/usePotentialMarkets'; + import { popoverMixins } from '@/styles/popoverMixins'; import { layoutMixins } from '@/styles/layoutMixins'; import { AssetIcon } from '@/components/AssetIcon'; +import { Button } from '@/components/Button'; import { Icon, IconName } from '@/components/Icon'; import { Output, OutputType } from '@/components/Output'; import { Popover, TriggerType } from '@/components/Popover'; +import { ColumnDef, Table } from '@/components/Table'; import { Tag } from '@/components/Tag'; import { Toolbar } from '@/components/Toolbar'; -import { ColumnDef, Table } from '@/components/Table'; -import { useMarketsData } from '@/hooks/useMarketsData'; import { getSelectedLocale } from '@/state/localizationSelectors'; import { MustBigNumber } from '@/lib/numbers'; @@ -32,6 +35,8 @@ const MarketsDropdownContent = ({ onRowAction }: { onRowAction?: (market: string const selectedLocale = useSelector(getSelectedLocale); const [searchFilter, setSearchFilter] = useState(); const { filteredMarkets, marketFilters } = useMarketsData(filter, searchFilter); + const navigate = useNavigate(); + const { hasPotentialMarketsData } = usePotentialMarkets(); return ( <> @@ -134,16 +139,16 @@ const MarketsDropdownContent = ({ onRowAction }: { onRowAction?: (market: string })}

{stringGetter({ key: STRING_KEYS.MARKET_SEARCH_DOES_NOT_EXIST_YET })}

- {/* TODO TRCL-1693 - uncomment when feedback modal is finalized -
- -
*/} + {hasPotentialMarketsData && ( +
+ +
+ )} } /> diff --git a/src/views/dialogs/NewMarketAgreementDialog.tsx b/src/views/dialogs/NewMarketAgreementDialog.tsx new file mode 100644 index 0000000..1346f02 --- /dev/null +++ b/src/views/dialogs/NewMarketAgreementDialog.tsx @@ -0,0 +1,105 @@ +import { useState } from 'react'; +import styled, { AnyStyledComponent } from 'styled-components'; + +import { ButtonAction } from '@/constants/buttons'; +import { AppRoute } from '@/constants/routes'; +import { STRING_KEYS } from '@/constants/localization'; +import { useStringGetter } from '@/hooks'; +import breakpoints from '@/styles/breakpoints'; +import { layoutMixins } from '@/styles/layoutMixins'; + +import { Button } from '@/components/Button'; +import { Checkbox } from '@/components/Checkbox'; +import { Dialog } from '@/components/Dialog'; +import { Link } from '@/components/Link'; + +type ElementProps = { + acceptTerms: () => void; + setIsOpen: (open: boolean) => void; +}; + +export const NewMarketAgreementDialog = ({ acceptTerms, setIsOpen }: ElementProps) => { + const [hasAcknowledged, setHasAcknowledged] = useState(false); + + const stringGetter = useStringGetter(); + + return ( + + +

+ {stringGetter({ + key: STRING_KEYS.NEW_MARKET_PROPOSAL_AGREEMENT, + params: { + DOCUMENTATION_LINK: ( + + {stringGetter({ key: STRING_KEYS.WEBSITE }).toLowerCase()} + + ), + TERMS_OF_USE: ( + + {stringGetter({ key: STRING_KEYS.TERMS_OF_USE })} + + ), + }, + })} +

+ + + + + + +
+
+ ); +}; + +const Styled: Record = {}; + +Styled.Dialog = styled(Dialog)` + @media ${breakpoints.notMobile} { + --dialog-width: 30rem; + } +`; + +Styled.Content = styled.div` + ${layoutMixins.column} + gap: 1rem; + + p { + border-radius: 0.5rem; + padding: 1rem; + background-color: var(--color-layer-1); + } +`; + +Styled.Link = styled(Link)` + --link-color: var(--color-accent); + display: inline-block; +`; + +Styled.ButtonRow = styled.div` + display: grid; + grid-template-columns: 1fr 2fr; + gap: 1rem; +`; diff --git a/src/views/dialogs/NewMarketMessageDetailsDialog.tsx b/src/views/dialogs/NewMarketMessageDetailsDialog.tsx new file mode 100644 index 0000000..e43ca1f --- /dev/null +++ b/src/views/dialogs/NewMarketMessageDetailsDialog.tsx @@ -0,0 +1,361 @@ +import { useMemo, useState } from 'react'; +import styled, { AnyStyledComponent } from 'styled-components'; +import { utils } from '@dydxprotocol/v4-client-js'; + +import { STRING_KEYS } from '@/constants/localization'; +import { isMainnet } from '@/constants/networks'; +import { PotentialMarketItem } from '@/constants/potentialMarkets'; +import { useGovernanceVariables, useStringGetter, useTokenConfigs } from '@/hooks'; +import { usePotentialMarkets } from '@/hooks/usePotentialMarkets'; +import { layoutMixins } from '@/styles/layoutMixins'; + +import { Details } from '@/components/Details'; +import { Dialog } from '@/components/Dialog'; +import { Output, OutputType } from '@/components/Output'; +import { Tag, TagType } from '@/components/Tag'; +import { ToggleGroup } from '@/components/ToggleGroup'; + +import { MustBigNumber } from '@/lib/numbers'; + +type ElementProps = { + preventClose?: boolean; + setIsOpen?: (open: boolean) => void; + assetData?: PotentialMarketItem; + clobPairId?: number; + liquidityTier?: string; +}; + +export enum CodeToggleGroup { + CREATE_ORACLE = 'CREATE_ORACLE', + MSG_CREATE_PERPETUAL = 'MSG_CREATE_PERPETUAL', + MSG_CREATE_CLOB_PAIR = 'MSG_CREATE_CLOB_PAIR', + MSG_DELAY_MESSAGE = 'MSG_DELAY_MESSAGE', + MSG_SUBMIT_PROPOSAL = 'MSG_SUBMIT_PROPOSAL', +} + +export const NewMarketMessageDetailsDialog = ({ + assetData, + clobPairId, + liquidityTier, + preventClose, + setIsOpen, +}: ElementProps) => { + const [codeToggleGroup, setCodeToggleGroup] = useState(CodeToggleGroup.CREATE_ORACLE); + const { exchangeConfigs } = usePotentialMarkets(); + const { baseAsset } = assetData ?? {}; + const { newMarketProposal } = useGovernanceVariables(); + const stringGetter = useStringGetter(); + const { chainTokenDecimals, chainTokenLabel } = useTokenConfigs(); + const initialDepositAmountDecimals = isMainnet ? 0 : chainTokenDecimals; + + const exchangeConfig = useMemo(() => { + return baseAsset ? exchangeConfigs?.[baseAsset] : undefined; + }, [baseAsset]); + + const ticker = useMemo(() => `${baseAsset}-USD`, [baseAsset]); + + const toggleGroupItems: Parameters[0]['items'] = useMemo(() => { + return [ + { + value: CodeToggleGroup.CREATE_ORACLE, + label: 'Create oracle market', + }, + { + value: CodeToggleGroup.MSG_CREATE_PERPETUAL, + label: 'Msg create perpetual', + }, + { + value: CodeToggleGroup.MSG_CREATE_CLOB_PAIR, + label: 'Msg create clobPair', + }, + { + value: CodeToggleGroup.MSG_DELAY_MESSAGE, + label: 'Msg delay message', + }, + { + value: CodeToggleGroup.MSG_SUBMIT_PROPOSAL, + label: 'Msg submit proposal', + }, + ]; + }, []); + + return ( + + + + { + { + [CodeToggleGroup.CREATE_ORACLE]: ( + + + + exchange_config_json{' '} + {exchangeConfig && {exchangeConfig.length}} + + {'['} + {exchangeConfig?.map((exchange) => { + return ( + + {'{'} + {Object.keys(exchange).map((key) => ( + + {key}: {exchange[key as keyof typeof exchange]} + + ))} + {'},'} + + ); + })} + {']'} + + ), + [CodeToggleGroup.MSG_CREATE_PERPETUAL]: ( + + + + ), + [CodeToggleGroup.MSG_CREATE_CLOB_PAIR]: ( + + + + ), + [CodeToggleGroup.MSG_DELAY_MESSAGE]: ( + + + ), + }, + ]} + /> +
MSG_UPDATE_CLOB_PAIR
+ +
+ ), + [CodeToggleGroup.MSG_SUBMIT_PROPOSAL]: ( + + title: + {utils.getGovAddNewMarketTitle(ticker)} + + initial_deposit_amount: + + { + + } + + + summary: + + {utils.getGovAddNewMarketSummary(ticker, newMarketProposal.delayBlocks)} + + + ), + }[codeToggleGroup] + } +
+
+ ); +}; + +const Styled: Record = {}; + +Styled.Content = styled.div` + ${layoutMixins.column} + gap: 0; +`; + +Styled.ProposedMessageDetails = styled.div` + display: flex; + flex-direction: column; + gap: 1rem; + width: 100%; + background-color: var(--color-layer-3); + margin-top: 1rem; + border-radius: 10px; +`; + +Styled.Tabs = styled(ToggleGroup)` + overflow-x: auto; +`; + +Styled.Text0 = styled.span` + color: var(--color-text-0); +`; + +Styled.Code = styled.div` + background-color: var(--color-layer-1); + padding: 1rem; + border-radius: 10px; + font: var(--font-mini-book); + font-family: var(--fontFamily-monospace); + margin-top: 1rem; + display: flex; + flex-direction: column; + gap: 0rem; +`; + +Styled.Details = styled(Details)` + --details-item-height: 1.5rem; +`; + +Styled.Line = styled.pre` + margin-left: 1rem; +`; + +Styled.Description = styled.p` + margin-bottom: 1rem; +`; diff --git a/src/views/forms/NewMarketForm/NewMarketPreviewStep.tsx b/src/views/forms/NewMarketForm/NewMarketPreviewStep.tsx new file mode 100644 index 0000000..d4edce3 --- /dev/null +++ b/src/views/forms/NewMarketForm/NewMarketPreviewStep.tsx @@ -0,0 +1,396 @@ +import { FormEvent, useCallback, useMemo, useState } from 'react'; +import styled, { AnyStyledComponent } from 'styled-components'; +import { useDispatch } from 'react-redux'; +import Long from 'long'; +import { encodeJson } from '@dydxprotocol/v4-client-js'; +import type { IndexedTx } from '@cosmjs/stargate'; + +import { AlertType } from '@/constants/alerts'; +import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons'; +import { DialogTypes } from '@/constants/dialogs'; +import { STRING_KEYS } from '@/constants/localization'; +import { isMainnet } from '@/constants/networks'; +import { NumberSign, TOKEN_DECIMALS } from '@/constants/numbers'; +import { LIQUIDITY_TIERS, type PotentialMarketItem } from '@/constants/potentialMarkets'; + +import { + useAccountBalance, + useGovernanceVariables, + useStringGetter, + useSubaccount, + useTokenConfigs, +} from '@/hooks'; +import { usePotentialMarkets } from '@/hooks/usePotentialMarkets'; + +import { formMixins } from '@/styles/formMixins'; +import { layoutMixins } from '@/styles/layoutMixins'; + +import { AlertMessage } from '@/components/AlertMessage'; +import { Button } from '@/components/Button'; +import { DiffOutput } from '@/components/DiffOutput'; +import { FormInput } from '@/components/FormInput'; +import { Icon, IconName } from '@/components/Icon'; +import { InputType } from '@/components/Input'; +import { Output, OutputType } from '@/components/Output'; +import { Tag } from '@/components/Tag'; +import { WithDetailsReceipt } from '@/components/WithDetailsReceipt'; + +import { openDialog } from '@/state/dialogs'; + +import { MustBigNumber } from '@/lib/numbers'; +import { log } from '@/lib/telemetry'; + +type NewMarketPreviewStepProps = { + assetData: PotentialMarketItem; + clobPairId: number; + liquidityTier: number; + onBack: () => void; + onSuccess: (hash: string) => void; + tickSizeDecimals: number; +}; + +export const NewMarketPreviewStep = ({ + assetData, + clobPairId, + liquidityTier, + onBack, + onSuccess, + tickSizeDecimals, +}: NewMarketPreviewStepProps) => { + const { nativeTokenBalance } = useAccountBalance(); + const dispatch = useDispatch(); + const stringGetter = useStringGetter(); + const { chainTokenDecimals, chainTokenLabel } = useTokenConfigs(); + const [errorMessage, setErrorMessage] = useState(); + const { exchangeConfigs } = usePotentialMarkets(); + const { submitNewMarketProposal } = useSubaccount(); + const { newMarketProposal } = useGovernanceVariables(); + const initialDepositAmountBN = MustBigNumber(newMarketProposal.initialDepositAmount).div( + Number(`1e${chainTokenDecimals}`) + ); + const initialDepositAmountDecimals = isMainnet ? 0 : chainTokenDecimals; + const initialDepositAmount = initialDepositAmountBN.toFixed(initialDepositAmountDecimals); + const [hasAcceptedTerms, setHasAcceptedTerms] = useState(false); + + const { label, initialMarginFraction, maintenanceMarginFraction, impactNotional } = + LIQUIDITY_TIERS[liquidityTier as unknown as keyof typeof LIQUIDITY_TIERS]; + + const ticker = `${assetData.baseAsset}-USD`; + + const alertMessage = useMemo(() => { + if (errorMessage) { + return { + type: AlertType.Error, + message: errorMessage, + }; + } + if (nativeTokenBalance.lt(initialDepositAmountBN)) { + return { + type: AlertType.Error, + message: stringGetter({ + key: STRING_KEYS.NOT_ENOUGH_BALANCE, + params: { + NUM_TOKENS_REQUIRED: initialDepositAmount, + NATIVE_TOKEN_DENOM: chainTokenLabel, + }, + }), + }; + } + + return null; + }, [nativeTokenBalance, errorMessage]); + + const isDisabled = alertMessage !== null; + + return ( + ) => { + e.preventDefault(); + + if (!hasAcceptedTerms) { + dispatch( + openDialog({ + type: DialogTypes.NewMarketAgreement, + dialogProps: { + acceptTerms: () => setHasAcceptedTerms(true), + }, + }) + ); + } else { + setErrorMessage(undefined); + + try { + const tx = await submitNewMarketProposal({ + id: clobPairId, + ticker, + priceExponent: assetData.priceExponent, + minPriceChange: assetData.minPriceChangePpm, + minExchanges: assetData.minExchanges, + exchangeConfigJson: JSON.stringify({ + exchanges: exchangeConfigs?.[assetData.baseAsset], + }), + atomicResolution: assetData.atomicResolution, + liquidityTier: liquidityTier, + quantumConversionExponent: assetData.quantumConversionExponent, + stepBaseQuantums: Long.fromNumber(assetData.stepBaseQuantum), + subticksPerTick: assetData.subticksPerTick, + delayBlocks: newMarketProposal.delayBlocks, + }); + + if ((tx as IndexedTx)?.code === 0) { + const encodedTx = encodeJson(tx); + const parsedTx = JSON.parse(encodedTx); + const hash = parsedTx.hash.toUpperCase(); + + if (!hash) { + throw new Error('Invalid transaction hash'); + } + + onSuccess(hash); + } else { + throw new Error('Transaction failed to commit.'); + } + } catch (error) { + log('NewMarketPreviewForm/submitNewMarketProposal', error); + setErrorMessage(error.message); + } + } + }} + > +

+ {stringGetter({ key: STRING_KEYS.CONFIRM_NEW_MARKET_PROPOSAL })} + + {stringGetter({ key: STRING_KEYS.BALANCE })}:{' '} + {chainTokenLabel}} + /> + +

+ + + ), + }, + { + key: 'mmf', + label: 'MMF', + tooltip: 'maintenance-margin-fraction', + value: ( + + ), + }, + { + key: 'impact-notional', + label: stringGetter({ key: STRING_KEYS.IMPACT_NOTIONAL }), + value: , + }, + ]} + > + + + + + ), + }, + { + key: 'message-details', + label: stringGetter({ key: STRING_KEYS.MESSAGE_DETAILS }), + value: ( + + dispatch( + openDialog({ + type: DialogTypes.NewMarketMessageDetails, + dialogProps: { assetData, clobPairId, liquidityTier }, + }) + ) + } + > + {stringGetter({ key: STRING_KEYS.VIEW_DETAILS })} → + + ), + }, + { + key: 'required-balance', + label: ( + + {stringGetter({ key: STRING_KEYS.REQUIRED_BALANCE })} {chainTokenLabel} + + ), + value: ( + + {'+ '} + + + } + /> + ), + }, + { + key: 'wallet-balance', + label: ( + + {stringGetter({ key: STRING_KEYS.WALLET_BALANCE })} {chainTokenLabel} + + ), + value: ( + + ), + }, + ]} + > +
+ + {alertMessage && ( + {alertMessage.message} + )} + + + + + + {stringGetter({ + key: STRING_KEYS.PROPOSAL_DISCLAIMER, + params: { + NUM_TOKENS_REQUIRED: initialDepositAmount, + NATIVE_TOKEN_DENOM: chainTokenLabel, + }, + })} + + + ); +}; + +const Styled: Record = {}; + +Styled.Form = styled.form` + ${formMixins.transfersForm} + ${layoutMixins.stickyArea0} + --stickyArea0-background: transparent; + + h2 { + ${layoutMixins.row} + justify-content: space-between; + margin: 0; + font: var(--font-large-medium); + color: var(--color-text-2); + } +`; + +Styled.Balance = styled.span` + ${layoutMixins.inlineRow} + font: var(--font-small-book); + margin-top: 0.125rem; + + output { + margin-left: 0.5ch; + } +`; + +Styled.Tag = styled(Tag)` + margin-left: 0.5ch; +`; + +Styled.FormInput = styled(FormInput)` + input { + font-size: 1rem; + } +`; + +Styled.Icon = styled(Icon)<{ $hasError?: boolean }>` + margin-left: 0.5ch; + + ${({ $hasError }) => ($hasError ? 'color: var(--color-error);' : 'color: var(--color-success);')} +`; + +Styled.WithDetailsReceipt = styled(WithDetailsReceipt)` + --details-item-fontSize: 1rem; +`; + +Styled.CheckboxContainer = styled.div` + display: flex; + flex-direction: row; + padding: 1rem; + align-items: center; +`; + +Styled.Disclaimer = styled.div<{ textAlign?: string }>` + font: var(--font-small); + color: var(--color-text-0); + text-align: center; + margin-left: 0.5ch; + + ${({ textAlign }) => textAlign && `text-align: ${textAlign};`} +`; + +Styled.ButtonRow = styled.div` + display: grid; + grid-template-columns: 1fr 2fr; + gap: 1rem; + width: 100%; +`; + +Styled.Button = styled(Button)` + --button-padding: 0; +`; diff --git a/src/views/forms/NewMarketForm/NewMarketSelectionStep.tsx b/src/views/forms/NewMarketForm/NewMarketSelectionStep.tsx new file mode 100644 index 0000000..a2bbd1c --- /dev/null +++ b/src/views/forms/NewMarketForm/NewMarketSelectionStep.tsx @@ -0,0 +1,466 @@ +import { FormEvent, useEffect, useMemo, useState } from 'react'; +import styled, { AnyStyledComponent } from 'styled-components'; +import { Root, Item } from '@radix-ui/react-radio-group'; +import { shallowEqual, useDispatch, useSelector } from 'react-redux'; + +import { OnboardingState } from '@/constants/account'; +import { AlertType } from '@/constants/alerts'; +import { ButtonAction, ButtonShape, ButtonSize, ButtonType } from '@/constants/buttons'; +import { DialogTypes } from '@/constants/dialogs'; +import { STRING_KEYS } from '@/constants/localization'; +import { isMainnet } from '@/constants/networks'; +import { TOKEN_DECIMALS } from '@/constants/numbers'; + +import { + LIQUIDITY_TIERS, + NUM_ORACLES_TO_QUALIFY_AS_SAFE, + type PotentialMarketItem, +} from '@/constants/potentialMarkets'; + +import { + useAccountBalance, + useBreakpoints, + useGovernanceVariables, + useStringGetter, + useTokenConfigs, +} from '@/hooks'; +import { usePotentialMarkets } from '@/hooks/usePotentialMarkets'; + +import { breakpoints } from '@/styles'; +import { formMixins } from '@/styles/formMixins'; +import { layoutMixins } from '@/styles/layoutMixins'; + +import { AlertMessage } from '@/components/AlertMessage'; +import { Button } from '@/components/Button'; +import { Details } from '@/components/Details'; +import { Icon, IconName } from '@/components/Icon'; +import { Output, OutputType } from '@/components/Output'; +import { Tag } from '@/components/Tag'; +import { SearchSelectMenu } from '@/components/SearchSelectMenu'; +import { WithReceipt } from '@/components/WithReceipt'; + +import { OnboardingTriggerButton } from '@/views/dialogs/OnboardingTriggerButton'; + +import { getOnboardingState } from '@/state/accountSelectors'; +import { openDialog } from '@/state/dialogs'; +import { getMarketIds } from '@/state/perpetualsSelectors'; + +import { isTruthy } from '@/lib/isTruthy'; +import { MustBigNumber } from '@/lib/numbers'; + +type NewMarketSelectionStepProps = { + assetToAdd?: PotentialMarketItem; + clobPairId?: number; + setAssetToAdd: (assetToAdd?: PotentialMarketItem) => void; + onConfirmMarket: () => void; + liquidityTier?: number; + setLiquidityTier: (liquidityTier?: number) => void; + tickSizeDecimals: number; +}; + +export const NewMarketSelectionStep = ({ + assetToAdd, + clobPairId, + setAssetToAdd, + onConfirmMarket, + liquidityTier, + setLiquidityTier, + tickSizeDecimals, +}: NewMarketSelectionStepProps) => { + const dispatch = useDispatch(); + const { nativeTokenBalance } = useAccountBalance(); + const onboardingState = useSelector(getOnboardingState); + const isDisconnected = onboardingState === OnboardingState.Disconnected; + const { isMobile } = useBreakpoints(); + const marketIds = useSelector(getMarketIds, shallowEqual); + const { chainTokenDecimals, chainTokenLabel } = useTokenConfigs(); + const { potentialMarkets, exchangeConfigs } = usePotentialMarkets(); + const stringGetter = useStringGetter(); + const { newMarketProposal } = useGovernanceVariables(); + const initialDepositAmountBN = MustBigNumber(newMarketProposal.initialDepositAmount).div( + Number(`1e${chainTokenDecimals}`) + ); + const initialDepositAmountDecimals = isMainnet ? 0 : chainTokenDecimals; + const initialDepositAmount = initialDepositAmountBN.toFixed(initialDepositAmountDecimals); + + const [tempLiquidityTier, setTempLiquidityTier] = useState(); + const [canModifyLiqTier, setCanModifyLiqTier] = useState(false); + + const alertMessage = useMemo(() => { + if (nativeTokenBalance.lt(initialDepositAmountBN)) { + return { + type: AlertType.Warning, + message: stringGetter({ + key: STRING_KEYS.NOT_ENOUGH_BALANCE, + params: { + NUM_TOKENS_REQUIRED: initialDepositAmount, + NATIVE_TOKEN_DENOM: chainTokenLabel, + }, + }), + }; + } + + return null; + }, [nativeTokenBalance, stringGetter]); + + useEffect(() => { + if (assetToAdd) { + setTempLiquidityTier(assetToAdd.liquidityTier); + setLiquidityTier(assetToAdd.liquidityTier); + } + }, [assetToAdd]); + + const filteredPotentialMarkets = useMemo(() => { + return potentialMarkets?.filter( + ({ baseAsset, numOracles }) => + exchangeConfigs?.[baseAsset] !== undefined && + Number(numOracles) >= NUM_ORACLES_TO_QUALIFY_AS_SAFE && + !marketIds.includes(`${baseAsset}-USD`) + ); + }, [exchangeConfigs, potentialMarkets, marketIds]); + + return ( + ) => { + e.preventDefault(); + if (canModifyLiqTier) { + setLiquidityTier(tempLiquidityTier); + setCanModifyLiqTier(false); + } else { + onConfirmMarket(); + } + }} + > +

+ {stringGetter({ key: STRING_KEYS.ADD_A_MARKET })} + + {stringGetter({ key: STRING_KEYS.BALANCE })}:{' '} + {chainTokenLabel}} + /> + +

+ ({ + value: potentialMarket.baseAsset, + label: potentialMarket?.assetName ?? potentialMarket.baseAsset, + tag: `${potentialMarket.baseAsset}-USD`, + onSelect: () => { + setAssetToAdd(potentialMarket); + }, + })) ?? [], + }, + ]} + label={stringGetter({ key: STRING_KEYS.MARKETS })} + > + {assetToAdd ? ( + + {assetToAdd?.assetName ?? assetToAdd.baseAsset} {assetToAdd?.baseAsset}-USD + + ) : ( + 'e.g. "BTC-USD"' + )} + + {assetToAdd && ( + <> +
{stringGetter({ key: STRING_KEYS.POPULATED_DETAILS })}
+
+ + + {stringGetter({ key: STRING_KEYS.LIQUIDITY_TIER })} + + + {canModifyLiqTier && ( + + )} + + + + {Object.keys(LIQUIDITY_TIERS).map((tier) => { + const { maintenanceMarginFraction, impactNotional, label, initialMarginFraction } = + LIQUIDITY_TIERS[tier as unknown as keyof typeof LIQUIDITY_TIERS]; + return ( + + + {label} + {Number(tier) === assetToAdd?.liquidityTier && ( + + ✨ {stringGetter({ key: STRING_KEYS.RECOMMENDED })} + + )} + + + ), + }, + { + key: 'mmf', + label: 'MMF', + tooltip: 'maintenance-margin-fraction', + value: ( + + ), + }, + { + key: 'impact-notional', + label: stringGetter({ key: STRING_KEYS.IMPACT_NOTIONAL }), + value: , + }, + ]} + /> + + ); + })} + +
+ + )} + {alertMessage && ( + {alertMessage.message} + )} + + ), + }, + assetToAdd && { + key: 'message-details', + label: stringGetter({ key: STRING_KEYS.MESSAGE_DETAILS }), + value: ( + + dispatch( + openDialog({ + type: DialogTypes.NewMarketMessageDetails, + dialogProps: { assetData: assetToAdd, clobPairId, liquidityTier }, + }) + ) + } + > + {stringGetter({ key: STRING_KEYS.VIEW_DETAILS })} → + + ), + }, + { + key: 'dydx-required', + label: ( + + {stringGetter({ key: STRING_KEYS.REQUIRED_BALANCE })}{' '} + {chainTokenLabel} + + ), + value: ( + + {stringGetter({ + key: STRING_KEYS.OR_MORE, + params: { + NUMBER: ( + + ), + }, + })} + + ), + }, + ].filter(isTruthy)} + /> + } + > + {isDisconnected ? ( + + ) : ( + + )} + +
+ ); +}; + +const Styled: Record = {}; + +Styled.Form = styled.form` + ${formMixins.transfersForm} + ${layoutMixins.stickyArea0} + --stickyArea0-background: transparent; + + h2 { + ${layoutMixins.row} + justify-content: space-between; + margin: 0; + font: var(--font-large-medium); + color: var(--color-text-2); + } +`; + +Styled.Balance = styled.span` + ${layoutMixins.inlineRow} + font: var(--font-small-book); + margin-top: 0.125rem; + + output { + margin-left: 0.5ch; + } +`; + +Styled.Tag = styled(Tag)` + margin-left: 0.5ch; +`; + +Styled.SelectedAsset = styled.span` + color: var(--color-text-2); +`; + +Styled.Disclaimer = styled.div` + color: var(--color-text-0); + margin-left: 0.5ch; +`; + +Styled.Header = styled.div` + display: flex; + flex: 1; + align-items: center; + color: var(--color-text-2); + font: var(--font-base-medium); + justify-content: space-between; +`; + +Styled.ButtonRow = styled.div` + display: flex; + flex-direction: row; + gap: 0.5rem; + + button { + min-width: 80px; + } +`; + +Styled.Root = styled(Root)` + display: flex; + flex-direction: column; + gap: 1rem; + padding: 1rem; + border-radius: 10px; + border: 1px solid var(--color-layer-6); + background-color: var(--color-layer-4); +`; + +Styled.LiquidityTierRadioButton = styled(Item)<{ selected?: boolean }>` + display: flex; + flex-direction: column; + border-radius: 0.625rem; + border: 1px solid var(--color-layer-6); + padding: 1rem 0; + font: var(--font-mini-book); + + ${({ selected }) => selected && 'background-color: var(--color-layer-2)'} +`; + +Styled.Details = styled(Details)` + margin-top: 0.5rem; + padding: 0; + + dt { + text-align: left; + } + + @media ${breakpoints.mobile} { + padding: 0 1rem; + + dd { + margin-bottom: 0.5rem; + } + } +`; + +Styled.ReceiptDetails = styled(Details)` + padding: 0.375rem 0.75rem 0.25rem; +`; + +Styled.Output = styled(Output)` + display: inline-block; +`; + +Styled.Button = styled(Button)` + --button-padding: 0; +`; diff --git a/src/views/forms/NewMarketForm/NewMarketSuccessStep.tsx b/src/views/forms/NewMarketForm/NewMarketSuccessStep.tsx new file mode 100644 index 0000000..32fda43 --- /dev/null +++ b/src/views/forms/NewMarketForm/NewMarketSuccessStep.tsx @@ -0,0 +1,81 @@ +import styled, { AnyStyledComponent } from 'styled-components'; + +import { ButtonAction, ButtonType } from '@/constants/buttons'; +import { STRING_KEYS } from '@/constants/localization'; +import { useStringGetter } from '@/hooks'; +import { LinkOutIcon } from '@/icons'; + +import { Button } from '@/components/Button'; +import { Icon, IconName } from '@/components/Icon'; + +type NewMarketSuccessStepProps = { + href: string; +}; + +export const NewMarketSuccessStep = ({ href }: NewMarketSuccessStepProps) => { + const stringGetter = useStringGetter(); + + return ( + + + + + + +

{stringGetter({ key: STRING_KEYS.SUBMITTED_PROPOSAL })}

+ {stringGetter({ key: STRING_KEYS.PROPOSAL_SUBMISSION_SUCCESSFUL })} + +
+ ); +}; + +const Styled: Record = {}; + +Styled.ProposalSent = styled.div` + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 1rem; + padding: 1rem; + + && { + h2 { + margin: 0 1rem; + } + } +`; + +Styled.OuterCircle = styled.div` + width: 5.25rem; + height: 5.25rem; + min-width: 5.25rem; + height: 5.25rem; + border-radius: 50%; + background-color: var(--color-gradient-positive); + + display: flex; + align-items: center; + justify-content: center; +`; + +Styled.InnerCircle = styled.div` + width: 2rem; + height: 2rem; + min-width: 2rem; + height: 2rem; + border-radius: 50%; + background-color: var(--color-success); + + display: flex; + align-items: center; + justify-content: center; + + svg { + color: var(--color-layer-2); + } +`; diff --git a/src/views/forms/NewMarketForm/index.tsx b/src/views/forms/NewMarketForm/index.tsx new file mode 100644 index 0000000..85604ce --- /dev/null +++ b/src/views/forms/NewMarketForm/index.tsx @@ -0,0 +1,80 @@ +import { useMemo, useState } from 'react'; +import styled, { AnyStyledComponent } from 'styled-components'; + +import { TOKEN_DECIMALS } from '@/constants/numbers'; +import { type PotentialMarketItem } from '@/constants/potentialMarkets'; +import { useNextClobPairId, useURLConfigs } from '@/hooks'; +import { usePotentialMarkets } from '@/hooks/usePotentialMarkets'; + +import { LoadingSpace } from '@/components/Loading/LoadingSpinner'; + +import { NewMarketSelectionStep } from './NewMarketSelectionStep'; +import { NewMarketPreviewStep } from './NewMarketPreviewStep'; +import { NewMarketSuccessStep } from './NewMarketSuccessStep'; + +enum NewMarketFormStep { + SELECTION, + PREVIEW, + SUCCESS, +} + +export const NewMarketForm = () => { + const [step, setStep] = useState(NewMarketFormStep.SELECTION); + const [assetToAdd, setAssetToAdd] = useState(); + const [liquidityTier, setLiquidityTier] = useState(); + const [proposalTxHash, setProposalTxHash] = useState(); + const { mintscan: mintscanTxUrl } = useURLConfigs(); + + const { nextAvailableClobPairId } = useNextClobPairId(); + const { hasPotentialMarketsData } = usePotentialMarkets(); + + const tickSizeDecimals = useMemo(() => { + if (!assetToAdd) return TOKEN_DECIMALS; + const p = Math.floor(Math.log(Number(assetToAdd.referencePrice))); + return Math.abs(p - 3); + }, [assetToAdd]); + + if (!hasPotentialMarketsData || !nextAvailableClobPairId) { + return ; + } + + if (NewMarketFormStep.SUCCESS === step && proposalTxHash) { + return ; + } + + if (NewMarketFormStep.PREVIEW === step) { + if (assetToAdd && liquidityTier && nextAvailableClobPairId) { + return ( + setStep(NewMarketFormStep.SELECTION)} + onSuccess={(hash: string) => { + setProposalTxHash(hash); + setStep(NewMarketFormStep.SUCCESS); + }} + tickSizeDecimals={tickSizeDecimals} + /> + ); + } + } + + return ( + setStep(NewMarketFormStep.PREVIEW)} + assetToAdd={assetToAdd} + clobPairId={nextAvailableClobPairId} + setAssetToAdd={setAssetToAdd} + liquidityTier={liquidityTier} + setLiquidityTier={setLiquidityTier} + tickSizeDecimals={tickSizeDecimals} + /> + ); +}; + +const Styled: Record = {}; + +Styled.LoadingSpace = styled(LoadingSpace)` + min-height: 18.75rem; +`; diff --git a/src/views/menus/useGlobalCommands.tsx b/src/views/menus/useGlobalCommands.tsx index 396fcd1..017df38 100644 --- a/src/views/menus/useGlobalCommands.tsx +++ b/src/views/menus/useGlobalCommands.tsx @@ -11,6 +11,7 @@ import { setSelectedTradeLayout } from '@/state/layout'; import { getAssets } from '@/state/assetsSelectors'; import { getPerpetualMarkets } from '@/state/perpetualsSelectors'; +import { Asset, PerpetualMarket } from '@/constants/abacus'; enum ThemeItems { SetClassicTheme = 'SetDefaultTheme', @@ -44,7 +45,7 @@ export const useGlobalCommands = (): MenuConfig => { const joinedPerpetualMarketsAndAssets = Object.values(allPerpetualMarkets).map((market) => ({ ...market, ...allAssets[market?.assetId], - })); + })) as Array; return [ { @@ -129,10 +130,10 @@ export const useGlobalCommands = (): MenuConfig => { { value: NavItems.NavigateToMarket, label: 'Navigate to Market', - subitems: joinedPerpetualMarketsAndAssets.map(({ market = '', name = '', id = '' }) => ({ - value: market, + subitems: joinedPerpetualMarketsAndAssets.map(({ market, name, id }) => ({ + value: market ?? '', slotBefore: , - label: name, + label: name ?? '', tag: id, onSelect: () => navigate(`/trade/${market}`), })),