diff --git a/package.json b/package.json index c200637..2044d6a 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,10 @@ "@cosmjs/encoding": "^0.31.0", "@cosmjs/proto-signing": "^0.31.0", "@cosmjs/stargate": "^0.31.0", - "@dydxprotocol/abacus": "^0.2.37", "@cosmjs/tendermint-rpc": "^0.31.0", - "@dydxprotocol/v4-client": "^0.29.0", + "@dydxprotocol/abacus": "^0.3.10", + "@dydxprotocol/v4-client-js": "^0.30.3", + "@dydxprotocol/v4-localization": "^0.0.16", "@ethersproject/providers": "^5.7.2", "@js-joda/core": "^5.5.3", "@radix-ui/react-collapsible": "^1.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a7f94ab..96b10c9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + dependencies: '@0xsquid/sdk': specifier: ^1.7.2 @@ -23,11 +27,14 @@ dependencies: specifier: ^0.31.0 version: 0.31.0 '@dydxprotocol/abacus': - specifier: ^0.2.37 - version: 0.2.37 - '@dydxprotocol/v4-client': - specifier: ^0.29.0 - version: 0.29.0 + specifier: ^0.3.10 + version: 0.3.10 + '@dydxprotocol/v4-client-js': + specifier: ^0.30.3 + version: 0.30.3 + '@dydxprotocol/v4-localization': + specifier: ^0.0.16 + version: 0.0.16 '@ethersproject/providers': specifier: ^5.7.2 version: 5.7.2 @@ -1139,8 +1146,8 @@ packages: resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==} dev: true - /@dydxprotocol/abacus@0.2.37: - resolution: {integrity: sha512-amoq9aVXo+lVTQGu2jsyy5/0bniOMEXpyJDmaAr2TpbrtQtw2WgyAP+se9Q5wt3yh0Mzdtsh7P2h090kH7/bZQ==} + /@dydxprotocol/abacus@0.3.10: + resolution: {integrity: sha512-CJV6zyoQLAoDWJdgLbP1Y2QYvSPybCGpykQY+WEWk4kQKnZkjxz25LPL0b8I9LrNDt2JknOxPJfAoUDXJPfNkg==} dev: false /@dydxprotocol/dydxjs@0.3.0: @@ -1160,8 +1167,8 @@ packages: - utf-8-validate dev: false - /@dydxprotocol/v4-client@0.29.0: - resolution: {integrity: sha512-BMgm6e91LFGKB0l3lC2/0aIgayejgBa7qCwCUxr05265tggZsI3l3Cui8LNDHeb8IAQ4KPcfAJ29c96lx+rLlw==} + /@dydxprotocol/v4-client-js@0.30.3: + resolution: {integrity: sha512-h9nB2cU+6sWwfOTQz6sMKZZxVa/Iwp1JciUqKi5HDUyWl/4wfbczDlUqbMUUeXgBgfbb9CImxn+PjF0v7lcD5A==} dependencies: '@cosmjs/amino': 0.30.1 '@cosmjs/proto-signing': 0.30.1 @@ -1183,6 +1190,10 @@ packages: - utf-8-validate dev: false + /@dydxprotocol/v4-localization@0.0.16: + resolution: {integrity: sha512-IuTjuVdGwV6nulBLCxbNydsEkwvx7mBn8SQtPP2pQ16yfUNWMyBG3GDEXlfAk41NcPSCGXlK5Wbl0R1xaOKCRA==} + dev: false + /@emotion/is-prop-valid@1.2.1: resolution: {integrity: sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==} dependencies: @@ -15851,7 +15862,3 @@ packages: release-it: 15.11.0 semver: 7.5.1 dev: false - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false diff --git a/src/components/OrderSideTag.stories.tsx b/src/components/OrderSideTag.stories.tsx index 7901238..088d456 100644 --- a/src/components/OrderSideTag.stories.tsx +++ b/src/components/OrderSideTag.stories.tsx @@ -1,5 +1,5 @@ import type { Story } from '@ladle/react'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { OrderSideTag } from '@/components/OrderSideTag'; diff --git a/src/components/OrderSideTag.tsx b/src/components/OrderSideTag.tsx index 47b3630..430426b 100644 --- a/src/components/OrderSideTag.tsx +++ b/src/components/OrderSideTag.tsx @@ -1,4 +1,4 @@ -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { STRING_KEYS } from '@/constants/localization'; import { useStringGetter } from '@/hooks'; diff --git a/src/constants/abacus.ts b/src/constants/abacus.ts index 8ba534b..04b1845 100644 --- a/src/constants/abacus.ts +++ b/src/constants/abacus.ts @@ -1,5 +1,5 @@ import Abacus, { kollections } from '@dydxprotocol/abacus'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { PositionSide, TradeTypes } from './trade'; import { STRING_KEYS } from './localization'; @@ -36,6 +36,12 @@ export type AbacusThreadingProtocol = Omit< Abacus.exchange.dydx.abacus.protocols.ThreadingProtocol, '__doNotUseOrImplementIt' >; +export type AbacusFileSystemProtocol = Omit< + Abacus.exchange.dydx.abacus.protocols.FileSystemProtocol, + '__doNotUseOrImplementIt' +>; + +export type FileLocation = Abacus.exchange.dydx.abacus.protocols.FileLocation; export type ThreadingType = Abacus.exchange.dydx.abacus.protocols.ThreadingType; export const CoroutineTimer = Abacus.exchange.dydx.abacus.utils.CoroutineTimer; @@ -180,6 +186,9 @@ export const RiskLevel = Abacus.exchange.dydx.abacus.utils.RiskLevel; const riskLevels = [...RiskLevel.values()] as const; export type RiskLevels = (typeof riskLevels)[number]; +// ------ Notifications ------ // +export type AbacusNotification = Abacus.exchange.dydx.abacus.output.Notification; + // ------ Enum Conversions ------ // type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A diff --git a/src/constants/networks.tsx b/src/constants/networks.tsx index f0a079f..7861da6 100644 --- a/src/constants/networks.tsx +++ b/src/constants/networks.tsx @@ -1,73 +1,29 @@ +import { ENDPOINTS, DEV_ENDPOINTS } from '@dydxprotocol/v4-localization'; + +export const NETWORK_ENDPOINTS = import.meta.env.MODE === 'production' ? ENDPOINTS : DEV_ENDPOINTS; + +export const CLIENT_NETWORK_CONFIGS: Record< + string, + (typeof NETWORK_ENDPOINTS.environments)[number] +> = Object.fromEntries( + NETWORK_ENDPOINTS.environments.map((environment) => [environment.environment, environment]) +); + +export const DEFAULT_APP_ENVIRONMENT = NETWORK_ENDPOINTS.defaultEnvironment; + export enum DydxV4Network { V4Mainnet = 'dydxprotocol-mainnet', V4Staging = 'dydxprotocol-staging', - V4Testnet2 = 'dydxprotocol-testnet-2', + V4Testnet2 = 'dydxprotocol-testnet', V4Local = 'dydxprotocol-dev', } -export enum DydxV3Network { - V3Mainnet = '1', - V3Testnet = '5', -} +export type DydxNetwork = keyof typeof CLIENT_NETWORK_CONFIGS; -export function isDydxV4Network(network: any): network is DydxV4Network { - return Object.values(DydxV4Network).includes(network); +export function isDydxV4Network(network: any): boolean { + return CLIENT_NETWORK_CONFIGS[network]?.version === 'v4'; } export function isValidDydxNetwork(network: any): boolean { - return isDydxV4Network(network) || Object.values(DydxV3Network).includes(network); + return Object.keys(CLIENT_NETWORK_CONFIGS).includes(network); } - -export type DydxNetwork = DydxV4Network | DydxV3Network; - -export const CHAIN_IDS = { - [DydxV4Network.V4Mainnet]: '', - [DydxV4Network.V4Staging]: 'dydxprotocol-testnet', - [DydxV4Network.V4Testnet2]: 'dydx-testnet-2', - [DydxV4Network.V4Local]: 'dydxprotocol-testnet', - [DydxV3Network.V3Mainnet]: '1', - [DydxV3Network.V3Testnet]: '5', -}; - -export const DEFAULT_APP_ENVIRONMENT = - import.meta.env.MODE === 'production' ? DydxV4Network.V4Testnet2 : DydxV4Network.V4Staging; - -export const CLIENT_NETWORK_CONFIGS: Record< - DydxV4Network, - { - chainId: string; - validatorUrl: string; - faucetUrl: string; - indexerUrl: string; - ethereumChainId: number; - } -> = { - [DydxV4Network.V4Mainnet]: { - chainId: CHAIN_IDS[DydxV4Network.V4Mainnet], - validatorUrl: import.meta.env.VITE_VALIDATOR_URL_STAGE, - faucetUrl: import.meta.env.VITE_FAUCET_URL_STAGE, - indexerUrl: import.meta.env.VITE_INDEXER_URL_STAGE, - ethereumChainId: 1, - }, - [DydxV4Network.V4Local]: { - chainId: CHAIN_IDS[DydxV4Network.V4Local], - validatorUrl: import.meta.env.VITE_VALIDATOR_URL_DEV, - faucetUrl: import.meta.env.VITE_FAUCET_URL_DEV, - indexerUrl: import.meta.env.VITE_INDEXER_URL_DEV, - ethereumChainId: 5, - }, - [DydxV4Network.V4Staging]: { - chainId: CHAIN_IDS[DydxV4Network.V4Staging], - validatorUrl: import.meta.env.VITE_VALIDATOR_URL_STAGE, - faucetUrl: import.meta.env.VITE_FAUCET_URL_STAGE, - indexerUrl: import.meta.env.VITE_INDEXER_URL_STAGE, - ethereumChainId: 5, - }, - [DydxV4Network.V4Testnet2]: { - chainId: CHAIN_IDS[DydxV4Network.V4Testnet2], - validatorUrl: import.meta.env.VITE_VALIDATOR_URL_TESTNET2, - faucetUrl: import.meta.env.VITE_FAUCET_URL_TESTNET2, - indexerUrl: import.meta.env.VITE_INDEXER_URL_TESTNET2, - ethereumChainId: 5, - }, -}; diff --git a/src/constants/trade.ts b/src/constants/trade.ts index 7444c49..e85b7a8 100644 --- a/src/constants/trade.ts +++ b/src/constants/trade.ts @@ -1,4 +1,4 @@ -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { AlertType } from '@/constants/alerts'; import { STRING_KEYS } from '@/constants/localization'; diff --git a/src/constants/wallets.ts b/src/constants/wallets.ts index 8e5299b..db13542 100644 --- a/src/constants/wallets.ts +++ b/src/constants/wallets.ts @@ -302,7 +302,7 @@ export type WalletConnection = { // dYdX Chain wallets -import { USDC_DENOM, type Onboarding, DYDX_DENOM } from '@dydxprotocol/v4-client'; +import { USDC_DENOM, type Onboarding, DYDX_DENOM } from '@dydxprotocol/v4-client-js'; import type { suggestChain } from 'graz'; export const COSMOS_DERIVATION_PATH = "m/44'/118'/0'/0/0"; diff --git a/src/hooks/tradingView/useTradingView.ts b/src/hooks/tradingView/useTradingView.ts index 45d2875..5206e2f 100644 --- a/src/hooks/tradingView/useTradingView.ts +++ b/src/hooks/tradingView/useTradingView.ts @@ -1,6 +1,5 @@ import { useEffect } from 'react'; import { shallowEqual, useSelector } from 'react-redux'; -import { useLocation } from 'react-router-dom'; import isEmpty from 'lodash/isEmpty'; import { LanguageCode, ResolutionString, widget } from 'public/tradingview/charting_library'; @@ -14,9 +13,8 @@ import { store } from '@/state/_store'; import { getSelectedNetwork } from '@/state/appSelectors'; import { getAppTheme } from '@/state/configsSelectors'; import { getSelectedLocale } from '@/state/localizationSelectors'; -import { getMarketIds } from '@/state/perpetualsSelectors'; +import { getCurrentMarketId, getMarketIds } from '@/state/perpetualsSelectors'; -import { getMarketIdFromLocation } from '@/lib/tradeData'; import { getDydxDatafeed } from '@/lib/tradingView/dydxfeed'; import { getSavedResolution, getWidgetOptions, getWidgetOverrides } from '@/lib/tradingView/utils'; @@ -30,8 +28,7 @@ export const useTradingView = ({ tvWidgetRef: React.MutableRefObject; setIsChartReady: React.Dispatch>; }) => { - const location = useLocation(); - const marketId = getMarketIdFromLocation(location); + const marketId = useSelector(getCurrentMarketId); const appTheme = useSelector(getAppTheme); const marketIds = useSelector(getMarketIds, shallowEqual); const selectedLocale = useSelector(getSelectedLocale); @@ -50,7 +47,6 @@ export const useTradingView = ({ if (hasMarkets) { const widgetOptions = getWidgetOptions(); const widgetOverrides = getWidgetOverrides(appTheme); - const options = { // debug: true, ...widgetOptions, diff --git a/src/hooks/useAccountBalance.ts b/src/hooks/useAccountBalance.ts index ea9269a..66ff748 100644 --- a/src/hooks/useAccountBalance.ts +++ b/src/hooks/useAccountBalance.ts @@ -5,7 +5,7 @@ import { StargateClient } from '@cosmjs/stargate'; import { useQuery } from 'react-query'; import { formatUnits } from 'viem'; -import { CLIENT_NETWORK_CONFIGS, type DydxV4Network } from '@/constants/networks'; +import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks'; import { QUANTUM_MULTIPLIER } from '@/constants/numbers'; import { EthereumAddress } from '@/constants/wallets'; @@ -15,7 +15,6 @@ import { MustBigNumber } from '@/lib/numbers'; import { getSelectedNetwork } from '@/state/appSelectors'; import { useAccounts } from './useAccounts'; -// import { useDydxClient } from './useDydxClient'; import { usePollNativeTokenBalance } from './usePollNativeTokenBalance'; type UseAccountBalanceProps = { @@ -49,10 +48,8 @@ export const useAccountBalance = ({ }: UseAccountBalanceProps = {}) => { const { evmAddress, dydxAddress } = useAccounts(); - // TODO: let Abacus / useDydxClient handle EVM chain IDs - // const { networkConfig } = useDydxClient(); const selectedNetwork = useSelector(getSelectedNetwork); - const evmChainId = Number(CLIENT_NETWORK_CONFIGS[selectedNetwork as DydxV4Network].ethereumChainId); + const evmChainId = Number(CLIENT_NETWORK_CONFIGS[selectedNetwork].ethereumChainId); const evmQuery = useBalance({ enabled: Boolean(!isCosmosChain && addressOrDenom?.startsWith('0x')), diff --git a/src/hooks/useAccounts.tsx b/src/hooks/useAccounts.tsx index ba7f9dd..824bcf0 100644 --- a/src/hooks/useAccounts.tsx +++ b/src/hooks/useAccounts.tsx @@ -2,7 +2,7 @@ import { useCallback, useContext, createContext, useEffect, useState, useMemo } import { useDispatch } from 'react-redux'; import { AES, enc } from 'crypto-js'; -import { LocalWallet, USDC_DENOM, type Subaccount } from '@dydxprotocol/v4-client'; +import { LocalWallet, USDC_DENOM, type Subaccount } from '@dydxprotocol/v4-client-js'; import { OnboardingGuard, OnboardingState, type EvmDerivedAddresses } from '@/constants/account'; import { LocalStorageKey, LOCAL_STORAGE_VERSIONS } from '@/constants/localStorage'; diff --git a/src/hooks/useCurrentMarketId.ts b/src/hooks/useCurrentMarketId.ts index 528364b..2ae40ee 100644 --- a/src/hooks/useCurrentMarketId.ts +++ b/src/hooks/useCurrentMarketId.ts @@ -29,7 +29,7 @@ export const useCurrentMarketId = () => { const validId = useMemo(() => { if (marketIds.length === 0) return marketId ?? lastViewedMarket; - if (!marketIds.includes(marketId)) return DEFAULT_MARKETID; + if (!marketIds.includes(marketId ?? lastViewedMarket)) return DEFAULT_MARKETID; return marketId ?? lastViewedMarket; }, [marketIds, marketId]); diff --git a/src/hooks/useDisplayedWallets.ts b/src/hooks/useDisplayedWallets.ts index c060e0c..618ad45 100644 --- a/src/hooks/useDisplayedWallets.ts +++ b/src/hooks/useDisplayedWallets.ts @@ -1,4 +1,4 @@ -import { DydxV4Network } from '@/constants/networks'; +import { isDydxV4Network } from '@/constants/networks'; import { WalletType } from '@/constants/wallets'; import { isTruthy } from '@/lib/isTruthy'; @@ -11,9 +11,7 @@ export const useDisplayedWallets = () => { return [ WalletType.MetaMask, - import.meta.env.MODE !== 'production' && - [DydxV4Network.V4Testnet2, DydxV4Network.V4Staging].includes(selectedNetwork) && - WalletType.Keplr, + import.meta.env.MODE !== 'production' && isDydxV4Network(selectedNetwork) && WalletType.Keplr, WalletType.WalletConnect2, WalletType.WalletConnect, diff --git a/src/hooks/useDydxClient.tsx b/src/hooks/useDydxClient.tsx index 2013d67..b0126f9 100644 --- a/src/hooks/useDydxClient.tsx +++ b/src/hooks/useDydxClient.tsx @@ -9,7 +9,7 @@ import { onboarding, Network, ValidatorConfig, -} from '@dydxprotocol/v4-client'; +} from '@dydxprotocol/v4-client-js'; import type { ResolutionString } from 'public/tradingview/charting_library'; diff --git a/src/hooks/useInitializePage.ts b/src/hooks/useInitializePage.ts index b9c66a6..ad9e1a9 100644 --- a/src/hooks/useInitializePage.ts +++ b/src/hooks/useInitializePage.ts @@ -3,11 +3,7 @@ import { useDispatch } from 'react-redux'; import { LocalStorageKey } from '@/constants/localStorage'; -import { - DEFAULT_APP_ENVIRONMENT, - DydxNetwork, - isValidDydxNetwork, -} from '@/constants/networks'; +import { DEFAULT_APP_ENVIRONMENT, DydxNetwork, isValidDydxNetwork } from '@/constants/networks'; import { useLocalStorage } from '@/hooks'; diff --git a/src/hooks/usePollNativeTokenBalance.ts b/src/hooks/usePollNativeTokenBalance.ts index 53f892a..9c91c91 100644 --- a/src/hooks/usePollNativeTokenBalance.ts +++ b/src/hooks/usePollNativeTokenBalance.ts @@ -3,7 +3,7 @@ import { useQuery } from 'react-query'; import { useAccounts } from '@/hooks'; import { DydxAddress } from '@/constants/wallets'; -import { DYDX_DENOM } from '@dydxprotocol/v4-client'; +import { DYDX_DENOM } from '@dydxprotocol/v4-client-js'; const ACCOUNT_BALANCE_POLLING_INTERVAL = 60_000; diff --git a/src/hooks/useSelectedNetwork.ts b/src/hooks/useSelectedNetwork.ts index 2f63c16..ca4cbb0 100644 --- a/src/hooks/useSelectedNetwork.ts +++ b/src/hooks/useSelectedNetwork.ts @@ -1,8 +1,8 @@ -import { useCallback, useEffect } from 'react'; +import { useCallback } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { LocalStorageKey } from '@/constants/localStorage'; -import { DEFAULT_APP_ENVIRONMENT, DydxNetwork, DydxV4Network } from '@/constants/networks'; +import { DEFAULT_APP_ENVIRONMENT, DydxNetwork } from '@/constants/networks'; import { useAccounts, useLocalStorage } from '@/hooks'; diff --git a/src/hooks/useSubaccount.tsx b/src/hooks/useSubaccount.tsx index a65082c..184c9e0 100644 --- a/src/hooks/useSubaccount.tsx +++ b/src/hooks/useSubaccount.tsx @@ -17,7 +17,7 @@ import { DYDX_DENOM, USDC_DENOM, GAS_PRICE_DYDX_DENOM, -} from '@dydxprotocol/v4-client'; +} from '@dydxprotocol/v4-client-js'; import type { HumanReadableCancelOrderPayload, diff --git a/src/lib/abacus/conversions.ts b/src/lib/abacus/conversions.ts index c9690e5..ee68222 100644 --- a/src/lib/abacus/conversions.ts +++ b/src/lib/abacus/conversions.ts @@ -1,4 +1,4 @@ -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { AbacusOrderSide, diff --git a/src/lib/abacus/dydxChainQueries.ts b/src/lib/abacus/dydxChainQueries.ts index 54f476d..a7e359c 100644 --- a/src/lib/abacus/dydxChainQueries.ts +++ b/src/lib/abacus/dydxChainQueries.ts @@ -8,7 +8,7 @@ import { Network, NetworkOptimizer, ValidatorConfig, -} from '@dydxprotocol/v4-client'; +} from '@dydxprotocol/v4-client-js'; import { type AbacusDydxChainQueriesProtocol, diff --git a/src/lib/abacus/filesystem.ts b/src/lib/abacus/filesystem.ts new file mode 100644 index 0000000..08a6f56 --- /dev/null +++ b/src/lib/abacus/filesystem.ts @@ -0,0 +1,23 @@ +import type { AbacusFileSystemProtocol, FileLocation, Nullable } from '@/constants/abacus'; +import { NETWORK_ENDPOINTS } from '@/constants/networks'; + +export const ENDPOINTS_PATH = + import.meta.env.MODE === 'production' + ? 'config/prod/endpoints.json' + : 'config/staging/dev_endpoints.json'; + +class AbacusFileSystem implements AbacusFileSystemProtocol { + readTextFile(location: FileLocation, path: string): Nullable { + if (path === ENDPOINTS_PATH) { + return JSON.stringify(NETWORK_ENDPOINTS); + } + + return null; + } + + writeTextFile(path: string, text: string): boolean { + return true; + } +} + +export default AbacusFileSystem; diff --git a/src/lib/abacus/index.ts b/src/lib/abacus/index.ts index d4ed16f..0d70787 100644 --- a/src/lib/abacus/index.ts +++ b/src/lib/abacus/index.ts @@ -36,8 +36,8 @@ import AbacusStateNotifier from './stateNotification'; import AbacusLocalizer from './localizer'; import AbacusFormatter from './formatter'; import AbacusThreading from './threading'; +import AbacusFileSystem, { ENDPOINTS_PATH } from './filesystem'; import { LocaleSeparators } from '../numbers'; - class AbacusStateManager { private store: RootStore | undefined; private currentMarket: string | undefined; @@ -62,7 +62,7 @@ class AbacusStateManager { null, new AbacusThreading(), new CoroutineTimer(), - null + new AbacusFileSystem() ); const uiImplementations = new UIImplementations( @@ -72,6 +72,8 @@ class AbacusStateManager { ); this.stateManager = new AsyncAbacusStateManager( + import.meta.env.SHARED_RESOURCES_URI, + ENDPOINTS_PATH, ioImplementations, uiImplementations, // @ts-ignore diff --git a/src/lib/abacus/stateNotification.ts b/src/lib/abacus/stateNotification.ts index fbadc75..32edb39 100644 --- a/src/lib/abacus/stateNotification.ts +++ b/src/lib/abacus/stateNotification.ts @@ -1,5 +1,8 @@ +import { kollections } from '@dydxprotocol/abacus'; + import type { AbacusApiState, + AbacusNotification, AbacusStateNotificationProtocol, Asset, Nullable, @@ -36,6 +39,14 @@ class AbacusStateNotifier implements AbacusStateNotificationProtocol { this.store = undefined; } + environmentsChanged(): void { + return; + } + + notificationsChanged(notifications: kollections.List): void { + return; + } + stateChanged( updatedState: Nullable, incomingChanges: Nullable diff --git a/src/lib/tradeData.ts b/src/lib/tradeData.ts index 416cc8c..f8ba970 100644 --- a/src/lib/tradeData.ts +++ b/src/lib/tradeData.ts @@ -1,5 +1,5 @@ import { type Location, matchPath } from 'react-router-dom'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { StringGetterFunction } from '@/constants/localization'; diff --git a/src/localization/en/app.json b/src/localization/en/app.json index 95c49cd..b7b8561 100644 --- a/src/localization/en/app.json +++ b/src/localization/en/app.json @@ -1209,5 +1209,20 @@ "NODE_DOWN": "Node cannot be reached.", "NODE_HALTED": "Node has halted on block {BLOCK_NUMBER}.", "UNKNOWN_API_ERROR": "Unknown API error" + }, + "CHAIN": { + "V3_MAINNET": "V3 Mainnet", + "V3_GOERLI": "V3 Staging", + "V4_DEVNET": "V4 Dev 1", + "V4_DEVNET_2": "V4 Dev 2", + "V4_DEVNET_3": "V4 Dev 3", + "V4_DEVNET_4": "V4 Dev 4", + "V4_DEVNET_5": "V4 Dev 5", + "V4_STAGING": "V4 Staging", + "V4_TESTNET2": "V4 Testnet", + "V4_TESTNET2_DSRV": "V4 Testnet (DSRV)", + "V4_TESTNET2_DYDX": "V4 Testnet (dYdX)", + "V4_TESTNET2_NODEFLEET": "V4 Testnet (nodefleet)", + "V4_TESTNET2_IMPERATOR": "V4 Testnet (Imperator)" } } diff --git a/src/state/accountCalculators.ts b/src/state/accountCalculators.ts index 45ab47a..10f0c48 100644 --- a/src/state/accountCalculators.ts +++ b/src/state/accountCalculators.ts @@ -1,7 +1,7 @@ import { createSelector } from 'reselect'; import { SubaccountPosition } from '@/constants/abacus'; -import { OnboardingGuard, OnboardingState, OnboardingSteps } from '@/constants/account'; +import { OnboardingState, OnboardingSteps } from '@/constants/account'; import { isDydxV4Network } from '@/constants/networks'; import { diff --git a/src/state/accountSelectors.ts b/src/state/accountSelectors.ts index 29aa72e..4adb879 100644 --- a/src/state/accountSelectors.ts +++ b/src/state/accountSelectors.ts @@ -1,4 +1,4 @@ -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { createSelector } from 'reselect'; import { diff --git a/src/views/charts/DepthChart.tsx b/src/views/charts/DepthChart.tsx index e2aa6e7..cd49893 100644 --- a/src/views/charts/DepthChart.tsx +++ b/src/views/charts/DepthChart.tsx @@ -33,7 +33,7 @@ import { Details } from '@/components/Details'; import { LoadingSpace } from '@/components/Loading/LoadingSpinner'; import { Output, OutputType } from '@/components/Output'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; // @ts-ignore const theme = buildChartTheme({ diff --git a/src/views/dialogs/ExchangeOfflineDialog.tsx b/src/views/dialogs/ExchangeOfflineDialog.tsx index ead24ac..2388963 100644 --- a/src/views/dialogs/ExchangeOfflineDialog.tsx +++ b/src/views/dialogs/ExchangeOfflineDialog.tsx @@ -3,7 +3,7 @@ import styled, { AnyStyledComponent } from 'styled-components'; import { useDispatch, useSelector } from 'react-redux'; import { AbacusApiStatus } from '@/constants/abacus'; -import { DydxV4Network } from '@/constants/networks'; +import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks'; import { UNICODE } from '@/constants/unicode'; import { STRING_KEYS } from '@/constants/localization'; @@ -44,7 +44,7 @@ export const ExchangeOfflineDialog = ({ preventClose, setIsOpen }: ElementProps) >

