From 0efbb17a80e120c11fee4c311004ff1d0766193d Mon Sep 17 00:00:00 2001 From: Peiman <25097709+Rickk137@users.noreply.github.com> Date: Thu, 23 May 2024 21:34:41 +0330 Subject: [PATCH] fix: withdrawal issue (#284) --- .../useCollateralPriceUpdates.ts | 5 +- .../useLiquidityPositions.ts | 4 +- .../useWithdrawBaseAndromeda.tsx | 105 ++++++++---------- liquidity/lib/withERC7412/withERC7412.ts | 3 +- .../WithdrawModal/WithdrawModal.tsx | 25 ++--- 5 files changed, 68 insertions(+), 74 deletions(-) diff --git a/liquidity/lib/useCollateralPriceUpdates/useCollateralPriceUpdates.ts b/liquidity/lib/useCollateralPriceUpdates/useCollateralPriceUpdates.ts index 1f510bbbd..5537706da 100644 --- a/liquidity/lib/useCollateralPriceUpdates/useCollateralPriceUpdates.ts +++ b/liquidity/lib/useCollateralPriceUpdates/useCollateralPriceUpdates.ts @@ -90,7 +90,7 @@ export const useCollateralPriceUpdates = () => { const { activeWallet } = useWallet(); return useQuery({ - queryKey: [`${network?.id}-${network?.preset}`, 'price-updates'], + queryKey: [`${network?.id}-${network?.preset}`, 'price-updates', activeWallet?.address], enabled: isBaseAndromeda(network?.id, network?.preset), queryFn: async () => { const stalenessTolerance = 3300; @@ -143,8 +143,8 @@ export const useCollateralPriceUpdates = () => { if (outdatedPriceIds.length) { return { - from: activeWallet?.address, ...(await getPriceUpdates(outdatedPriceIds, stalenessTolerance, network)), + from: activeWallet?.address, }; } @@ -153,5 +153,6 @@ export const useCollateralPriceUpdates = () => { return null; } }, + refetchInterval: 60000, }); }; diff --git a/liquidity/lib/useLiquidityPositions/useLiquidityPositions.ts b/liquidity/lib/useLiquidityPositions/useLiquidityPositions.ts index 195921800..a94575af1 100644 --- a/liquidity/lib/useLiquidityPositions/useLiquidityPositions.ts +++ b/liquidity/lib/useLiquidityPositions/useLiquidityPositions.ts @@ -11,7 +11,7 @@ import { erc7412Call } from '@snx-v3/withERC7412'; import { keyBy, stringToHash } from '@snx-v3/tsHelpers'; import { useAllCollateralPriceIds } from '@snx-v3/useAllCollateralPriceIds'; import { fetchPriceUpdates, priceUpdatesToPopulatedTx } from '@snx-v3/fetchPythPrices'; -import { useCollateralPriceUpdates } from '../useCollateralPriceUpdates'; +import { useAllCollateralPriceUpdates } from '../useCollateralPriceUpdates'; export type LiquidityPositionType = { id: `${string}-${string}`; @@ -45,7 +45,7 @@ export const useLiquidityPositions = ({ accountId }: { accountId?: string }) => const { data: collateralTypes } = useCollateralTypes(); const { data: collateralPriceUpdates } = useAllCollateralPriceIds(); const { data: priceUpdateTx, isLoading: collateralPriceUpdatesIsLoading } = - useCollateralPriceUpdates(); + useAllCollateralPriceUpdates(); const { network } = useNetwork(); const provider = useProviderForChain(network!); diff --git a/liquidity/lib/useWithdrawBaseAndromeda/useWithdrawBaseAndromeda.tsx b/liquidity/lib/useWithdrawBaseAndromeda/useWithdrawBaseAndromeda.tsx index 404083367..aaaf16d9e 100644 --- a/liquidity/lib/useWithdrawBaseAndromeda/useWithdrawBaseAndromeda.tsx +++ b/liquidity/lib/useWithdrawBaseAndromeda/useWithdrawBaseAndromeda.tsx @@ -1,4 +1,4 @@ -import { useMemo, useReducer } from 'react'; +import { useReducer } from 'react'; import { useCoreProxy } from '@snx-v3/useCoreProxy'; import { useMutation } from '@tanstack/react-query'; import { useNetwork, useProvider, useSigner } from '@snx-v3/useBlockchain'; @@ -15,6 +15,7 @@ import { useUSDProxy } from '@snx-v3/useUSDProxy'; import { Wei } from '@synthetixio/wei'; import { useCollateralPriceUpdates } from '@snx-v3/useCollateralPriceUpdates'; import { useGetUSDTokens } from '@snx-v3/useGetUSDTokens'; +import { ZEROWEI } from '../../ui/src/utils/constants'; export const useWithdrawBaseAndromeda = ({ accountId, @@ -39,68 +40,55 @@ export const useWithdrawBaseAndromeda = ({ const signer = useSigner(); const provider = useProvider(); - const isSUSDCEnough = amountToWithdraw.lte(sUSDCCollateral); - const howMuchSNXUSD = amountToWithdraw.sub(sUSDCCollateral).sub(snxUSDCollateral).eq(0) - ? snxUSDCollateral - : snxUSDCollateral.sub(amountToWithdraw); - - const amount = useMemo( - () => snxUSDCollateral.add(sUSDCCollateral), - [snxUSDCollateral, sUSDCCollateral] - ); - const mutation = useMutation({ mutationFn: async () => { if (!signer || !network || !provider) throw new Error('No signer or network'); + if (!(CoreProxy && SpotProxy && accountId && usdTokens?.sUSD && usdTokens.snxUSD)) return; - if ( - !( - CoreProxy && - SpotProxy && - amount.gt(0) && - accountId && - usdTokens?.sUSD && - usdTokens.snxUSD - ) - ) + const total = snxUSDCollateral.add(sUSDCCollateral); + + if (total.lt(amountToWithdraw)) { return; + } + + const sUSDCAmount = amountToWithdraw.gt(sUSDCCollateral) ? sUSDCCollateral : amountToWithdraw; + const snxUSDAmount = amountToWithdraw.sub(sUSDCAmount).gt(0) + ? amountToWithdraw.sub(sUSDCAmount) + : ZEROWEI; try { dispatch({ type: 'prompting' }); const gasPricesPromised = getGasPrice({ provider }); - const withdraw_sUSDC = sUSDCCollateral.gt(0) + const withdraw_sUSDC = sUSDCAmount.gt(0) ? CoreProxy.populateTransaction.withdraw( BigNumber.from(accountId), usdTokens?.sUSD, - isSUSDCEnough ? amountToWithdraw.toBN() : sUSDCCollateral.toBN() + sUSDCAmount.toBN() ) : undefined; - const withdraw_sUSD = - snxUSDCollateral.gt(0) && !isSUSDCEnough - ? CoreProxy.populateTransaction.withdraw( - BigNumber.from(accountId), - usdTokens?.snxUSD, - howMuchSNXUSD.toBN() - ) - : undefined; - - const sUSDCApproval = - snxUSDCollateral.gt(0) && !isSUSDCEnough - ? UsdProxy?.populateTransaction.approve(SpotProxy.address, howMuchSNXUSD.toBN()) - : undefined; - - const buy_SUSD = - snxUSDCollateral.gt(0) && !isSUSDCEnough - ? SpotProxy.populateTransaction.buy( - USDC_BASE_MARKET, - howMuchSNXUSD.toBN(), - 0, - constants.AddressZero - ) - : undefined; + const withdraw_snxUSD = snxUSDAmount.gt(0) + ? CoreProxy.populateTransaction.withdraw( + BigNumber.from(accountId), + usdTokens?.snxUSD, + snxUSDAmount.toBN() + ) + : undefined; + + const snxUSDApproval = snxUSDAmount.gt(0) + ? UsdProxy?.populateTransaction.approve(SpotProxy.address, snxUSDAmount.toBN()) + : undefined; + + const buy_sUSDC = snxUSDAmount.gt(0) + ? SpotProxy.populateTransaction.buy( + USDC_BASE_MARKET, + snxUSDAmount.toBN(), + 0, + constants.AddressZero + ) + : undefined; const unwrapTxnPromised = SpotProxy.populateTransaction.unwrap( USDC_BASE_MARKET, @@ -114,24 +102,24 @@ export const useWithdrawBaseAndromeda = ({ const [ gasPrices, withdraw_sUSDC_Txn, - withdraw_SUSD_Txn, - sUSDCApproval_Txn, - buy_SUSD_Txn, + withdraw_snxUSD_Txn, + snxUSDCApproval_Txn, + buy_sUSDC_Txn, unwrapTxn, ] = await Promise.all([ gasPricesPromised, withdraw_sUSDC, - withdraw_sUSD, - sUSDCApproval, - buy_SUSD, + withdraw_snxUSD, + snxUSDApproval, + buy_sUSDC, unwrapTxnPromised, ]); const allCalls = [ withdraw_sUSDC_Txn, - withdraw_SUSD_Txn, - sUSDCApproval_Txn, - buy_SUSD_Txn, + withdraw_snxUSD_Txn, + snxUSDCApproval_Txn, + buy_sUSDC_Txn, unwrapTxn, ].filter(notNil); @@ -139,7 +127,12 @@ export const useWithdrawBaseAndromeda = ({ allCalls.unshift(priceUpdateTx as any); } - const erc7412Tx = await withERC7412(network, allCalls, 'useWithdraw', CoreProxy.interface); + const erc7412Tx = await withERC7412( + network, + [...allCalls], + 'useWithdrawBase', + CoreProxy.interface + ); const gasOptionsForTransaction = formatGasPriceForTransaction({ gasLimit: erc7412Tx.gasLimit, diff --git a/liquidity/lib/withERC7412/withERC7412.ts b/liquidity/lib/withERC7412/withERC7412.ts index b9ace46c7..6907591d8 100644 --- a/liquidity/lib/withERC7412/withERC7412.ts +++ b/liquidity/lib/withERC7412/withERC7412.ts @@ -186,7 +186,7 @@ export const withERC7412 = async ( ): Promise => { const initialMulticallLength = Array.isArray(tx) ? tx.length : 1; // eslint-disable-next-line prefer-const - let multicallCalls = [tx].flat(); // Use let to communicate that we mutate this array + let multicallCalls = [...[tx].flat()]; // Use let to communicate that we mutate this array if (multicallCalls.some((x) => !x.to)) { throw Error(`Make sure all txs have 'to' field set`); @@ -305,6 +305,7 @@ export async function erc7412Call( ); const reqs = [txRequests].flat(); + for (const txRequest of reqs) { txRequest.from = getDefaultFromAddress(network.name); // Reads can always use WETH } diff --git a/liquidity/ui/src/components/WithdrawModal/WithdrawModal.tsx b/liquidity/ui/src/components/WithdrawModal/WithdrawModal.tsx index 34f03f806..3e4a0e88d 100644 --- a/liquidity/ui/src/components/WithdrawModal/WithdrawModal.tsx +++ b/liquidity/ui/src/components/WithdrawModal/WithdrawModal.tsx @@ -14,7 +14,7 @@ import { Text, } from '@chakra-ui/react'; import Wei from '@synthetixio/wei'; -import { useState } from 'react'; +import { useCallback, useState } from 'react'; import { useWithdraw } from '@snx-v3/useWithdraw'; import { useWithdrawBaseAndromeda } from '@snx-v3/useWithdrawBaseAndromeda'; import { isBaseAndromeda } from '@snx-v3/isBaseAndromeda'; @@ -51,12 +51,6 @@ export function WithdrawModal({ isOpen, onClose }: { isOpen: boolean; onClose: ( const { data: collateralPrices } = useCollateralPrices(); - const { mutation: withdrawMain } = useWithdraw({ - amount, - accountId, - collateralTypeAddress: selectedCollateralType, - }); - const activeCollateral = isBase ? accountCollaterals?.reduce((cur, prev, index) => { //ignore the first iteration cause we are starting witht the first index of the @@ -69,7 +63,13 @@ export function WithdrawModal({ isOpen, onClose }: { isOpen: boolean; onClose: ( }, accountCollaterals[0]) : accountCollaterals?.find((collateral) => collateral.tokenAddress === selectedCollateralType); - const { mutation: withdrawAndromeda } = useWithdrawBaseAndromeda({ + const { mutation: withdrawMain, isLoading } = useWithdraw({ + amount, + accountId, + collateralTypeAddress: selectedCollateralType, + }); + + const { mutation: withdrawAndromeda, isLoading: isLoadingAndromeda } = useWithdrawBaseAndromeda({ accountId, sUSDCCollateral: accountCollaterals && accountCollaterals[0] @@ -82,14 +82,14 @@ export function WithdrawModal({ isOpen, onClose }: { isOpen: boolean; onClose: ( amountToWithdraw: amount, }); - const withdraw = async () => { + const withdraw = useCallback(async () => { if (!isBaseAndromeda(network?.id, network?.preset)) { await withdrawMain.mutateAsync(); } else { await withdrawAndromeda.mutateAsync(); } queryClient.clear(); - }; + }, [network?.id, network?.preset, queryClient, withdrawAndromeda, withdrawMain]); // Replace out sUSDC with USDC for Andromeda const collateralTypesHydated = collateralTypes?.map((type) => { @@ -286,9 +286,8 @@ export function WithdrawModal({ isOpen, onClose }: { isOpen: boolean; onClose: ( isDisabled={amount.eq(0)} mt={6} mb="2" - onClick={() => { - withdraw(); - }} + onClick={withdraw} + isLoading={isLoadingAndromeda || isLoading} > {amount.eq(0) ? 'Enter Amount' : 'Withdraw'}