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 }