Commit aa2949ef authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

fix: eth deposits through bridge (#3160)

Withdrawals don't seem to update balances correctly
for some reason, still need to debug why that is.

chore: add changeset
parent a088bb36
---
'@eth-optimism/sdk': patch
---
Add eth withdrawal support
...@@ -8,7 +8,13 @@ import { ...@@ -8,7 +8,13 @@ import {
Log, Log,
} from '@ethersproject/abstract-provider' } from '@ethersproject/abstract-provider'
import { Signer } from '@ethersproject/abstract-signer' import { Signer } from '@ethersproject/abstract-signer'
import { ethers, BigNumber, Overrides, CallOverrides } from 'ethers' import {
ethers,
BigNumber,
Overrides,
CallOverrides,
PayableOverrides,
} from 'ethers'
import { import {
sleep, sleep,
remove0x, remove0x,
...@@ -1143,7 +1149,7 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -1143,7 +1149,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
message: MessageLike, message: MessageLike,
opts?: { opts?: {
signer?: Signer signer?: Signer
overrides?: Overrides overrides?: PayableOverrides
} }
): Promise<TransactionResponse> { ): Promise<TransactionResponse> {
return (opts?.signer || this.l1Signer).sendTransaction( return (opts?.signer || this.l1Signer).sendTransaction(
...@@ -1315,7 +1321,7 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -1315,7 +1321,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
finalizeMessage: async ( finalizeMessage: async (
message: MessageLike, message: MessageLike,
opts?: { opts?: {
overrides?: Overrides overrides?: PayableOverrides
} }
): Promise<TransactionRequest> => { ): Promise<TransactionRequest> => {
const resolved = await this.toCrossChainMessage(message) const resolved = await this.toCrossChainMessage(message)
...@@ -1327,6 +1333,15 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -1327,6 +1333,15 @@ export class CrossChainMessenger implements ICrossChainMessenger {
const [proof, output, withdrawalTx] = await this.getBedrockMessageProof( const [proof, output, withdrawalTx] = await this.getBedrockMessageProof(
message message
) )
if (!opts) {
opts = {}
}
if (!opts.overrides) {
opts.overrides = {}
}
if (!opts.overrides.value) {
opts.overrides.value = withdrawalTx.value
}
return this.contracts.l1.OptimismPortal.populateTransaction.finalizeWithdrawalTransaction( return this.contracts.l1.OptimismPortal.populateTransaction.finalizeWithdrawalTransaction(
[ [
...@@ -1344,7 +1359,8 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -1344,7 +1359,8 @@ export class CrossChainMessenger implements ICrossChainMessenger {
proof.outputRootProof.withdrawerStorageRoot, proof.outputRootProof.withdrawerStorageRoot,
proof.outputRootProof.latestBlockhash, proof.outputRootProof.latestBlockhash,
], ],
proof.withdrawalProof proof.withdrawalProof,
opts.overrides
) )
} else { } else {
// L1CrossDomainMessenger relayMessage is the only method that isn't fully backwards // L1CrossDomainMessenger relayMessage is the only method that isn't fully backwards
...@@ -1372,9 +1388,25 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -1372,9 +1388,25 @@ export class CrossChainMessenger implements ICrossChainMessenger {
opts?: { opts?: {
recipient?: AddressLike recipient?: AddressLike
l2GasLimit?: NumberLike l2GasLimit?: NumberLike
overrides?: Overrides overrides?: PayableOverrides
} }
): Promise<TransactionRequest> => { ): Promise<TransactionRequest> => {
if (this.bedrock) {
const value = BigNumber.from(opts?.overrides?.value ?? 0)
if (!value.eq(0) && !value.eq(amount)) {
throw new Error(`amount and value mismatch`)
}
if (!opts) {
opts = {}
}
if (!opts.overrides) {
opts.overrides = {}
}
if (!opts.overrides.value) {
opts.overrides.value = value
}
}
return this.bridges.ETH.populateTransaction.deposit( return this.bridges.ETH.populateTransaction.deposit(
ethers.constants.AddressZero, ethers.constants.AddressZero,
predeploys.OVM_ETH, predeploys.OVM_ETH,
...@@ -1387,9 +1419,24 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -1387,9 +1419,24 @@ export class CrossChainMessenger implements ICrossChainMessenger {
amount: NumberLike, amount: NumberLike,
opts?: { opts?: {
recipient?: AddressLike recipient?: AddressLike
overrides?: Overrides overrides?: PayableOverrides
} }
): Promise<TransactionRequest> => { ): Promise<TransactionRequest> => {
const value = BigNumber.from(opts?.overrides?.value ?? 0)
if (this.bedrock) {
if (!value.eq(0) && !value.eq(amount)) {
throw new Error(`amount and value mismatch`)
}
if (!opts) {
opts = {}
}
if (!opts.overrides) {
opts.overrides = {}
}
if (!opts.overrides.value) {
opts.overrides.value = value
}
}
return this.bridges.ETH.populateTransaction.withdraw( return this.bridges.ETH.populateTransaction.withdraw(
ethers.constants.AddressZero, ethers.constants.AddressZero,
predeploys.OVM_ETH, predeploys.OVM_ETH,
......
import { Contract, Overrides, Signer, BigNumber, CallOverrides } from 'ethers' import {
Contract,
Overrides,
Signer,
BigNumber,
CallOverrides,
PayableOverrides,
} from 'ethers'
import { import {
TransactionRequest, TransactionRequest,
TransactionResponse, TransactionResponse,
...@@ -204,7 +211,7 @@ export interface IBridgeAdapter { ...@@ -204,7 +211,7 @@ export interface IBridgeAdapter {
opts?: { opts?: {
recipient?: AddressLike recipient?: AddressLike
l2GasLimit?: NumberLike l2GasLimit?: NumberLike
overrides?: Overrides overrides?: PayableOverrides
} }
): Promise<TransactionRequest> ): Promise<TransactionRequest>
...@@ -225,7 +232,7 @@ export interface IBridgeAdapter { ...@@ -225,7 +232,7 @@ export interface IBridgeAdapter {
amount: NumberLike, amount: NumberLike,
opts?: { opts?: {
recipient?: AddressLike recipient?: AddressLike
overrides?: Overrides overrides?: PayableOverrides
} }
): Promise<TransactionRequest> ): Promise<TransactionRequest>
} }
......
...@@ -15,8 +15,9 @@ import { ...@@ -15,8 +15,9 @@ import {
// TODO(tynes): this task could be modularized in the future // TODO(tynes): this task could be modularized in the future
// so that it can deposit an arbitrary token. Right now it // so that it can deposit an arbitrary token. Right now it
// deposits and withdraws ETH through the bridge,
// deploys a WETH9 contract, mints some WETH9 and then // deploys a WETH9 contract, mints some WETH9 and then
// deposits that into L2 through the StandardBridge // deposits that into L2 through the StandardBridge.
task('deposit', 'Deposits WETH9 onto L2.') task('deposit', 'Deposits WETH9 onto L2.')
.addParam( .addParam(
'l2ProviderUrl', 'l2ProviderUrl',
...@@ -72,6 +73,10 @@ task('deposit', 'Deposits WETH9 onto L2.') ...@@ -72,6 +73,10 @@ task('deposit', 'Deposits WETH9 onto L2.')
const Deployment__OptimismMintableERC20TokenFactory = const Deployment__OptimismMintableERC20TokenFactory =
await hre.deployments.get('OptimismMintableERC20Factory') await hre.deployments.get('OptimismMintableERC20Factory')
const Deployment__OptimismPortal = await hre.deployments.get(
'OptimismPortal'
)
const Deployment__OptimismPortalProxy = await hre.deployments.get( const Deployment__OptimismPortalProxy = await hre.deployments.get(
'OptimismPortalProxy' 'OptimismPortalProxy'
) )
...@@ -84,6 +89,12 @@ task('deposit', 'Deposits WETH9 onto L2.') ...@@ -84,6 +89,12 @@ task('deposit', 'Deposits WETH9 onto L2.')
'L1CrossDomainMessengerProxy' 'L1CrossDomainMessengerProxy'
) )
const OptimismPortal = new hre.ethers.Contract(
Deployment__OptimismPortalProxy.address,
Deployment__OptimismPortal.abi,
signer
)
const messenger = new CrossChainMessenger({ const messenger = new CrossChainMessenger({
l1SignerOrProvider: signer, l1SignerOrProvider: signer,
l2SignerOrProvider: l2Signer, l2SignerOrProvider: l2Signer,
...@@ -108,6 +119,65 @@ task('deposit', 'Deposits WETH9 onto L2.') ...@@ -108,6 +119,65 @@ task('deposit', 'Deposits WETH9 onto L2.')
bedrock: true, bedrock: true,
}) })
const opBalanceBefore = await signer.provider.getBalance(
OptimismPortal.address
)
// Deposit ETH
console.log('Depositing ETH through StandardBridge')
const ethDeposit = await messenger.depositETH(utils.parseEther('1'))
const depositMessageReceipt = await messenger.waitForMessageReceipt(
ethDeposit
)
if (depositMessageReceipt.receiptStatus !== 1) {
throw new Error('deposit failed')
}
console.log('Deposit complete')
const opBalanceAfter = await signer.provider.getBalance(
OptimismPortal.address
)
if (!opBalanceBefore.add(utils.parseEther('1')).eq(opBalanceAfter)) {
throw new Error(`OptimismPortal balance mismatch`)
}
console.log('Withdrawing ETH')
const ethWithdraw = await messenger.withdrawETH(utils.parseEther('1'))
const ethWithdrawReceipt = await ethWithdraw.wait()
console.log('Withdrawal on L2 complete')
console.log('Waiting to be able to withdraw')
const id = setInterval(async () => {
const currentStatus = await messenger.getMessageStatus(ethWithdrawReceipt)
console.log(`Message status: ${MessageStatus[currentStatus]}`)
}, 3000)
await messenger.waitForMessageStatus(
ethWithdrawReceipt,
MessageStatus.READY_FOR_RELAY
)
clearInterval(id)
const ethFinalize = await messenger.finalizeMessage(ethWithdrawReceipt)
const ethFinalizeReceipt = await ethFinalize.wait()
if (ethFinalizeReceipt.status !== 1) {
throw new Error('Finalize withdrawal reverted')
}
console.log('ETH withdrawal complete')
const opBalanceFinally = await signer.provider.getBalance(
OptimismPortal.address
)
// TODO(tynes): fix this bug
if (!opBalanceFinally.eq(opBalanceBefore)) {
console.log('OptimismPortal balance mismatch')
console.log(`Balance before deposit: ${opBalanceBefore.toString()}`)
console.log(`Balance after deposit: ${opBalanceAfter.toString()}`)
console.log(`Balance after withdrawal: ${opBalanceFinally.toString()}`)
// throw new Error('OptimismPortal balance mismatch')
}
const OptimismMintableERC20TokenFactory = await hre.ethers.getContractAt( const OptimismMintableERC20TokenFactory = await hre.ethers.getContractAt(
Deployment__OptimismMintableERC20TokenFactory.abi, Deployment__OptimismMintableERC20TokenFactory.abi,
predeploys.OptimismMintableERC20Factory, predeploys.OptimismMintableERC20Factory,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment