import { BigNumber , Contract , providers } from 'ethers' ; import { getAddress , hexDataSlice } from 'ethers/lib/utils' ; import { TokenMapping } from '../common/interfaces' ; import { Allowance } from './interfaces' ; import { toFloat , unpackResult } from '../common/util' ; import { DUMMY_ADDRESS , DUMMY_ADDRESS_2 } from '../common/constants' ; export async function getAllowancesFromApprovals ( contract , ownerAddress , approvals ) { const deduplicatedApprovals = approvals . filter ( ( approval , i ) => i === approvals . findIndex ( other => approval . topics [ 2 ] === other . topics [ 2 ] ) ) ; let allowances = await Promise . all ( deduplicatedApprovals . map ( ( approval ) => getAllowanceFromApproval ( contract , ownerAddress , approval ) ) ) ; return allowances ; } async function getAllowanceFromApproval ( multicallContract , ownerAddress , approval ) { const spender = getAddress ( hexDataSlice ( approval . topics [ 2 ] , 12 ) ) ; const allowance = ( await unpackResult ( multicallContract . functions . allowance ( ownerAddress , spender ) ) ) . toString ( ) ; return { spender , allowance } ; } export async function getTokenData ( contract , ownerAddress , tokenMapping = { } ) { const tokenData = tokenMapping [ getAddress ( contract . address ) ] ; const [ totalSupplyBN , balance , symbol , decimals ] = await Promise . all ( [ unpackResult ( contract . functions . totalSupply ( ) ) , unpackResult ( contract . functions . balanceOf ( ownerAddress ) ) , tokenData ?. symbol ?? unpackResult ( contract . functions . symbol ( ) ) , tokenData ?. decimals ?? unpackResult ( contract . functions . decimals ( ) ) , throwIfNotErc20 ( contract ) , ] ) ; const totalSupply = totalSupplyBN . toString ( ) ; return { symbol , decimals , totalSupply , balance } ; } export function formatAllowance ( allowance , decimals , totalSupply ) { const allowanceBN = BigNumber . from ( allowance ) ; const totalSupplyBN = BigNumber . from ( totalSupply ) ; if ( allowanceBN . gt ( totalSupplyBN ) ) { return 'Unlimited' ; } return toFloat ( Number ( allowanceBN ) , decimals ) ; } async function throwIfNotErc20 ( contract ) { const [ allowance ] = await contract . functions . allowance ( DUMMY_ADDRESS , DUMMY_ADDRESS_2 ) ; if ( allowance . toString ( ) !== '0' ) { throw new Error ( 'Response to allowance was not 0, indicating that this is not an ERC20 contract' ) ; } }