{statusErrorMessage}

- {selectedNetwork === DydxV4Network.V4Testnet2 && ( + {CLIENT_NETWORK_CONFIGS[selectedNetwork].dydxChainId === 'dydx-testnet-2' && ( {stringGetter({ key: STRING_KEYS.LEARN_MORE })} {UNICODE.ARROW_RIGHT} diff --git a/src/views/dialogs/OnboardingDialog/GenerateKeys.tsx b/src/views/dialogs/OnboardingDialog/GenerateKeys.tsx index 2a8e6b8..84a704d 100644 --- a/src/views/dialogs/OnboardingDialog/GenerateKeys.tsx +++ b/src/views/dialogs/OnboardingDialog/GenerateKeys.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { useSignTypedData } from 'wagmi'; import styled, { type AnyStyledComponent, css } from 'styled-components'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { AES } from 'crypto-js'; import { EvmDerivedAccountStatus } from '@/constants/account'; @@ -9,7 +9,7 @@ import { AlertType } from '@/constants/alerts'; import { AnalyticsEvent } from '@/constants/analytics'; import { ButtonAction } from '@/constants/buttons'; import { STRING_KEYS } from '@/constants/localization'; -import { CLIENT_NETWORK_CONFIGS, DydxV4Network } from '@/constants/networks'; +import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks'; import { DydxAddress, SIGN_TYPED_DATA } from '@/constants/wallets'; import { useAccounts, useBreakpoints, useDydxClient, useStringGetter } from '@/hooks'; @@ -54,7 +54,7 @@ export const GenerateKeys = ({ // 1. Switch network const selectedNetwork = useSelector(getSelectedNetwork); - const chainId = Number(CLIENT_NETWORK_CONFIGS[selectedNetwork as DydxV4Network].ethereumChainId); + const chainId = Number(CLIENT_NETWORK_CONFIGS[selectedNetwork].ethereumChainId); const { isMatchingNetwork, matchNetwork, isSwitchingNetwork } = useMatchingEvmNetwork({ chainId, diff --git a/src/views/forms/AccountManagementForms/DepositForm.tsx b/src/views/forms/AccountManagementForms/DepositForm.tsx index 5366823..eee9207 100644 --- a/src/views/forms/AccountManagementForms/DepositForm.tsx +++ b/src/views/forms/AccountManagementForms/DepositForm.tsx @@ -2,14 +2,10 @@ import { type FormEvent, useCallback, useEffect, useMemo, useState } from 'react import styled, { type AnyStyledComponent } from 'styled-components'; import { type NumberFormatValues } from 'react-number-format'; import { shallowEqual, useSelector } from 'react-redux'; -import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client'; +import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client-js'; import { ethers } from 'ethers'; -import { - TransferInputField, - TransferInputTokenResource, - TransferType, -} from '@/constants/abacus'; +import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus'; import { AlertType } from '@/constants/alerts'; import { ButtonSize } from '@/constants/buttons'; import { STRING_KEYS } from '@/constants/localization'; @@ -54,8 +50,13 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => { const { signerWagmi } = useAccounts(); - const { requestPayload, token, chain: chainIdStr, resources } = useSelector(getTransferInputs, shallowEqual) || {}; - const chainId = chainIdStr ? parseInt(chainIdStr) : undefined + const { + requestPayload, + token, + chain: chainIdStr, + resources, + } = useSelector(getTransferInputs, shallowEqual) || {}; + const chainId = chainIdStr ? parseInt(chainIdStr) : undefined; // User inputs const sourceToken = useMemo( @@ -197,7 +198,6 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => { abacusStateManager.clearTransferInputValues(); setFromAmount(''); } - } catch (error) { setError(error); } finally { diff --git a/src/views/forms/AccountManagementForms/WithdrawForm.tsx b/src/views/forms/AccountManagementForms/WithdrawForm.tsx index 3c2f1f4..103f7ab 100644 --- a/src/views/forms/AccountManagementForms/WithdrawForm.tsx +++ b/src/views/forms/AccountManagementForms/WithdrawForm.tsx @@ -3,11 +3,11 @@ import type { ChangeEvent, FormEvent } from 'react'; import styled, { type AnyStyledComponent } from 'styled-components'; import type { NumberFormatValues } from 'react-number-format'; import { shallowEqual, useSelector } from 'react-redux'; -import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client'; +import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client-js'; import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus'; import { AlertType } from '@/constants/alerts'; -import { ButtonSize } from '@/constants/buttons'; +import { ButtonSize } from '@/constants/buttons'; import { STRING_KEYS } from '@/constants/localization'; import { NumberSign, QUANTUM_MULTIPLIER } from '@/constants/numbers'; diff --git a/src/views/forms/TradeForm/LeverageSlider.stories.tsx b/src/views/forms/TradeForm/LeverageSlider.stories.tsx index b41d81d..8290697 100644 --- a/src/views/forms/TradeForm/LeverageSlider.stories.tsx +++ b/src/views/forms/TradeForm/LeverageSlider.stories.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import type { Story } from '@ladle/react'; import styled, { AnyStyledComponent } from 'styled-components'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { PositionSide } from '@/constants/trade'; import { breakpoints } from '@/styles'; diff --git a/src/views/forms/TradeForm/LeverageSlider.tsx b/src/views/forms/TradeForm/LeverageSlider.tsx index 4f04311..b18a1c0 100644 --- a/src/views/forms/TradeForm/LeverageSlider.tsx +++ b/src/views/forms/TradeForm/LeverageSlider.tsx @@ -2,7 +2,7 @@ import { type Dispatch, type SetStateAction, useCallback, useMemo } from 'react' import styled, { AnyStyledComponent, css } from 'styled-components'; import { Root, Thumb, Track } from '@radix-ui/react-slider'; import _ from 'lodash'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { type Nullable, TradeInputField } from '@/constants/abacus'; import { PositionSide } from '@/constants/trade'; @@ -43,9 +43,7 @@ export const LeverageSlider = ({ }, [PositionSide.Long]: { min: - orderSide === OrderSide.BUY - ? leverageBN.toNumber() - : maxLeverageBN.negated().toNumber(), + orderSide === OrderSide.BUY ? leverageBN.toNumber() : maxLeverageBN.negated().toNumber(), max: orderSide === OrderSide.BUY ? maxLeverageBN.toNumber() : leverageBN.toNumber(), midpoint: orderSide === OrderSide.SELL @@ -56,9 +54,7 @@ export const LeverageSlider = ({ }, [PositionSide.Short]: { min: - orderSide === OrderSide.BUY - ? leverageBN.toNumber() - : maxLeverageBN.negated().toNumber(), + orderSide === OrderSide.BUY ? leverageBN.toNumber() : maxLeverageBN.negated().toNumber(), max: orderSide === OrderSide.BUY ? maxLeverageBN.toNumber() : leverageBN.toNumber(), midpoint: orderSide === OrderSide.BUY diff --git a/src/views/forms/TradeForm/MarketLeverageInput.tsx b/src/views/forms/TradeForm/MarketLeverageInput.tsx index c92b118..04fa56a 100644 --- a/src/views/forms/TradeForm/MarketLeverageInput.tsx +++ b/src/views/forms/TradeForm/MarketLeverageInput.tsx @@ -1,7 +1,7 @@ import type { Dispatch, SetStateAction } from 'react'; import { shallowEqual, useSelector } from 'react-redux'; import styled, { AnyStyledComponent } from 'styled-components'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { TradeInputField, Nullable } from '@/constants/abacus'; import { ButtonShape } from '@/constants/buttons'; diff --git a/src/views/forms/TradeForm/PlaceOrderButtonAndReceipt.tsx b/src/views/forms/TradeForm/PlaceOrderButtonAndReceipt.tsx index 5231bf0..f7468aa 100644 --- a/src/views/forms/TradeForm/PlaceOrderButtonAndReceipt.tsx +++ b/src/views/forms/TradeForm/PlaceOrderButtonAndReceipt.tsx @@ -1,5 +1,5 @@ import { shallowEqual, useDispatch, useSelector } from 'react-redux'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import type { TradeInputSummary } from '@/constants/abacus'; import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons'; diff --git a/src/views/forms/TradeForm/TradeSideToggle.tsx b/src/views/forms/TradeForm/TradeSideToggle.tsx index be9eb78..cc5df49 100644 --- a/src/views/forms/TradeForm/TradeSideToggle.tsx +++ b/src/views/forms/TradeForm/TradeSideToggle.tsx @@ -1,7 +1,7 @@ import { memo } from 'react'; import styled, { css } from 'styled-components'; import { shallowEqual, useSelector } from 'react-redux'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { AbacusOrderSide } from '@/constants/abacus'; import { ButtonShape, ButtonSize } from '@/constants/buttons'; @@ -31,9 +31,7 @@ export const TradeSideToggle = memo(() => { onValueChange={(side: OrderSide) => { abacusStateManager.setTradeValue({ value: - side === OrderSide.BUY - ? AbacusOrderSide.buy.rawValue - : AbacusOrderSide.sell.rawValue, + side === OrderSide.BUY ? AbacusOrderSide.buy.rawValue : AbacusOrderSide.sell.rawValue, field: TradeInputField.side, }); }} diff --git a/src/views/forms/TransferForm.tsx b/src/views/forms/TransferForm.tsx index 2131411..c9dda54 100644 --- a/src/views/forms/TransferForm.tsx +++ b/src/views/forms/TransferForm.tsx @@ -5,14 +5,14 @@ import { shallowEqual, useSelector } from 'react-redux'; import type { SyntheticInputEvent } from 'react-number-format/types/types'; import { debounce } from 'lodash'; import { StdFee } from '@cosmjs/stargate'; -import { validation } from '@dydxprotocol/v4-client'; +import { validation } from '@dydxprotocol/v4-client-js'; import { TransferInputField, TransferType } from '@/constants/abacus'; import { AlertType } from '@/constants/alerts'; import { ButtonShape, ButtonSize } from '@/constants/buttons'; import { ERROR_STRING_KEYS } from '@/constants/localization/errors'; import { STRING_KEYS } from '@/constants/localization'; -import { CHAIN_IDS } from '@/constants/networks'; +import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks'; import { NumberSign, QUANTUM_MULTIPLIER } from '@/constants/numbers'; import { DYDX_CHAIN_ASSET_COIN_DENOM, DYDX_CHAIN_INFO, DydxChainAsset } from '@/constants/wallets'; @@ -228,7 +228,7 @@ export const TransferForm = ({ const networkOptions = [ { - chainId: CHAIN_IDS[selectedNetwork], + chainId: CLIENT_NETWORK_CONFIGS[selectedNetwork].dydxChainId, label: ( {stringGetter({ key: STRING_KEYS.DYDX_CHAIN })} @@ -318,7 +318,7 @@ export const TransferForm = ({ /> {networkOptions.map(({ chainId, label }) => ( diff --git a/src/views/menus/NetworkSelectMenu.tsx b/src/views/menus/NetworkSelectMenu.tsx index c95b63f..45165d7 100644 --- a/src/views/menus/NetworkSelectMenu.tsx +++ b/src/views/menus/NetworkSelectMenu.tsx @@ -1,6 +1,7 @@ import styled, { type AnyStyledComponent } from 'styled-components'; import { useSelectedNetwork } from '@/hooks'; +import { layoutMixins } from '@/styles/layoutMixins'; import { headerMixins } from '@/styles/headerMixins'; import { DropdownSelectMenu } from '@/components/DropdownSelectMenu'; @@ -18,7 +19,6 @@ export const NetworkSelectMenu = ({ align, sideOffset }: StyleProps) => { return ( = {}; Styled.DropdownSelectMenu = styled(DropdownSelectMenu)` ${headerMixins.dropdownTrigger} + + & > span:first-of-type { + ${layoutMixins.textOverflow} + max-width: 5.625rem; + min-width: 0; + white-space: nowrap; + } `; diff --git a/src/views/menus/useNetworks.tsx b/src/views/menus/useNetworks.tsx index f96e46c..6fea12e 100644 --- a/src/views/menus/useNetworks.tsx +++ b/src/views/menus/useNetworks.tsx @@ -1,45 +1,13 @@ import { type MenuItem } from '@/constants/menus'; -import { type DydxNetwork, DydxV3Network, DydxV4Network } from '@/constants/networks'; +import { type DydxNetwork, NETWORK_ENDPOINTS } from '@/constants/networks'; +import { useStringGetter } from '@/hooks'; -export const useNetworks = (): MenuItem[] => - import.meta.env.MODE === 'production' - ? [ - { - value: DydxV4Network.V4Testnet2, - label: 'Testnet', - slotBefore: v4, - }, - ] - : [ - { - value: DydxV4Network.V4Mainnet, - label: 'Mainnet', - slotBefore: v4, - disabled: true, - }, - { - value: DydxV4Network.V4Staging, - label: 'Staging', - slotBefore: v4, - }, - { - value: DydxV4Network.V4Testnet2, - label: 'Testnet-2', - slotBefore: v4, - }, - { - value: DydxV4Network.V4Local, - label: 'Dev', - slotBefore: v4, - }, - { - value: DydxV3Network.V3Mainnet, - label: 'Mainnet', - slotBefore: v3, - }, - { - value: DydxV3Network.V3Testnet, - label: 'Testnet', - slotBefore: v3, - }, - ]; +export const useNetworks = (): MenuItem[] => { + const stringGetter = useStringGetter(); + + return NETWORK_ENDPOINTS.environments.map(({ stringKey, environment }) => ({ + key: environment, + label: stringGetter({ key: stringKey }), + value: environment, + })); +}; diff --git a/src/views/tables/FillsTable.tsx b/src/views/tables/FillsTable.tsx index 07683dc..6010499 100644 --- a/src/views/tables/FillsTable.tsx +++ b/src/views/tables/FillsTable.tsx @@ -1,7 +1,7 @@ import { useEffect } from 'react'; import styled, { type AnyStyledComponent, css } from 'styled-components'; import { shallowEqual, useDispatch, useSelector } from 'react-redux'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import type { ColumnSize } from '@react-types/table'; import { type Asset, type SubaccountFill } from '@/constants/abacus'; diff --git a/src/views/tables/LiveTrades.tsx b/src/views/tables/LiveTrades.tsx index e295733..d061a4d 100644 --- a/src/views/tables/LiveTrades.tsx +++ b/src/views/tables/LiveTrades.tsx @@ -1,7 +1,7 @@ import { useMemo } from 'react'; import styled, { type AnyStyledComponent, css, keyframes } from 'styled-components'; import { shallowEqual, useSelector } from 'react-redux'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { MarketTrade } from '@/constants/abacus'; import { STRING_KEYS } from '@/constants/localization'; diff --git a/src/views/tables/Orderbook.tsx b/src/views/tables/Orderbook.tsx index 0cdc8c0..a8140a4 100644 --- a/src/views/tables/Orderbook.tsx +++ b/src/views/tables/Orderbook.tsx @@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { shallowEqual, useSelector } from 'react-redux'; import styled, { type AnyStyledComponent, css, keyframes } from 'styled-components'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { type OrderbookLine, TradeInputField } from '@/constants/abacus'; import { STRING_KEYS } from '@/constants/localization'; diff --git a/src/views/tables/OrdersTable.tsx b/src/views/tables/OrdersTable.tsx index 755f8ec..1269844 100644 --- a/src/views/tables/OrdersTable.tsx +++ b/src/views/tables/OrdersTable.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react'; import styled, { css, type AnyStyledComponent } from 'styled-components'; import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { DateTime } from 'luxon'; -import { OrderSide } from '@dydxprotocol/v4-client'; +import { OrderSide } from '@dydxprotocol/v4-client-js'; import { ColumnSize } from '@react-types/table'; import type { Dispatch } from '@reduxjs/toolkit';