import { AbstractConnector } from '@web3-react/abstract-connector' ; import BigNumber from 'bignumber.js' ; import Web3 from 'web3' ; import { SendOptions } from 'web3-eth-contract' ; import { prefix0X } from '../../utils/prefix0x' ; import { contractAbi } from '../../contractAbi' ; import { TransactionStatus } from '../../store/actions/depositFileActions' ; import { CONTRACT_ADDRESS , PRICE_PER_VALIDATOR } from '../../utils/envVars' ; import { DepositKeyInterface } from '../../store/reducers' ; const pricePerValidator = new BigNumber ( PRICE_PER_VALIDATOR ) ; const TX_VALUE = pricePerValidator . multipliedBy ( 1e18 ) . toNumber ( ) ; const isUserRejectionError = ( error ) => { if ( error . code === 4001 ) return true ; if ( error . code === - 32603 ) { if ( error . message . includes ( 'MetaMask Tx Signature: User denied transaction signature.' ) ) return true ; if ( error . message . includes ( '​Ledger device: U2F OTHER_ERROR' ) ) return false ; if ( error . message . includes ( 'Ledger device: Condition of use not satisfied (denied by the user?)' ) ) return true ; if ( error . message . includes ( 'Action cancelled by user' ) ) return true ; if ( error . message . includes ( 'Popup closed' ) ) return true ; if ( error . message . includes ( 'Permissions not granted' ) ) return true ; if ( error . message . includes ( 'device disconnected during action' ) ) return true ; if ( error . message . includes ( 'Fortmatic: User denied transaction.' ) ) return true ; if ( error . message . includes ( 'User denied transaction signature.' ) ) return true ; } return false ; } ; export const handleMultipleTransactions = async ( depositKeys , connector , account , updateTransactionStatus ) => { const walletProvider = await ( connector as AbstractConnector ) . getProvider ( ) ; const web3 = new Web3 ( walletProvider ) ; const contract = new web3 . eth . Contract ( contractAbi , CONTRACT_ADDRESS ) ; const transactionParameters = { gasPrice : web3 . utils . toHex ( await web3 . eth . getGasPrice ( ) ) , from : account as string , value : TX_VALUE , } ; const remainingTxs = depositKeys . filter ( key => key . transactionStatus === TransactionStatus . READY || key . transactionStatus === TransactionStatus . REJECTED ) ; const nextTransaction = remainingTxs . shift ( ) ; if ( nextTransaction === undefined ) { return ; } const { pubkey , withdrawal_credentials , signature , deposit_data_root , } = nextTransaction ; updateTransactionStatus ( pubkey , TransactionStatus . PENDING ) ; contract . methods . deposit ( prefix0X ( pubkey ) , prefix0X ( withdrawal_credentials ) , prefix0X ( signature ) , prefix0X ( deposit_data_root ) ) . send ( transactionParameters ) . on ( 'transactionHash' , ( txHash ) : void => { updateTransactionStatus ( pubkey , TransactionStatus . STARTED , txHash ) ; handleMultipleTransactions ( depositKeys , connector , account , updateTransactionStatus ) ; } ) . on ( 'receipt' , ( ) => { } ) . on ( 'confirmation' , ( confirmation , receipt ) : any => { if ( confirmation === 0 ) { if ( receipt . status ) { updateTransactionStatus ( pubkey , TransactionStatus . SUCCEEDED ) ; } else { updateTransactionStatus ( pubkey , TransactionStatus . FAILED ) ; } } } ) . on ( 'error' , ( error ) => { if ( isUserRejectionError ( error ) ) { updateTransactionStatus ( pubkey , TransactionStatus . REJECTED ) ; } else { updateTransactionStatus ( pubkey , TransactionStatus . FAILED ) ; } } ) ; } ;