import { MaxUint256 } from '@ethersproject/constants' ; import { TransactionResponse } from '@ethersproject/providers' ; import { Trade , TokenAmount , CurrencyAmount , ETHER } from '@pancakeswap-libs/sdk' ; import { useCallback , useMemo } from 'react' ; import { ROUTER_ADDRESS } from '../constants' ; import { useTokenAllowance } from '../data/Allowances' ; import { Field } from '../state/swap/actions' ; import { useTransactionAdder , useHasPendingApproval } from '../state/transactions/hooks' ; import { computeSlippageAdjustedAmounts } from '../utils/prices' ; import { calculateGasMargin } from '../utils' ; import { useTokenContract } from './useContract' ; import { useActiveWeb3React } from './index' ; export enum ApprovalState { UNKNOWN , NOT_APPROVED , PENDING , APPROVED } export function useApproveCallback ( amountToApprove ? , spender ? ) { const { account } = useActiveWeb3React ( ) ; const token = amountToApprove instanceof TokenAmount ? amountToApprove . token : undefined ; const currentAllowance = useTokenAllowance ( token , account ?? undefined , spender ) ; const pendingApproval = useHasPendingApproval ( token ?. address , spender ) ; const approvalState = useMemo ( ( ) => { if ( ! amountToApprove || ! spender ) return ApprovalState . UNKNOWN ; if ( amountToApprove . currency === ETHER ) return ApprovalState . APPROVED ; if ( ! currentAllowance ) return ApprovalState . UNKNOWN ; return currentAllowance . lessThan ( amountToApprove ) ? pendingApproval ? ApprovalState . PENDING : ApprovalState . NOT_APPROVED : ApprovalState . APPROVED ; } , [ amountToApprove , currentAllowance , pendingApproval , spender ] ) ; const tokenContract = useTokenContract ( token ?. address ) ; const addTransaction = useTransactionAdder ( ) ; const approve = useCallback ( async ( ) : Promise < void > => { if ( approvalState !== ApprovalState . NOT_APPROVED ) { console . error ( 'approve was called unnecessarily' ) ; return ; } if ( ! token ) { console . error ( 'no token' ) ; return ; } if ( ! tokenContract ) { console . error ( 'tokenContract is null' ) ; return ; } if ( ! amountToApprove ) { console . error ( 'missing amount to approve' ) ; return ; } if ( ! spender ) { console . error ( 'no spender' ) ; return ; } let useExact = false ; const estimatedGas = await tokenContract . estimateGas . approve ( spender , MaxUint256 ) . catch ( ( ) => { useExact = true ; return tokenContract . estimateGas . approve ( spender , amountToApprove . raw . toString ( ) ) ; } ) ; return tokenContract . approve ( spender , useExact ? amountToApprove . raw . toString ( ) : MaxUint256 , { gasLimit : calculateGasMargin ( estimatedGas ) , } ) . then ( ( response ) => { addTransaction ( response , { summary : `Approve ${ amountToApprove . currency . symbol }` , approval : { tokenAddress : token . address , spender } , } ) ; } ) . catch ( ( error ) => { console . error ( 'Failed to approve token' , error ) ; throw error ; } ) ; } , [ approvalState , token , tokenContract , amountToApprove , spender , addTransaction ] ) ; return [ approvalState , approve ] ; } export function useApproveCallbackFromTrade ( trade ? , allowedSlippage = 0 ) { const amountToApprove = useMemo ( ( ) => ( trade ? computeSlippageAdjustedAmounts ( trade , allowedSlippage ) [ Field . INPUT ] : undefined ) , [ trade , allowedSlippage ] ) ; return useApproveCallback ( amountToApprove , ROUTER_ADDRESS ) ; }