import urlcat from 'urlcat' ; import type BigNumber from 'bignumber.js' ; import { first } from 'lodash-unified' ; import { ChainId , getExplorerConstants , getRedPacketConstants , isSameAddress , getChainName , } from '@masknet/web3-shared-evm' ; import { Interface } from '@ethersproject/abi' ; import type { RedPacketJSONPayloadFromChain } from '../../types' ; import { getTransactionReceipt } from '../../../../extension/background-script/EthereumService' ; import REDPACKET_ABI from '@masknet/web3-contracts/abis/HappyRedPacketV4.json' ; import { checkAvailability } from './checkAvailability' ; const interFace = new Interface ( REDPACKET_ABI ) ; export async function getRedPacketHistory ( chainId , startBlock , endBlock , senderAddress ) { const { EXPLORER_API , API_KEYS = [ ] } = getExplorerConstants ( chainId ) ; const { HAPPY_RED_PACKET_ADDRESS_V4 } = getRedPacketConstants ( chainId ) ; if ( ! EXPLORER_API || ! HAPPY_RED_PACKET_ADDRESS_V4 || ! startBlock ) return [ ] ; const response = await fetch ( urlcat ( EXPLORER_API , { apikey : first ( API_KEYS ) , action : 'txlist' , module : 'account' , sort : 'desc' , startBlock , endBlock , address : HAPPY_RED_PACKET_ADDRESS_V4 , } ) ) ; if ( ! response . ok ) return [ ] ; type TxType = { hash : string ; input : string ; from : string ; to : string ; blockNumber : string ; } ; type CreateRedpacketParam = { _duration : BigNumber ; _ifrandom : boolean ; _message : string ; _name : string ; _number : BigNumber ; _public_key : string ; _seed : string ; _token_addr : string ; _token_type : BigNumber ; _total_tokens : BigNumber ; } ; const { result } = await response . json ( ) ; if ( ! result . length ) return [ ] ; const payloadList = result . reduce ( ( acc , cur ) => { if ( ! isSameAddress ( cur . from , senderAddress ) ) return acc ; try { const decodedInputParam = interFace . decodeFunctionData ( 'create_red_packet' , cur . input ) as unknown as CreateRedpacketParam ; const redpacketPayload = { contract_address : cur . to , txid : cur . hash , shares : decodedInputParam . _number . toNumber ( ) , is_random : decodedInputParam . _ifrandom , total : decodedInputParam . _total_tokens . toString ( ) , duration : decodedInputParam . _duration . toNumber ( ) * 1000 , block_number : Number ( cur . blockNumber ) , contract_version : 4 , network : getChainName ( chainId ) , token_address : decodedInputParam . _token_addr , sender : { address : senderAddress , name : decodedInputParam . _name , message : decodedInputParam . _message , } , rpid : '' , creation_time : 0 , total_remaining : '' , claimers : [ ] , password : '' , } ; return acc . concat ( redpacketPayload ) ; } catch { return acc ; } } , [ ] ) ; type CreationSuccessEventParams = { id : string ; creation_time : BigNumber ; } ; const eventLogResponse = await Promise . allSettled ( payloadList . map ( async ( payload ) => { const result = await getTransactionReceipt ( payload . txid ) ; if ( ! result ) return null ; const log = result . logs . find ( ( log ) => isSameAddress ( log . address , HAPPY_RED_PACKET_ADDRESS_V4 ) ) ; if ( ! log ) return null ; const eventParams = interFace . decodeEventLog ( 'CreationSuccess' , log . data , log . topics ) as unknown as CreationSuccessEventParams ; payload . rpid = eventParams . id ; payload . creation_time = eventParams . creation_time . toNumber ( ) * 1000 ; const data = await checkAvailability ( payload . rpid , payload . sender . address , payload . contract_address , chainId ) ; payload . claimers = Array . from ( { length : data . claimed } ) . map ( ( ) => ( { address : '' , name : '' } ) ) ; payload . total_remaining = data . balance ; return payload ; } ) ) ; return eventLogResponse . map ( ( v ) => ( v . status === 'fulfilled' && v . value ? v . value : null ) ) . filter ( ( v ) => Boolean ( v ) ) as RedPacketJSONPayloadFromChain [ ] ; }