/ src / components / transactions / StakingMigrate / StakingMigrateActions.tsx
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  };