import { BigNumber } from '@ethersproject/bignumber' ; import { arrayify , hexlify } from '@ethersproject/bytes' ; import { TransactionReceipt } from '@ethersproject/abstract-provider' ; import { ethers } from 'ethers' ; import { xapps } from '@optics-xyz/ts-interface' ; import { BridgeContracts , OpticsContext } from '..' ; import { ResolvedTokenInfo , TokenIdentifier } from '../tokens' ; import { OpticsMessage } from './OpticsMessage' ; import { AnnotatedDispatch } from '../events/opticsEvents' ; const ACTION_LEN = { identifier : 1 , tokenId : 36 , transfer : 65 , details : 66 , requestDetails : 1 , } ; type Transfer = { type : 'transfer' ; to : string ; amount : BigNumber ; } ; export type Details = { type : 'details' ; name : string ; symbol : string ; decimals : number ; } ; export type RequestDetails = { type : 'requestDetails' ; } ; export type Action = Transfer | Details | RequestDetails ; export type ParsedBridgeMessage < T extends Action > = { token : TokenIdentifier ; action : T ; } ; export type AnyBridgeMessage = TransferMessage | DetailsMessage | RequestDetailsMessage ; export type ParsedTransferMessage = ParsedBridgeMessage < Transfer > ; export type ParsedDetailsMessage = ParsedBridgeMessage < Details > ; export type ParsedRequestDetailsMesasage = ParsedBridgeMessage < RequestDetails > ; function parseAction ( buf ) { if ( buf . length === ACTION_LEN . requestDetails ) { return { type : 'requestDetails' } ; } if ( buf . length === ACTION_LEN . transfer ) { buf = buf . slice ( ACTION_LEN . identifier ) ; return { type : 'transfer' , to : hexlify ( buf . slice ( 0 , 32 ) ) , amount : BigNumber . from ( hexlify ( buf . slice ( 32 ) ) ) , } ; } if ( buf . length === ACTION_LEN . details ) { buf = buf . slice ( ACTION_LEN . identifier ) ; return { type : 'details' , name : hexlify ( buf . slice ( 0 , 32 ) ) , symbol : hexlify ( buf . slice ( 32 , 64 ) ) , decimals : buf [ 64 ] , } ; } throw new Error ( 'Bad action' ) ; } function parseBody ( messageBody ) { const buf = arrayify ( messageBody ) ; const tokenId = buf . slice ( 0 , 36 ) ; const token = { domain : Buffer . from ( tokenId ) . readUInt32BE ( 0 ) , id : hexlify ( tokenId . slice ( 4 , 36 ) ) , } ; const action = parseAction ( buf . slice ( 36 ) ) ; const parsedMessage = { action , token , } ; switch ( action . type ) { case 'transfer' : return parsedMessage as ParsedTransferMessage ; case 'details' : return parsedMessage as ParsedDetailsMessage ; case 'requestDetails' : return parsedMessage as ParsedRequestDetailsMesasage ; } } /**
 * The BridgeMessage extends  OpticsMessage with Bridge-specific
 * functionality.
  class BridgeMessage extends OpticsMessage { readonly token : TokenIdentifier ; readonly fromBridge : BridgeContracts ; readonly toBridge : BridgeContracts ; hideconstructor constructor ( context , event , token , callerKnowsWhatTheyAreDoing ) { if ( ! callerKnowsWhatTheyAreDoing ) { throw new Error ( 'Use `fromReceipt` to instantiate' ) ; } super ( context , event ) ; const fromBridge = context . mustGetBridge ( this . message . from ) ; const toBridge = context . mustGetBridge ( this . message . destination ) ; this . fromBridge = fromBridge ; this . toBridge = toBridge ; this . token = token ; } /**
     * Attempt to instantiate a BridgeMessage from an existing
     *  OpticsMessage param context The  OpticsContext to use.
     *  param opticsMessage returns throws static fromOpticsMessage ( context , opticsMessage ) { const parsedMessageBody = parseBody ( opticsMessage . message . body ) ; switch ( parsedMessageBody . action . type ) { case 'transfer' : return new TransferMessage ( context , opticsMessage . dispatch , parsedMessageBody as ParsedTransferMessage ) ; case 'details' : return new DetailsMessage ( context , opticsMessage . dispatch , parsedMessageBody as ParsedDetailsMessage ) ; case 'requestDetails' : return new RequestDetailsMessage ( context , opticsMessage . dispatch , parsedMessageBody as ParsedRequestDetailsMesasage ) ; } } param context The  OpticsContext to use.
     *  param nameOrDomain param receipt returns an array of  BridgeMessage objects
     *  throws static fromReceipt ( context , nameOrDomain , receipt ) { const opticsMessages = OpticsMessage . fromReceipt ( context , nameOrDomain , receipt ) ; const bridgeMessages = [ ] ; for ( const opticsMessage of opticsMessages ) { try { const bridgeMessage = BridgeMessage . fromOpticsMessage ( context , opticsMessage ) ; bridgeMessages . push ( bridgeMessage ) ; } catch ( e ) { } } return bridgeMessages ; } param context The  OpticsContext to use.
     *  param nameOrDomain param receipt returns an array of  BridgeMessage objects
     *  throws static singleFromReceipt ( context , nameOrDomain , receipt ) { const messages = BridgeMessage . fromReceipt ( context , nameOrDomain , receipt ) ; if ( messages . length !== 1 ) { throw new Error ( 'Expected single Dispatch in transaction' ) ; } return messages [ 0 ] ; } param context The  OpticsContext to use.
     *  param nameOrDomain param transactionHash returns an array of  BridgeMessage objects
     *  throws static async fromTransactionHash ( context , nameOrDomain , transactionHash ) { const provider = context . mustGetProvider ( nameOrDomain ) ; const receipt = await provider . getTransactionReceipt ( transactionHash ) ; if ( ! receipt ) { throw new Error ( `No receipt for ${ transactionHash } on ${ nameOrDomain }` ) ; } return BridgeMessage . fromReceipt ( context , nameOrDomain , receipt ) ; } param context The  OpticsContext to use.
     *  param nameOrDomain param transactionHash returns an array of  BridgeMessage objects
     *  throws static async singleFromTransactionHash ( context , nameOrDomain , transactionHash ) { const provider = context . mustGetProvider ( nameOrDomain ) ; const receipt = await provider . getTransactionReceipt ( transactionHash ) ; if ( ! receipt ) { throw new Error ( `No receipt for ${ transactionHash } on ${ nameOrDomain }` ) ; } return BridgeMessage . singleFromReceipt ( context , nameOrDomain , receipt ) ; } returns async asset ( ) { return await this . context . resolveRepresentations ( this . token ) ; } returns async assetAtOrigin ( ) { return ( await this . asset ( ) ) . tokens . get ( this . origin ) ; } returns async assetAtDestination ( ) { return ( await this . asset ( ) ) . tokens . get ( this . destination ) ; } } /**
 * A TransferMessage extends the  BridgeMessage with transfer-specific
 * functionality.
  export class TransferMessage extends BridgeMessage { action : Transfer ; constructor ( context , event , parsed ) { super ( context , event , parsed . token , true ) ; this . action = parsed . action ; } returns async currentlyPrefilled ( ) { const bridge = this . context . mustGetBridge ( this . destination ) ; const lpAddress = await bridge . bridgeRouter . liquidityProvider ( this . prefillId ) ; if ( lpAddress !== ethers . constants . AddressZero ) { return true ; } return false ; } /**
     * The amount of tokens being transferred (in the smallest unit)
     */ get amount ( ) : BigNumber { return this . action . amount ; } /**
     * The identifier for the recipient of the tokens
     */ get to ( ) : string { return this . action . to ; } /**
     * The ID used for prefilling this transfer message.
     */ get prefillId ( ) : string { return this . bodyHash ; } } /**
 * A DetailsMessage extends the  BridgeMessage with details-specific
 * functionality.
  export class DetailsMessage extends BridgeMessage { action : Details ; constructor ( context , event , parsed ) { super ( context , event , parsed . token , true ) ; this . action = parsed . action ; } /**
     * Get the token name being sent
     */ get name ( ) : string { return this . action . name ; } /**
     * Get the token symbol being sent
     */ get symbol ( ) : string { return this . action . symbol ; } /**
     * Get the token decimals being sent
     */ get decimals ( ) : number { return this . action . decimals ; } } /**
 * A RequestDetailsMessage extends the  BridgeMessage with
 * details-specific functionality.
  export class RequestDetailsMessage extends BridgeMessage { action : RequestDetails ; constructor ( context , event , parsed ) { super ( context , event , parsed . token , true ) ; this . action = parsed . action ; } }