github.com/ethereum-optimism/optimism@v1.7.2/packages/sdk/src/adapters/eth-bridge.ts (about)

     1  /* eslint-disable @typescript-eslint/no-unused-vars */
     2  import { ethers, Overrides, BigNumber } from 'ethers'
     3  import { TransactionRequest, BlockTag } from '@ethersproject/abstract-provider'
     4  import { predeploys } from '@eth-optimism/contracts'
     5  import { hexStringEquals } from '@eth-optimism/core-utils'
     6  
     7  import {
     8    NumberLike,
     9    AddressLike,
    10    TokenBridgeMessage,
    11    MessageDirection,
    12  } from '../interfaces'
    13  import { toAddress, omit } from '../utils'
    14  import { StandardBridgeAdapter } from './standard-bridge'
    15  
    16  /**
    17   * Bridge adapter for the ETH bridge.
    18   */
    19  export class ETHBridgeAdapter extends StandardBridgeAdapter {
    20    public async approval(
    21      l1Token: AddressLike,
    22      l2Token: AddressLike,
    23      signer: ethers.Signer
    24    ): Promise<BigNumber> {
    25      throw new Error(`approval not necessary for ETH bridge`)
    26    }
    27  
    28    public async getDepositsByAddress(
    29      address: AddressLike,
    30      opts?: {
    31        fromBlock?: BlockTag
    32        toBlock?: BlockTag
    33      }
    34    ): Promise<TokenBridgeMessage[]> {
    35      const events = await this.l1Bridge.queryFilter(
    36        this.l1Bridge.filters.ETHDepositInitiated(address),
    37        opts?.fromBlock,
    38        opts?.toBlock
    39      )
    40  
    41      return events
    42        .map((event) => {
    43          return {
    44            direction: MessageDirection.L1_TO_L2,
    45            from: event.args.from,
    46            to: event.args.to,
    47            l1Token: ethers.constants.AddressZero,
    48            l2Token: predeploys.OVM_ETH,
    49            amount: event.args.amount,
    50            data: event.args.extraData,
    51            logIndex: event.logIndex,
    52            blockNumber: event.blockNumber,
    53            transactionHash: event.transactionHash,
    54          }
    55        })
    56        .sort((a, b) => {
    57          // Sort descending by block number
    58          return b.blockNumber - a.blockNumber
    59        })
    60    }
    61  
    62    public async getWithdrawalsByAddress(
    63      address: AddressLike,
    64      opts?: {
    65        fromBlock?: BlockTag
    66        toBlock?: BlockTag
    67      }
    68    ): Promise<TokenBridgeMessage[]> {
    69      const events = await this.l2Bridge.queryFilter(
    70        this.l2Bridge.filters.WithdrawalInitiated(undefined, undefined, address),
    71        opts?.fromBlock,
    72        opts?.toBlock
    73      )
    74  
    75      return events
    76        .filter((event) => {
    77          // Only find ETH withdrawals.
    78          return (
    79            hexStringEquals(event.args.l1Token, ethers.constants.AddressZero) &&
    80            hexStringEquals(event.args.l2Token, predeploys.OVM_ETH)
    81          )
    82        })
    83        .map((event) => {
    84          return {
    85            direction: MessageDirection.L2_TO_L1,
    86            from: event.args.from,
    87            to: event.args.to,
    88            l1Token: event.args.l1Token,
    89            l2Token: event.args.l2Token,
    90            amount: event.args.amount,
    91            data: event.args.extraData,
    92            logIndex: event.logIndex,
    93            blockNumber: event.blockNumber,
    94            transactionHash: event.transactionHash,
    95          }
    96        })
    97        .sort((a, b) => {
    98          // Sort descending by block number
    99          return b.blockNumber - a.blockNumber
   100        })
   101    }
   102  
   103    public async supportsTokenPair(
   104      l1Token: AddressLike,
   105      l2Token: AddressLike
   106    ): Promise<boolean> {
   107      // Only support ETH deposits and withdrawals.
   108      return (
   109        hexStringEquals(toAddress(l1Token), ethers.constants.AddressZero) &&
   110        hexStringEquals(toAddress(l2Token), predeploys.OVM_ETH)
   111      )
   112    }
   113  
   114    populateTransaction = {
   115      approve: async (
   116        l1Token: AddressLike,
   117        l2Token: AddressLike,
   118        amount: NumberLike,
   119        opts?: {
   120          overrides?: Overrides
   121        }
   122      ): Promise<never> => {
   123        throw new Error(`approvals not necessary for ETH bridge`)
   124      },
   125  
   126      deposit: async (
   127        l1Token: AddressLike,
   128        l2Token: AddressLike,
   129        amount: NumberLike,
   130        opts?: {
   131          recipient?: AddressLike
   132          l2GasLimit?: NumberLike
   133          overrides?: Overrides
   134        }
   135      ): Promise<TransactionRequest> => {
   136        if (!(await this.supportsTokenPair(l1Token, l2Token))) {
   137          throw new Error(`token pair not supported by bridge`)
   138        }
   139  
   140        if (opts?.recipient === undefined) {
   141          return this.l1Bridge.populateTransaction.depositETH(
   142            opts?.l2GasLimit || 200_000, // Default to 200k gas limit.
   143            '0x', // No data.
   144            {
   145              ...omit(opts?.overrides || {}, 'value'),
   146              value: amount,
   147            }
   148          )
   149        } else {
   150          return this.l1Bridge.populateTransaction.depositETHTo(
   151            toAddress(opts.recipient),
   152            opts?.l2GasLimit || 200_000, // Default to 200k gas limit.
   153            '0x', // No data.
   154            {
   155              ...omit(opts?.overrides || {}, 'value'),
   156              value: amount,
   157            }
   158          )
   159        }
   160      },
   161  
   162      withdraw: async (
   163        l1Token: AddressLike,
   164        l2Token: AddressLike,
   165        amount: NumberLike,
   166        opts?: {
   167          recipient?: AddressLike
   168          overrides?: Overrides
   169        }
   170      ): Promise<TransactionRequest> => {
   171        if (!(await this.supportsTokenPair(l1Token, l2Token))) {
   172          throw new Error(`token pair not supported by bridge`)
   173        }
   174  
   175        if (opts?.recipient === undefined) {
   176          return this.l2Bridge.populateTransaction.withdraw(
   177            toAddress(l2Token),
   178            amount,
   179            0, // L1 gas not required.
   180            '0x', // No data.
   181            {
   182              ...omit(opts?.overrides || {}, 'value'),
   183              value: this.messenger.bedrock ? amount : 0,
   184            }
   185          )
   186        } else {
   187          return this.l2Bridge.populateTransaction.withdrawTo(
   188            toAddress(l2Token),
   189            toAddress(opts.recipient),
   190            amount,
   191            0, // L1 gas not required.
   192            '0x', // No data.
   193            {
   194              ...omit(opts?.overrides || {}, 'value'),
   195              value: this.messenger.bedrock ? amount : 0,
   196            }
   197          )
   198        }
   199      },
   200    }
   201  }