import type { ExchangeProxy } from '@masknet/web3-contracts/types/ExchangeProxy' ; import type { PayableTx } from '@masknet/web3-contracts/types/types' ; import { EthereumTokenType , GasOptionConfig , TransactionEventType , TransactionState , TransactionStateType , useAccount , useTraderConstants , } from '@masknet/web3-shared-evm' ; import { useCallback , useState } from 'react' ; import { SLIPPAGE_DEFAULT } from '../../constants' ; import { SwapResponse , TradeComputed , TradeStrategy } from '../../types' ; import { useTradeAmount } from './useTradeAmount' ; import { TargetChainIdContext } from '../useTargetChainIdContext' ; export function useTradeCallback ( trade , exchangeProxyContract , allowedSlippage = SLIPPAGE_DEFAULT , gasConfig ? ) { const account = useAccount ( ) ; const { targetChainId : chainId } = TargetChainIdContext . useContainer ( ) ; const { BALANCER_ETH_ADDRESS } = useTraderConstants ( chainId ) ; const [ tradeState , setTradeState ] = useState < TransactionState > ( { type : TransactionStateType . UNKNOWN , } ) ; const tradeAmount = useTradeAmount ( trade , allowedSlippage ) ; const tradeCallback = useCallback ( async ( ) => { if ( ! trade || ! trade . inputToken || ! trade . outputToken || ! exchangeProxyContract || ! BALANCER_ETH_ADDRESS ) { setTradeState ( { type : TransactionStateType . UNKNOWN , } ) ; return ; } setTradeState ( { type : TransactionStateType . WAIT_FOR_CONFIRMING , } ) ; const { swaps : [ swaps ] , } = trade . trade_ as SwapResponse ; const swap_ = swaps . map ( ( x ) => x . map ( ( y ) => [ y . pool , y . tokenIn , y . tokenOut , y . swapAmount , y . limitReturnAmount , y . maxPrice , ] as [ string , string , string , string , string , string ] ) ) ; const inputTokenAddress = trade . inputToken . type === EthereumTokenType . Native ? BALANCER_ETH_ADDRESS : trade . inputToken . address ; const outputTokenAddress = trade . outputToken . type === EthereumTokenType . Native ? BALANCER_ETH_ADDRESS : trade . outputToken . address ; const tx = trade . strategy === TradeStrategy . ExactIn ? exchangeProxyContract . methods . multihopBatchSwapExactIn ( swap_ , inputTokenAddress , outputTokenAddress , trade . inputAmount . toFixed ( ) , tradeAmount . toFixed ( ) ) : exchangeProxyContract . methods . multihopBatchSwapExactOut ( swap_ , inputTokenAddress , outputTokenAddress , tradeAmount . toFixed ( ) ) ; let transactionValue = '0' ; if ( trade . strategy === TradeStrategy . ExactIn && trade . inputToken . type === EthereumTokenType . Native ) transactionValue = trade . inputAmount . toFixed ( ) ; else if ( trade . strategy === TradeStrategy . ExactOut && trade . outputToken . type === EthereumTokenType . Native ) transactionValue = trade . outputAmount . toFixed ( ) ; const config = { from : account , gas : await tx . estimateGas ( { from : account , value : transactionValue , } ) . catch ( ( error ) => { setTradeState ( { type : TransactionStateType . FAILED , error , } ) ; throw error ; } ) , value : transactionValue , ... gasConfig , } ; return new Promise < void > ( ( resolve , reject ) => { tx . send ( config as PayableTx ) . on ( TransactionEventType . RECEIPT , ( receipt ) => { setTradeState ( { type : TransactionStateType . CONFIRMED , no : 0 , receipt , } ) ; resolve ( ) ; } ) . on ( TransactionEventType . CONFIRMATION , ( no , receipt ) => { setTradeState ( { type : TransactionStateType . CONFIRMED , no , receipt , } ) ; resolve ( ) ; } ) . on ( TransactionEventType . ERROR , ( error ) => { setTradeState ( { type : TransactionStateType . FAILED , error , } ) ; reject ( error ) ; } ) ; } ) ; } , [ chainId , trade , tradeAmount , exchangeProxyContract , BALANCER_ETH_ADDRESS ] ) ; const resetCallback = useCallback ( ( ) => { setTradeState ( { type : TransactionStateType . UNKNOWN , } ) ; } , [ ] ) ; return [ tradeState , tradeCallback , resetCallback ] as const ; }