StakingMigrateActions.tsx
1 import { 2 ChainId, 3 gasLimitRecommendations, 4 ProtocolAction, 5 valueToWei, 6 } from '@aave/contract-helpers'; 7 import { AaveSafetyModule } from '@bgd-labs/aave-address-book'; 8 import { Trans } from '@lingui/macro'; 9 import { useQueryClient } from '@tanstack/react-query'; 10 import { PopulatedTransaction } from 'ethers'; 11 import { useEffect, useState } from 'react'; 12 import { SignedParams, useApprovalTx } from 'src/hooks/useApprovalTx'; 13 import { useApprovedAmount } from 'src/hooks/useApprovedAmount'; 14 import { useModalContext } from 'src/hooks/useModal'; 15 import { useWeb3Context } from 'src/libs/hooks/useWeb3Context'; 16 import { useRootStore } from 'src/store/root'; 17 import { ApprovalMethod } from 'src/store/walletSlice'; 18 import { getErrorTextFromError, TxAction } from 'src/ui-config/errorMapping'; 19 import { queryKeysFactory } from 'src/ui-config/queries'; 20 import { useSharedDependencies } from 'src/ui-config/SharedDependenciesProvider'; 21 import { useShallow } from 'zustand/shallow'; 22 23 import { TxActionsWrapper } from '../TxActionsWrapper'; 24 import { APPROVAL_GAS_LIMIT, checkRequiresApproval } from '../utils'; 25 26 export const StakingMigrateActions = ({ 27 amountToMigrate, 28 minOutWithSlippage, 29 }: { 30 amountToMigrate: string; 31 minOutWithSlippage: string; 32 }) => { 33 const { stkAbptMigrationService } = useSharedDependencies(); 34 const [ 35 walletApprovalMethodPreference, 36 currentMarketData, 37 user, 38 estimateGasLimit, 39 addTransaction, 40 ] = useRootStore( 41 useShallow((store) => [ 42 store.walletApprovalMethodPreference, 43 store.currentMarketData, 44 store.account, 45 store.estimateGasLimit, 46 store.addTransaction, 47 ]) 48 ); 49 const { sendTx } = useWeb3Context(); 50 const queryClient = useQueryClient(); 51 const [signatureParams, setSignatureParams] = useState<SignedParams | undefined>(); 52 const { 53 approvalTxState, 54 mainTxState, 55 loadingTxns, 56 setApprovalTxState, 57 setMainTxState, 58 setLoadingTxns, 59 setTxError, 60 setGasLimit, 61 } = useModalContext(); 62 const usePermit = walletApprovalMethodPreference === ApprovalMethod.PERMIT; 63 64 const { 65 data: approvedAmount, 66 refetch: fetchApprovedAmount, 67 isFetching: fetchingApprovedAmount, 68 isFetchedAfterMount, 69 } = useApprovedAmount({ 70 chainId: currentMarketData.chainId, 71 token: AaveSafetyModule.STK_ABPT, 72 spender: AaveSafetyModule.STK_ABPT_STK_AAVE_WSTETH_BPTV2_MIGRATOR, 73 }); 74 75 setLoadingTxns(fetchingApprovedAmount); 76 77 const requiresApproval = 78 Number(amountToMigrate) !== 0 && 79 checkRequiresApproval({ 80 approvedAmount: approvedAmount ? approvedAmount.toString() : '0', 81 amount: amountToMigrate, 82 signedAmount: signatureParams ? signatureParams.amount : '0', 83 }); 84 85 if (requiresApproval && approvalTxState?.success) { 86 // There was a successful approval tx, but the approval amount is not enough. 87 // Clear the state to prompt for another approval. 88 setApprovalTxState({}); 89 } 90 91 useEffect(() => { 92 if (!isFetchedAfterMount) { 93 fetchApprovedAmount(); 94 } 95 }, [fetchApprovedAmount, isFetchedAfterMount]); 96 97 useEffect(() => { 98 let migrateGasLimit = 0; 99 migrateGasLimit = Number(gasLimitRecommendations[ProtocolAction.migrateABPT].recommended); 100 if (requiresApproval && !approvalTxState.success) { 101 migrateGasLimit += Number(APPROVAL_GAS_LIMIT); 102 } 103 setGasLimit(migrateGasLimit.toString()); 104 }, [requiresApproval, approvalTxState, setGasLimit]); 105 106 const { approval } = useApprovalTx({ 107 usePermit, 108 approvedAmount: { 109 user, 110 token: AaveSafetyModule.STK_ABPT, 111 amount: approvedAmount?.toString() || '0', 112 spender: AaveSafetyModule.STK_ABPT_STK_AAVE_WSTETH_BPTV2_MIGRATOR, 113 }, 114 requiresApproval, 115 assetAddress: AaveSafetyModule.STK_ABPT, 116 symbol: 'stkABPT', 117 decimals: 18, 118 signatureAmount: amountToMigrate, 119 onApprovalTxConfirmed: fetchApprovedAmount, 120 onSignTxCompleted: (signedParams) => setSignatureParams(signedParams), 121 }); 122 123 const action = async () => { 124 try { 125 setMainTxState({ ...mainTxState, loading: true }); 126 const amount = valueToWei(amountToMigrate, 18); 127 let txData: PopulatedTransaction; 128 129 if (usePermit && signatureParams) { 130 txData = await stkAbptMigrationService.migrateWithPermit( 131 user, 132 amount, 133 minOutWithSlippage, 134 signatureParams.signature, 135 signatureParams.deadline 136 ); 137 } else { 138 txData = await stkAbptMigrationService.migrate(user, amount, minOutWithSlippage); 139 } 140 141 txData = await estimateGasLimit(txData, ChainId.mainnet); 142 const response = await sendTx(txData); 143 await response.wait(1); 144 145 queryClient.invalidateQueries({ queryKey: queryKeysFactory.staking }); 146 147 setMainTxState({ 148 txHash: response.hash, 149 loading: false, 150 success: true, 151 }); 152 addTransaction(response.hash, { 153 action: 'todo', 154 txState: 'success', 155 asset: AaveSafetyModule.STK_ABPT, 156 amount: amountToMigrate, 157 assetName: 'stkABPT', 158 }); 159 } catch (e) { 160 const parsedError = getErrorTextFromError(e, TxAction.GAS_ESTIMATION, false); 161 setTxError(parsedError); 162 setMainTxState({ 163 txHash: undefined, 164 loading: false, 165 }); 166 } 167 }; 168 169 return ( 170 <TxActionsWrapper 171 requiresApproval={requiresApproval} 172 blocked={false} 173 preparingTransactions={loadingTxns} 174 handleAction={action} 175 actionText={<Trans>Migrate</Trans>} 176 actionInProgressText={<Trans>Migrating</Trans>} 177 mainTxState={mainTxState} 178 isWrongNetwork={false} 179 amount={amountToMigrate} 180 requiresAmount 181 handleApproval={approval} 182 approvalTxState={approvalTxState} 183 tryPermit 184 /> 185 ); 186 };