import { bufferToHex } from 'ethereumjs-util' ; import { SUPPORTED_TRANSACTION_QUERY_PARAMS } from '@config' ; import { deriveTxRecipientsAndAmount , ERCType , guessERC20Type , isEIP1559Supported } from '@helpers' ; import { encodeTransfer } from '@services/EthService' ; import { translateRaw } from '@translations' ; import { Asset , DistributiveOmit , ExtendedAsset , IFormikFields , ITxConfig , ITxData , ITxObject , ITxToAddress , ITxValue , Network , NetworkId , StoreAccount , TAddress , TTicker , TxQueryTypes } from '@types' ; import { Address , fromTokenBase , generateAssetUUID , handleValues , inputGasLimitToHex , inputGasPriceToHex , inputNonceToHex , inputValueToHex , isQueryValid , isSameAddress , TokenValue , toWei } from '@utils' ; import { isEmpty } from '@vendor' ; import { IFullTxParam } from './types' ; const createBaseTxObject = ( formData ) : ITxObject => { const { network , account } = formData ; const gas = isEIP1559Supported ( network , account ) ? { maxFeePerGas : inputGasPriceToHex ( formData . maxFeePerGasField ) , maxPriorityFeePerGas : inputGasPriceToHex ( formData . maxPriorityFeePerGasField ) , type : 2 as const } : { gasPrice : formData . advancedTransaction ? inputGasPriceToHex ( formData . gasPriceField ) : inputGasPriceToHex ( formData . gasPriceSlider ) } ; return { ... gas , to : formData . address . value as ITxToAddress , value : formData . amount ? inputValueToHex ( formData . amount ) : ( '0x0' as ITxValue ) , data : formData . txDataField ? ( formData . txDataField as ITxData ) : ( '0x0' as ITxData ) , gasLimit : inputGasLimitToHex ( formData . gasLimitField ) , nonce : inputNonceToHex ( formData . nonceField ) , chainId : network . chainId ? network . chainId : 1 } ; } ; const createERC20TxObject = ( formData ) : ITxObject => { const baseTx = createBaseTxObject ( formData ) ; const { asset } = formData ; return { ... baseTx , to : asset . contractAddress ! as ITxToAddress , value : '0x0' as ITxValue , data : bufferToHex ( encodeTransfer ( Address ( formData . address . value ) , formData . amount !== '' ? toWei ( formData . amount , asset . decimal ! ) : TokenValue ( '0' ) ) ) as ITxData } ; } ; export const isERC20Asset = ( asset ) : boolean => { return ! ! ( asset . type === 'erc20' && asset . contractAddress && asset . decimal ) ; } ; export const processFormDataToTx = ( formData ) : ITxObject => { const transform = isERC20Asset ( formData . asset ) ? createERC20TxObject : createBaseTxObject ; return transform ( formData ) ; } ; export const processFormForEstimateGas = ( formData ) : DistributiveOmit < ITxObject , 'gasLimit' > => { const { gasLimit , ... tx } = processFormDataToTx ( formData ) ; return { ... tx , from : formData . account . address } ; } ; export const parseQueryParams = ( queryParams ) => ( networks , assets , accounts ) => { if ( ! queryParams || isEmpty ( queryParams ) ) return ; switch ( queryParams . queryType ) { case TxQueryTypes . SPEEDUP : return { queryType : TxQueryTypes . SPEEDUP , txConfig : parseTransactionQueryParams ( queryParams ) ( networks , assets , accounts ) } ; case TxQueryTypes . CANCEL : return { queryType : TxQueryTypes . CANCEL , txConfig : parseTransactionQueryParams ( queryParams ) ( networks , assets , accounts ) } ; default : return { queryType : TxQueryTypes . DEFAULT } ; } } ; export const parseTransactionQueryParams = ( queryParams ) => ( networks , assets , accounts ) : ITxConfig | undefined => { const i = SUPPORTED_TRANSACTION_QUERY_PARAMS . reduce ( ( acc , cv ) => { if ( queryParams [ cv ] === undefined ) return acc ; return { ... acc , [ cv ] : queryParams [ cv ] } ; } , { } ) as IFullTxParam ; if ( ! isQueryValid ( i ) ) return ; const network = networks . find ( ( n ) => n . chainId . toString ( ) === i . chainId ) ; if ( ! network ) return ; const senderAccount = accounts . find ( ( { address } ) => isSameAddress ( address , i . from ) ) ; if ( ! senderAccount ) return ; const gas = i . gasPrice ? { gasPrice : i . gasPrice } : { maxFeePerGas : i . maxFeePerGas ! , maxPriorityFeePerGas : i . maxPriorityFeePerGas ! , type : ( i . type ?? 2 ) as 2 } ; const rawTransaction = { to : i . to , value : i . value , gasLimit : i . gasLimit , ... gas , nonce : i . nonce , data : i . data , chainId : parseInt ( i . chainId , 16 ) } ; const ercType = guessERC20Type ( i . data ) ; const isERC20 = ercType === ERCType . TRANSFER ; const { to , amount , receiverAddress } = deriveTxRecipientsAndAmount ( ercType , i . data , i . to , i . value ) ; const baseAsset = assets . find ( ( { uuid } ) => uuid === network . baseAsset ) as ExtendedAsset ; const asset = isERC20 ? assets . find ( ( { contractAddress } ) => contractAddress && isSameAddress ( contractAddress as TAddress , to ) ) || generateGenericErc20 ( to ! , i . chainId , network . id ) : baseAsset ; return { from : senderAccount . address , amount : fromTokenBase ( handleValues ( amount ) , asset . decimal ) , rawTransaction , networkId : network . id , senderAccount , baseAsset , asset , receiverAddress } ; } ; export const generateGenericErc20 = ( contractAddress , chainId , networkId ) : ExtendedAsset => ( { uuid : generateAssetUUID ( chainId , contractAddress ) , name : translateRaw ( 'GENERIC_ERC20_NAME' ) , ticker : 'Unknown ERC20' as TTicker , type : 'erc20' , networkId } ) ;