From dea36da7bfd50e26d5a2403ffab89c305db68241 Mon Sep 17 00:00:00 2001 From: Bill Date: Fri, 22 Sep 2023 14:21:42 -0700 Subject: [PATCH] Use abacus for simulate transactions and balance polling (#43) * Use abacus for simulate transactions and balance polling * address comment * use dydx gas token * address nits --- package.json | 2 +- pnpm-lock.yaml | 8 +- src/constants/abacus.ts | 5 + src/constants/wallets.ts | 10 +- src/hooks/useAccountBalance.ts | 14 +-- src/hooks/usePollNativeTokenBalance.ts | 31 ------ src/hooks/usePollUSDCBalance.ts | 30 ------ src/hooks/useSubaccount.tsx | 98 +++---------------- src/lib/abacus/dydxChainTransactions.ts | 93 ++++++++++++++++++ src/lib/abacus/stateNotification.ts | 12 +++ src/state/account.ts | 6 ++ src/state/accountSelectors.ts | 5 + .../AccountManagementForms/WithdrawForm.tsx | 10 +- src/views/forms/TransferForm.tsx | 68 +++---------- .../TransferForm/TransferButtonAndReceipt.tsx | 6 +- 15 files changed, 175 insertions(+), 223 deletions(-) delete mode 100644 src/hooks/usePollNativeTokenBalance.ts delete mode 100644 src/hooks/usePollUSDCBalance.ts diff --git a/package.json b/package.json index 09dcd54..93cc357 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "@cosmjs/proto-signing": "^0.31.0", "@cosmjs/stargate": "^0.31.0", "@cosmjs/tendermint-rpc": "^0.31.0", - "@dydxprotocol/v4-abacus": "^0.5.0", + "@dydxprotocol/v4-abacus": "^0.5.4", "@dydxprotocol/v4-client-js": "^0.36.1", "@dydxprotocol/v4-localization": "^0.1.11", "@ethersproject/providers": "^5.7.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 31b271b..6cf0633 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,8 +27,8 @@ dependencies: specifier: ^0.31.0 version: 0.31.0 '@dydxprotocol/v4-abacus': - specifier: ^0.5.0 - version: 0.5.0 + specifier: ^0.5.4 + version: 0.5.4 '@dydxprotocol/v4-client-js': specifier: ^0.36.1 version: 0.36.1 @@ -979,8 +979,8 @@ packages: resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==} dev: true - /@dydxprotocol/v4-abacus@0.5.0: - resolution: {integrity: sha512-K/aLJeOWzmToCn6p9vjBqfwn79/nuKxjZLSzaj1mKNxw25KBFh2q93njNbONFRA72zBElD0K+gw8J/skTpGg1Q==} + /@dydxprotocol/v4-abacus@0.5.4: + resolution: {integrity: sha512-LMwmyXCih2bBdLX3vO5OwbdGWg3oZ8WSGj+4nqr8tn/bn1qCSKdYdZZ9/U20Yir2rMAcoC0jmznMcBwthlSp/w==} dev: false /@dydxprotocol/v4-client-js@0.36.1: diff --git a/src/constants/abacus.ts b/src/constants/abacus.ts index 308578b..fa23da6 100644 --- a/src/constants/abacus.ts +++ b/src/constants/abacus.ts @@ -122,6 +122,7 @@ export const InputSelectionOption = Abacus.exchange.dydx.abacus.output.input.Sel // ------ Wallet ------ // export type Wallet = Abacus.exchange.dydx.abacus.output.Wallet; +export type AccountBalance = Abacus.exchange.dydx.abacus.output.AccountBalance; export type Subaccount = Abacus.exchange.dydx.abacus.output.Subaccount; export type SubaccountPosition = Abacus.exchange.dydx.abacus.output.SubaccountPosition; export type SubaccountOrder = Abacus.exchange.dydx.abacus.output.SubaccountOrder; @@ -188,6 +189,10 @@ export type HumanReadablePlaceOrderPayload = Abacus.exchange.dydx.abacus.state.manager.HumanReadablePlaceOrderPayload; export type HumanReadableCancelOrderPayload = Abacus.exchange.dydx.abacus.state.manager.HumanReadableCancelOrderPayload; +export type HumanReadableWithdrawPayload = + Abacus.exchange.dydx.abacus.state.manager.HumanReadableWithdrawPayload; +export type HumanReadableTransferPayload = + Abacus.exchange.dydx.abacus.state.manager.HumanReadableTransferPayload; // ------ Helpers ------ // export const AbacusHelper = Abacus.exchange.dydx.abacus.utils.AbacusHelper; diff --git a/src/constants/wallets.ts b/src/constants/wallets.ts index a205516..b9cb9d5 100644 --- a/src/constants/wallets.ts +++ b/src/constants/wallets.ts @@ -383,12 +383,18 @@ export const DYDX_CHAIN_INFO: Parameters[0] = { features: [], }; +// TODO: export this type from abacus instead export enum DydxChainAsset { - USDC = 'USDC', - DYDX = 'Dv4TNT', + USDC = 'usdc', + DYDX = 'dydx', } export const DYDX_CHAIN_ASSET_COIN_DENOM: Record = { [DydxChainAsset.USDC]: USDC_DENOM, [DydxChainAsset.DYDX]: DYDX_DENOM, }; + +export const DYDX_CHAIN_ASSET_TAGS: Record = { + [DydxChainAsset.USDC]: 'USDC', + [DydxChainAsset.DYDX]: 'Dv4TNT', +}; diff --git a/src/hooks/useAccountBalance.ts b/src/hooks/useAccountBalance.ts index c47d9bb..166e14f 100644 --- a/src/hooks/useAccountBalance.ts +++ b/src/hooks/useAccountBalance.ts @@ -1,10 +1,12 @@ import { useCallback } from 'react'; -import { useSelector } from 'react-redux'; +import { shallowEqual, useSelector } from 'react-redux'; import { useBalance } from 'wagmi'; import { StargateClient } from '@cosmjs/stargate'; import { useQuery } from 'react-query'; import { formatUnits } from 'viem'; +import { USDC_DENOM, DYDX_DENOM } from '@dydxprotocol/v4-client-js'; + import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks'; import { QUANTUM_MULTIPLIER } from '@/constants/numbers'; import { EvmAddress } from '@/constants/wallets'; @@ -12,11 +14,10 @@ import { EvmAddress } from '@/constants/wallets'; import { convertBech32Address } from '@/lib/addressUtils'; import { MustBigNumber } from '@/lib/numbers'; +import { getBalances } from '@/state/accountSelectors'; import { getSelectedNetwork } from '@/state/appSelectors'; import { useAccounts } from './useAccounts'; -import { usePollNativeTokenBalance } from './usePollNativeTokenBalance'; -import { usePollUSDCBalance } from './usePollUSDCBalance'; type UseAccountBalanceProps = { // Token Items @@ -50,6 +51,7 @@ export const useAccountBalance = ({ const { evmAddress, dydxAddress } = useAccounts(); const selectedNetwork = useSelector(getSelectedNetwork); + const balances = useSelector(getBalances, shallowEqual); const evmChainId = Number(CLIENT_NETWORK_CONFIGS[selectedNetwork].ethereumChainId); const evmQuery = useBalance({ @@ -92,12 +94,12 @@ export const useAccountBalance = ({ const { formatted: evmBalance } = evmQuery.data || {}; const balance = !assetSymbol ? '0' : isCosmosChain ? cosmosQuery.data : evmBalance; - const nativeTokenCoinBalance = usePollNativeTokenBalance({ dydxAddress }); + const nativeTokenCoinBalance = balances?.[DYDX_DENOM]; const nativeTokenBalance = MustBigNumber(nativeTokenCoinBalance?.amount) .div(QUANTUM_MULTIPLIER) .toNumber(); - - const usdcCoinBalance = usePollUSDCBalance({ dydxAddress }); + + const usdcCoinBalance = balances?.[USDC_DENOM]; const usdcBalance = MustBigNumber(usdcCoinBalance?.amount).div(QUANTUM_MULTIPLIER).toNumber(); return { diff --git a/src/hooks/usePollNativeTokenBalance.ts b/src/hooks/usePollNativeTokenBalance.ts deleted file mode 100644 index 9c91c91..0000000 --- a/src/hooks/usePollNativeTokenBalance.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { useQuery } from 'react-query'; - -import { useAccounts } from '@/hooks'; - -import { DydxAddress } from '@/constants/wallets'; -import { DYDX_DENOM } from '@dydxprotocol/v4-client-js'; - -const ACCOUNT_BALANCE_POLLING_INTERVAL = 60_000; - -export const usePollNativeTokenBalance = ({ - dydxAddress, - interval = ACCOUNT_BALANCE_POLLING_INTERVAL, -}: { - dydxAddress?: DydxAddress; - interval?: number; -}) => { - const { getAccountBalance } = useAccounts(); - - const { data } = useQuery({ - enabled: dydxAddress !== undefined, - queryKey: ['usePollNativeTokenBalance', { dydxAddress }], - queryFn: async () => { - if (!dydxAddress) return; - return await getAccountBalance({ dydxAddress, denom: DYDX_DENOM }); - }, - refetchInterval: interval, - staleTime: interval, - }); - - return data; -}; diff --git a/src/hooks/usePollUSDCBalance.ts b/src/hooks/usePollUSDCBalance.ts deleted file mode 100644 index 851c394..0000000 --- a/src/hooks/usePollUSDCBalance.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { useQuery } from 'react-query'; - -import { useAccounts } from '@/hooks'; - -import { DydxAddress } from '@/constants/wallets'; - -const ACCOUNT_BALANCE_POLLING_INTERVAL = 60_000; - -export const usePollUSDCBalance = ({ - dydxAddress, - interval = ACCOUNT_BALANCE_POLLING_INTERVAL, -}: { - dydxAddress?: DydxAddress; - interval?: number; -}) => { - const { getAccountBalance } = useAccounts(); - - const { data } = useQuery({ - enabled: dydxAddress !== undefined, - queryKey: ['usePollUSDCBalance', { dydxAddress }], - queryFn: async () => { - if (!dydxAddress) return; - return await getAccountBalance({ dydxAddress }); - }, - refetchInterval: interval, - staleTime: interval, - }); - - return data; -}; diff --git a/src/hooks/useSubaccount.tsx b/src/hooks/useSubaccount.tsx index f4748ed..5ab0a73 100644 --- a/src/hooks/useSubaccount.tsx +++ b/src/hooks/useSubaccount.tsx @@ -1,5 +1,5 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'; -import { useDispatch } from 'react-redux'; +import { shallowEqual, useSelector, useDispatch } from 'react-redux'; import type { Nullable } from '@dydxprotocol/v4-abacus'; import Long from 'long'; import type { IndexedTx } from '@cosmjs/stargate'; @@ -11,10 +11,10 @@ import { SubaccountClient, DYDX_DENOM, USDC_DENOM, - GAS_PRICE_DYDX_DENOM, } from '@dydxprotocol/v4-client-js'; import type { + AccountBalance, HumanReadablePlaceOrderPayload, ParsingError, SubAccountHistoricalPNLs, @@ -26,6 +26,7 @@ import { QUANTUM_MULTIPLIER } from '@/constants/numbers'; import { DydxAddress } from '@/constants/wallets'; import { setSubaccount, setHistoricalPnl, removeUncommittedOrderClientId } from '@/state/account'; +import { getBalances } from '@/state/accountSelectors'; import abacusStateManager from '@/lib/abacus'; import { track } from '@/lib/analytics'; @@ -34,7 +35,7 @@ import { log } from '@/lib/telemetry'; import { useAccounts } from './useAccounts'; import { useDydxClient } from './useDydxClient'; -import { usePollUSDCBalance } from './usePollUSDCBalance'; + type SubaccountContextType = ReturnType; const SubaccountContext = createContext({} as SubaccountContextType); @@ -70,10 +71,8 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo const { depositToSubaccount, withdrawFromSubaccount, - simulateWithdrawFromSubaccount, transferFromSubaccountToAddress, transferNativeToken, - simulateTransferNativeToken, sendSquidWithdrawFromSubaccount, } = useMemo( () => ({ @@ -95,31 +94,6 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo amount: number; }) => await compositeClient?.withdrawFromSubaccount(subaccountClient, amount), - simulateWithdrawFromSubaccount: async ({ - subaccountClient, - amount, - recipient, - }: { - subaccountClient: SubaccountClient; - amount: number; - recipient?: string; - }) => { - return await compositeClient?.simulate( - subaccountClient?.wallet, - () => - new Promise((resolve) => { - const msg = compositeClient?.withdrawFromSubaccountMessage( - subaccountClient, - amount, - recipient - ); - - resolve([msg]); - }), - undefined - ); - }, - transferFromSubaccountToAddress: async ({ subaccountClient, assetId = 0, @@ -170,31 +144,6 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo Method.BroadcastTxCommit ), - simulateTransferNativeToken: async ({ - subaccountClient, - amount, - recipient, - }: { - subaccountClient: SubaccountClient; - amount: number; - recipient: string; - }) => - await compositeClient?.simulate( - subaccountClient?.wallet, - () => - new Promise((resolve) => { - const msg = compositeClient?.validatorClient.post.composer.composeMsgSendToken( - subaccountClient.address, - recipient, - DYDX_DENOM, - Long.fromNumber(amount * QUANTUM_MULTIPLIER) - ); - - resolve([msg]); - }), - GAS_PRICE_DYDX_DENOM, - undefined - ), sendSquidWithdrawFromSubaccount: async ({ subaccountClient, amount, @@ -244,10 +193,10 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo // ------ Deposit/Withdraw Methods ------ // const depositFunds = useCallback( - async (balance?: Coin) => { + async (balance: AccountBalance) => { if (!localDydxWallet) return; - const amountAfterDust = MustBigNumber(balance?.amount) + const amountAfterDust = MustBigNumber(balance.amount) .minus(AMOUNT_RESERVED_FOR_GAS_USDC) // keep 0.1 USDC in user's wallet for gas .toString(); @@ -261,11 +210,14 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo [localDydxWallet, depositToSubaccount] ); - const balance = usePollUSDCBalance({ dydxAddress }); + const balances = useSelector(getBalances, shallowEqual); + const usdcCoinBalance = balances?.[USDC_DENOM]; useEffect(() => { - depositFunds(balance); - }, [balance]); + if (usdcCoinBalance) { + depositFunds(usdcCoinBalance); + } + }, [usdcCoinBalance]); const deposit = useCallback( async (amount: Long) => { @@ -304,30 +256,6 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo [subaccountClient, transferFromSubaccountToAddress, transferNativeToken] ); - const simulateTransfer = useCallback( - async (amount: number, recipient: string, coinDenom: string) => { - if (!subaccountClient) { - return; - } - - return await (coinDenom === USDC_DENOM - ? simulateWithdrawFromSubaccount - : simulateTransferNativeToken)({ subaccountClient, amount, recipient }); - }, - [subaccountClient, simulateWithdrawFromSubaccount, simulateTransferNativeToken] - ); - - const simulateWithdraw = useCallback( - async (amount: number) => { - if (!subaccountClient) { - return; - } - - return await simulateWithdrawFromSubaccount({ subaccountClient, amount }); - }, - [subaccountClient, simulateWithdrawFromSubaccount] - ); - const sendSquidWithdraw = useCallback( async (amount: number, payload: string) => { if (!subaccountClient) { @@ -437,9 +365,7 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo requestFaucetFunds, // Transfer Methods - simulateTransfer, transfer, - simulateWithdraw, sendSquidWithdraw, // Trading Methods diff --git a/src/lib/abacus/dydxChainTransactions.ts b/src/lib/abacus/dydxChainTransactions.ts index a616899..c84e05f 100644 --- a/src/lib/abacus/dydxChainTransactions.ts +++ b/src/lib/abacus/dydxChainTransactions.ts @@ -14,6 +14,8 @@ import { OrderSide, OrderTimeInForce, OrderExecution, + DYDX_DENOM, + GAS_PRICE_DYDX_DENOM, } from '@dydxprotocol/v4-client-js'; import { @@ -24,10 +26,13 @@ import { type TransactionTypes, type HumanReadablePlaceOrderPayload, type HumanReadableCancelOrderPayload, + type HumanReadableWithdrawPayload, + type HumanReadableTransferPayload, } from '@/constants/abacus'; import { DialogTypes } from '@/constants/dialogs'; import { UNCOMMITTED_ORDER_TIMEOUT_MS } from '@/constants/trade'; +import { QUANTUM_MULTIPLIER } from '@/constants/numbers'; import { RootStore } from '@/state/_store'; import { addUncommittedOrderClientId, removeUncommittedOrderClientId } from '@/state/account'; @@ -229,6 +234,76 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol { } } + async simulateWithdrawTransaction(params: HumanReadableWithdrawPayload): Promise { + if (!this.compositeClient || !this.localWallet) { + throw new Error('Missing compositeClient or localWallet'); + } + + const { subaccountNumber, amount } = params ?? {}; + const compositeClient = this.compositeClient; + const subaccountClient = new SubaccountClient(this.localWallet, subaccountNumber); + + try { + const tx = await compositeClient.simulate( + this.localWallet, + () => + new Promise((resolve) => { + const msg = compositeClient.withdrawFromSubaccountMessage(subaccountClient, amount); + + resolve([msg]); + }), + ); + + const parsedTx = this.parseToPrimitives(tx); + + return JSON.stringify(parsedTx); + } catch (error) { + log('DydxChainTransactions/simulateWithdrawTransaction', error); + + return JSON.stringify({ + error, + }); + } + } + + async simulateTransferNativeTokenTransaction(params: HumanReadableTransferPayload): Promise { + if (!this.compositeClient || !this.localWallet) { + throw new Error('Missing compositeClient or localWallet'); + } + + const { subaccountNumber, amount, recipient } = params ?? {}; + const compositeClient = this.compositeClient; + const subaccountClient = new SubaccountClient(this.localWallet, subaccountNumber); + + try { + const tx = await compositeClient.simulate( + this.localWallet, + () => + new Promise((resolve) => { + const msg = compositeClient?.validatorClient.post.composer.composeMsgSendToken( + subaccountClient.address, + recipient, + DYDX_DENOM, + Long.fromNumber(amount * QUANTUM_MULTIPLIER) + ); + + resolve([msg]); + }), + GAS_PRICE_DYDX_DENOM, + ); + + const parsedTx = this.parseToPrimitives(tx); + + return JSON.stringify(parsedTx); + } catch (error) { + log('DydxChainTransactions/simulateTransferNativeTokenTransaction', error); + + return JSON.stringify({ + error, + }); + } + } + async transaction( type: TransactionTypes, paramsInJson: Abacus.Nullable, @@ -248,6 +323,16 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol { callback(result); break; } + case TransactionType.simulateWithdraw: { + const result = await this.simulateWithdrawTransaction(params); + callback(result); + break; + } + case TransactionType.simulateTransferNativeToken: { + const result = await this.simulateTransferNativeTokenTransaction(params); + callback(result); + break; + } default: { break; } @@ -310,6 +395,14 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol { const parsedUserStats = this.parseToPrimitives(userStats); callback(JSON.stringify(parsedUserStats)); break; + case QueryType.GetAccountBalances: + if (!this.localWallet?.address) throw new Error('Missing localWallet'); + const accountBalances = await this.compositeClient?.validatorClient.get.getAccountBalances( + this.localWallet.address + ); + const parsedAccountBalances = this.parseToPrimitives(accountBalances); + callback(JSON.stringify(parsedAccountBalances)); + break; // Do not implement Transfers (yet) case QueryType.Transfers: default: diff --git a/src/lib/abacus/stateNotification.ts b/src/lib/abacus/stateNotification.ts index 3c0262f..879dc09 100644 --- a/src/lib/abacus/stateNotification.ts +++ b/src/lib/abacus/stateNotification.ts @@ -1,6 +1,7 @@ import { kollections } from '@dydxprotocol/v4-abacus'; import type { + AccountBalance, AbacusApiState, AbacusNotification, AbacusStateNotificationProtocol, @@ -18,6 +19,7 @@ import { Changes } from '@/constants/abacus'; import type { RootStore } from '@/state/_store'; import { + setBalances, setFills, setFundingPayments, setHistoricalPnl, @@ -72,6 +74,16 @@ class AbacusStateNotifier implements AbacusStateNotificationProtocol { ); } + if (changes.has(Changes.accountBalances)) { + if (updatedState.account?.balances) { + const balances: Record = {} + for (const { k, v } of updatedState.account.balances.toArray()) { + balances[k] = v; + } + dispatch(setBalances(balances)); + } + } + if (changes.has(Changes.configs)) { dispatch(setConfigs(updatedState.configs)); } diff --git a/src/state/account.ts b/src/state/account.ts index f234a16..467774f 100644 --- a/src/state/account.ts +++ b/src/state/account.ts @@ -1,6 +1,7 @@ import { createSlice, type PayloadAction } from '@reduxjs/toolkit'; import type { + AccountBalance, SubaccountFill, Nullable, Subaccount, @@ -35,6 +36,7 @@ export type AccountState = { wallet?: Nullable; walletType?: WalletType; historicalPnlPeriod?: HistoricalPnlPeriods; + balances?: Record; }; const initialState: AccountState = { @@ -149,6 +151,9 @@ export const accountSlice = createSlice({ viewedOrders: (state) => { state.hasUnseenOrderUpdates = false; }, + setBalances: (state, action: PayloadAction>) => { + state.balances = action.payload; + }, addUncommittedOrderClientId: (state, action: PayloadAction) => { state.uncommittedOrderClientIds.push(action.payload); }, @@ -173,6 +178,7 @@ export const { setWallet, viewedFills, viewedOrders, + setBalances, addUncommittedOrderClientId, removeUncommittedOrderClientId, } = accountSlice.actions; diff --git a/src/state/accountSelectors.ts b/src/state/accountSelectors.ts index a03faeb..8054dc3 100644 --- a/src/state/accountSelectors.ts +++ b/src/state/accountSelectors.ts @@ -332,3 +332,8 @@ export const getUserStats = (state: RootState) => ({ makerVolume30D: state.account?.wallet?.user?.makerVolume30D, takerVolume30D: state.account?.wallet?.user?.takerVolume30D, }); + +/** + * @returns user wallet balances + */ +export const getBalances = (state: RootState) => state.account?.balances; diff --git a/src/views/forms/AccountManagementForms/WithdrawForm.tsx b/src/views/forms/AccountManagementForms/WithdrawForm.tsx index b50e1f1..02ce647 100644 --- a/src/views/forms/AccountManagementForms/WithdrawForm.tsx +++ b/src/views/forms/AccountManagementForms/WithdrawForm.tsx @@ -43,7 +43,7 @@ export const WithdrawForm = () => { const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(false); - const { simulateWithdraw, sendSquidWithdraw } = useSubaccount(); + const { sendSquidWithdraw } = useSubaccount(); const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {}; // User input @@ -97,16 +97,10 @@ export const WithdrawForm = () => { field: TransferInputField.usdcSize, }); } else { - const stdFee = await simulateWithdraw(parseFloat(debouncedAmount)); - const amount = - parseFloat(debouncedAmount) - - parseFloat(stdFee?.amount[0]?.amount || '0') / QUANTUM_MULTIPLIER; - abacusStateManager.setTransferValue({ - value: amount.toString(), + value: debouncedAmount, field: TransferInputField.usdcSize, }); - setError(null); } } catch (error) { diff --git a/src/views/forms/TransferForm.tsx b/src/views/forms/TransferForm.tsx index 6a855c5..f314ef4 100644 --- a/src/views/forms/TransferForm.tsx +++ b/src/views/forms/TransferForm.tsx @@ -13,7 +13,7 @@ import { ButtonShape, ButtonSize } from '@/constants/buttons'; import { STRING_KEYS } from '@/constants/localization'; import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks'; import { NumberSign, QUANTUM_MULTIPLIER } from '@/constants/numbers'; -import { DYDX_CHAIN_ASSET_COIN_DENOM, DydxChainAsset } from '@/constants/wallets'; +import { DYDX_CHAIN_ASSET_COIN_DENOM, DYDX_CHAIN_ASSET_TAGS, DydxChainAsset } from '@/constants/wallets'; import { useAccountBalance, @@ -52,28 +52,6 @@ type TransferFormProps = { className?: string; }; -const debouncedEstimateFee = debounce( - async ({ amount, recipientAddress, asset, setFees, simulateTransfer }) => { - if (!amount || !recipientAddress) { - return; - } - - try { - const coinDenom = DYDX_CHAIN_ASSET_COIN_DENOM[asset as DydxChainAsset]; - const stdFee: StdFee = await simulateTransfer(amount, recipientAddress, coinDenom); - - const fee = stdFee?.amount.find((coin) => coin.denom === coinDenom)?.amount; - const feeAmount = MustBigNumber(fee).div(QUANTUM_MULTIPLIER).toNumber(); - - setFees(feeAmount); - } catch (error) { - console.error('TransferForm > : debouncedEstimateFee > ', error); - } - }, - 1000, - { trailing: true } -); - export const TransferForm = ({ selectedAsset = DydxChainAsset.DYDX, onDone, @@ -82,8 +60,8 @@ export const TransferForm = ({ const stringGetter = useStringGetter(); const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {}; const { dydxAddress } = useAccounts(); - const { address: recipientAddress, size } = useSelector(getTransferInputs, shallowEqual) || {}; - const { transfer, simulateTransfer } = useSubaccount(); + const { address: recipientAddress, size, fee } = useSelector(getTransferInputs, shallowEqual) || {}; + const { transfer } = useSubaccount(); const { nativeTokenBalance, usdcBalance } = useAccountBalance(); const { selectedNetwork } = useSelectedNetwork(); @@ -93,7 +71,6 @@ export const TransferForm = ({ // Form states const [error, setError] = useState(); const [isLoading, setIsLoading] = useState(false); - const [fees, setFees] = useState(); const balance = asset === DydxChainAsset.USDC ? freeCollateral?.current : nativeTokenBalance; const newBalance = @@ -104,7 +81,7 @@ export const TransferForm = ({ .toNumber(); const amount = asset === DydxChainAsset.USDC ? size?.usdcSize : size?.size; - const showNotEnoughGasWarning = fees && asset === DydxChainAsset.USDC && usdcBalance < fees; + const showNotEnoughGasWarning = fee && asset === DydxChainAsset.USDC && usdcBalance < fee; // BN const amountBN = MustBigNumber(amount); @@ -134,34 +111,21 @@ export const TransferForm = ({ useEffect(() => { setError(undefined); - debouncedEstimateFee.cancel(); - - if (isAmountValid && isAddressValid) { - debouncedEstimateFee({ - amount, - recipientAddress, - asset, - setFees, - simulateTransfer, - }); - } else { - setFees(undefined); - } - }, [asset, amount, recipientAddress]); - - useEffect(() => { - setError(undefined); + abacusStateManager.setTransferValue({ + value: asset, + field: TransferInputField.token, + }); }, [asset]); const onTransfer = async () => { - if (!isAmountValid || !isAddressValid || !fees) return; + if (!isAmountValid || !isAddressValid || !fee) return; setIsLoading(true); setError(undefined); try { // Subtract fees from amount if sending native tokens const amountToTransfer = ( - asset === DydxChainAsset.DYDX ? amountBN.minus(fees) : amountBN + asset === DydxChainAsset.DYDX ? amountBN.minus(fee) : amountBN ).toNumber(); const txResponse = await transfer( @@ -212,7 +176,7 @@ export const TransferForm = ({ value: DydxChainAsset.USDC, label: ( - USDC + {DYDX_CHAIN_ASSET_TAGS[DydxChainAsset.USDC]} ), }, @@ -221,7 +185,7 @@ export const TransferForm = ({ label: ( {/* */} - Dv4TNT + {DYDX_CHAIN_ASSET_TAGS[DydxChainAsset.DYDX]} ), }, @@ -243,7 +207,7 @@ export const TransferForm = ({ key: 'amount', label: ( - {stringGetter({ key: STRING_KEYS.AVAILABLE })} {asset} + {stringGetter({ key: STRING_KEYS.AVAILABLE })} {DYDX_CHAIN_ASSET_TAGS[asset]} ), value: ( @@ -375,9 +339,9 @@ export const TransferForm = ({ diff --git a/src/views/forms/TransferForm/TransferButtonAndReceipt.tsx b/src/views/forms/TransferForm/TransferButtonAndReceipt.tsx index 888f316..a9dd149 100644 --- a/src/views/forms/TransferForm/TransferButtonAndReceipt.tsx +++ b/src/views/forms/TransferForm/TransferButtonAndReceipt.tsx @@ -3,7 +3,7 @@ import { shallowEqual, useSelector } from 'react-redux'; import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons'; import { STRING_KEYS } from '@/constants/localization'; import { NumberSign } from '@/constants/numbers'; -import { DydxChainAsset } from '@/constants/wallets'; +import { DYDX_CHAIN_ASSET_TAGS, DydxChainAsset } from '@/constants/wallets'; import { useAccountBalance, useStringGetter } from '@/hooks'; @@ -60,7 +60,7 @@ export const TransferButtonAndReceipt = ({ key: 'fees', label: ( - {stringGetter({ key: STRING_KEYS.FEES })} {selectedAsset} + {stringGetter({ key: STRING_KEYS.FEES })} {DYDX_CHAIN_ASSET_TAGS[selectedAsset]} ), value: , @@ -69,7 +69,7 @@ export const TransferButtonAndReceipt = ({ key: 'balance', label: ( - {stringGetter({ key: STRING_KEYS.BALANCE })} {selectedAsset} + {stringGetter({ key: STRING_KEYS.BALANCE })} {DYDX_CHAIN_ASSET_TAGS[selectedAsset]} ), value: (