Commit 6f66c71f authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

sdk: cleanup the deposit scripts (#3199)

Modularize into 2 hardhat tasks, make them
easier to debug.
parent c76c9587
...@@ -463,7 +463,11 @@ jobs: ...@@ -463,7 +463,11 @@ jobs:
working_directory: packages/contracts-bedrock working_directory: packages/contracts-bedrock
- run: - run:
name: Deposit ERC20 through the bridge name: Deposit ERC20 through the bridge
command: timeout 5m npx hardhat deposit --network devnetL1 command: timeout 5m npx hardhat deposit-erc20 --network devnetL1
working_directory: packages/sdk
- run:
name: Deposit ETH through the bridge
command: timeout 5m npx hardhat deposit-eth --network devnetL1
working_directory: packages/sdk working_directory: packages/sdk
- run: - run:
name: Check the status name: Check the status
......
...@@ -4,7 +4,7 @@ import '@nomiclabs/hardhat-ethers' ...@@ -4,7 +4,7 @@ import '@nomiclabs/hardhat-ethers'
import '@nomiclabs/hardhat-waffle' import '@nomiclabs/hardhat-waffle'
import 'hardhat-deploy' import 'hardhat-deploy'
import './tasks/deposit' import './tasks'
const config: HardhatUserConfig = { const config: HardhatUserConfig = {
solidity: { solidity: {
......
import { task, types } from 'hardhat/config'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { predeploys } from '@eth-optimism/contracts-bedrock'
import { Event, Contract, Wallet, providers, utils } from 'ethers'
import {
CrossChainMessenger,
StandardBridgeAdapter,
MessageStatus,
} from '../src'
const deployWETH9 = async (
hre: HardhatRuntimeEnvironment,
wrap: boolean
): Promise<Contract> => {
const signers = await hre.ethers.getSigners()
const signer = signers[0]
const Artifact__WETH9 = await hre.deployments.getArtifact('WETH9')
const Factory__WETH9 = new hre.ethers.ContractFactory(
Artifact__WETH9.abi,
Artifact__WETH9.bytecode,
signer
)
const WETH9 = await Factory__WETH9.deploy()
await WETH9.deployTransaction.wait()
if (wrap) {
const deposit = await signer.sendTransaction({
value: utils.parseEther('1'),
to: WETH9.address,
})
await deposit.wait()
}
return WETH9
}
const createOptimismMintableERC20 = async (
hre: HardhatRuntimeEnvironment,
L1ERC20: Contract,
l2Signer: Wallet
): Promise<Contract> => {
const Deployment__OptimismMintableERC20TokenFactory =
await hre.deployments.get('OptimismMintableERC20Factory')
const Artifact__OptimismMintableERC20Token =
await hre.deployments.getArtifact('OptimismMintableERC20')
const OptimismMintableERC20TokenFactory = await hre.ethers.getContractAt(
Deployment__OptimismMintableERC20TokenFactory.abi,
predeploys.OptimismMintableERC20Factory,
l2Signer
)
const name = await L1ERC20.name()
const symbol = await L1ERC20.symbol()
const tx =
await OptimismMintableERC20TokenFactory.createOptimismMintableERC20(
L1ERC20.address,
`L2 ${name}`,
`L2-${symbol}`
)
const receipt = await tx.wait()
const event = receipt.events.find(
(e: Event) => e.event === 'OptimismMintableERC20Created'
)
if (!event) {
throw new Error('Unable to find OptimismMintableERC20Created event')
}
// TODO(tynes): may need to be updated based on
// https://github.com/ethereum-optimism/optimism/pull/3104
const l2WethAddress = event.args.remoteToken
console.log(`Deployed to ${l2WethAddress}`)
const contract = new Contract(
l2WethAddress,
Artifact__OptimismMintableERC20Token.abi,
l2Signer
)
return contract
}
// TODO(tynes): this task could be modularized in the future
// so that it can deposit an arbitrary token. Right now it
// deploys a WETH9 contract, mints some WETH9 and then
// deposits that into L2 through the StandardBridge.
task('deposit-erc20', 'Deposits WETH9 onto L2.')
.addParam(
'l2ProviderUrl',
'L2 provider URL.',
'http://localhost:9545',
types.string
)
.addParam(
'opNodeProviderUrl',
'op-node provider URL',
'http://localhost:7545',
types.string
)
.setAction(async (args, hre) => {
const signers = await hre.ethers.getSigners()
if (signers.length === 0) {
throw new Error('No configured signers')
}
// Use the first configured signer for simplicity
const signer = signers[0]
const address = await signer.getAddress()
console.log(`Using signer ${address}`)
// Ensure that the signer has a balance before trying to
// do anything
const balance = await signer.getBalance()
if (balance.eq(0)) {
throw new Error('Signer has no balance')
}
const l2Provider = new providers.StaticJsonRpcProvider(args.l2ProviderUrl)
const l2Signer = new hre.ethers.Wallet(
hre.network.config.accounts[0],
l2Provider
)
const Deployment__L2OutputOracleProxy = await hre.deployments.get(
'L2OutputOracleProxy'
)
const Artifact__L2ToL1MessagePasser = await hre.deployments.getArtifact(
'L2ToL1MessagePasser'
)
const Artifact__L2CrossDomainMessenger = await hre.deployments.getArtifact(
'L2CrossDomainMessenger'
)
const Artifact__L2StandardBridge = await hre.deployments.getArtifact(
'L2StandardBridge'
)
const Deployment__OptimismPortal = await hre.deployments.get(
'OptimismPortal'
)
const Deployment__OptimismPortalProxy = await hre.deployments.get(
'OptimismPortalProxy'
)
const Deployment__L1StandardBridgeProxy = await hre.deployments.get(
'L1StandardBridgeProxy'
)
const Deployment__L1CrossDomainMessenger = await hre.deployments.get(
'L1CrossDomainMessenger'
)
const Deployment__L1CrossDomainMessengerProxy = await hre.deployments.get(
'L1CrossDomainMessengerProxy'
)
const Deployment__L1StandardBridge = await hre.deployments.get(
'L1StandardBridge'
)
const OptimismPortal = new hre.ethers.Contract(
Deployment__OptimismPortalProxy.address,
Deployment__OptimismPortal.abi,
signer
)
const L1CrossDomainMessenger = new hre.ethers.Contract(
Deployment__L1CrossDomainMessengerProxy.address,
Deployment__L1CrossDomainMessenger.abi,
signer
)
const L1StandardBridge = new hre.ethers.Contract(
Deployment__L1StandardBridgeProxy.address,
Deployment__L1StandardBridge.abi,
signer
)
const L2ToL1MessagePasser = new hre.ethers.Contract(
predeploys.L2ToL1MessagePasser,
Artifact__L2ToL1MessagePasser.abi
)
const L2CrossDomainMessenger = new hre.ethers.Contract(
predeploys.L2CrossDomainMessenger,
Artifact__L2CrossDomainMessenger.abi
)
const L2StandardBridge = new hre.ethers.Contract(
predeploys.L2StandardBridge,
Artifact__L2StandardBridge.abi
)
const messenger = new CrossChainMessenger({
l1SignerOrProvider: signer,
l2SignerOrProvider: l2Signer,
l1ChainId: await signer.getChainId(),
l2ChainId: await l2Signer.getChainId(),
bridges: {
Standard: {
Adapter: StandardBridgeAdapter,
l1Bridge: Deployment__L1StandardBridgeProxy.address,
l2Bridge: predeploys.L2StandardBridge,
},
},
contracts: {
l1: {
L1StandardBridge: Deployment__L1StandardBridgeProxy.address,
L1CrossDomainMessenger:
Deployment__L1CrossDomainMessengerProxy.address,
L2OutputOracle: Deployment__L2OutputOracleProxy.address,
OptimismPortal: Deployment__OptimismPortalProxy.address,
},
},
bedrock: true,
})
console.log('Deploying WETH9 to L1')
const WETH9 = await deployWETH9(hre, true)
console.log(`Deployed to ${WETH9.address}`)
console.log('Creating L2 WETH9')
const OptimismMintableERC20 = await createOptimismMintableERC20(
hre,
WETH9,
l2Signer
)
console.log(`Approving WETH9 for deposit`)
const approvalTx = await messenger.approveERC20(
WETH9.address,
OptimismMintableERC20.address,
hre.ethers.constants.MaxUint256
)
await approvalTx.wait()
console.log('WETH9 approved')
console.log('Depositing WETH9 to L2')
const depositTx = await messenger.depositERC20(
WETH9.address,
OptimismMintableERC20.address,
utils.parseEther('1')
)
await depositTx.wait()
console.log(`ERC20 deposited - ${depositTx.hash}`)
const messageReceipt = await messenger.waitForMessageReceipt(depositTx)
if (messageReceipt.receiptStatus !== 1) {
throw new Error('deposit failed')
}
const l2Balance = await OptimismMintableERC20.balanceOf(address)
if (l2Balance.lt(utils.parseEther('1'))) {
throw new Error('bad deposit')
}
console.log(
`Deposit success - ${messageReceipt.transactionReceipt.transactionHash}`
)
console.log('Starting withdrawal')
const preBalance = await WETH9.balanceOf(signer.address)
const withdraw = await messenger.withdrawERC20(
WETH9.address,
OptimismMintableERC20.address,
utils.parseEther('1')
)
const withdrawalReceipt = await withdraw.wait()
for (const log of withdrawalReceipt.logs) {
switch (log.address) {
case L2ToL1MessagePasser.address: {
const parsed = L2ToL1MessagePasser.interface.parseLog(log)
console.log(`Log ${parsed.name} from ${log.address}`)
console.log(parsed.args)
console.log()
break
}
case L2StandardBridge.address: {
const parsed = L2StandardBridge.interface.parseLog(log)
console.log(`Log ${parsed.name} from ${log.address}`)
console.log(parsed.args)
console.log()
break
}
case L2CrossDomainMessenger.address: {
const parsed = L2CrossDomainMessenger.interface.parseLog(log)
console.log(`Log ${parsed.name} from ${log.address}`)
console.log(parsed.args)
console.log()
break
}
default: {
console.log(`Unknown log from ${log.address} - ${log.topics[0]}`)
}
}
}
setInterval(async () => {
const currentStatus = await messenger.getMessageStatus(withdraw)
console.log(`Message status: ${MessageStatus[currentStatus]}`)
}, 3000)
const now = Math.floor(Date.now() / 1000)
console.log('Waiting for message to be able to be relayed')
await messenger.waitForMessageStatus(
withdraw,
MessageStatus.READY_FOR_RELAY
)
const finalize = await messenger.finalizeMessage(withdraw)
const receipt = await finalize.wait()
console.log(`Took ${Math.floor(Date.now() / 1000) - now} seconds`)
for (const log of receipt.logs) {
switch (log.address) {
case OptimismPortal.address: {
const parsed = OptimismPortal.interface.parseLog(log)
console.log(`Log ${parsed.name} from ${log.address}`)
console.log(parsed.args)
console.log()
break
}
case L1CrossDomainMessenger.address: {
const parsed = L1CrossDomainMessenger.interface.parseLog(log)
console.log(`Log ${parsed.name} from ${log.address}`)
console.log(parsed.args)
console.log()
break
}
case L1StandardBridge.address: {
const parsed = L1StandardBridge.interface.parseLog(log)
console.log(`Log ${parsed.name} from ${log.address}`)
console.log(parsed.args)
console.log()
break
}
default:
console.log(
`Unknown log emitted from ${log.address} - ${log.topics[0]}`
)
}
}
const postBalance = await WETH9.balanceOf(signer.address)
const expectedBalance = preBalance.add(utils.parseEther('1'))
if (!expectedBalance.eq(postBalance)) {
throw new Error('Balance mismatch')
}
console.log('Withdrawal success')
})
import { task, types } from 'hardhat/config' import { task, types } from 'hardhat/config'
import '@nomiclabs/hardhat-ethers' import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy' import 'hardhat-deploy'
import { import { predeploys } from '@eth-optimism/contracts-bedrock'
predeploys, import { providers, utils } from 'ethers'
getContractInterface,
} from '@eth-optimism/contracts-bedrock'
import { Event } from 'ethers'
import { import {
CrossChainMessenger, CrossChainMessenger,
...@@ -13,12 +10,7 @@ import { ...@@ -13,12 +10,7 @@ import {
MessageStatus, MessageStatus,
} from '../src' } from '../src'
// TODO(tynes): this task could be modularized in the future task('deposit-eth', 'Deposits WETH9 onto L2.')
// 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
// deposits that into L2 through the StandardBridge.
task('deposit', 'Deposits WETH9 onto L2.')
.addParam( .addParam(
'l2ProviderUrl', 'l2ProviderUrl',
'L2 provider URL.', 'L2 provider URL.',
...@@ -31,9 +23,21 @@ task('deposit', 'Deposits WETH9 onto L2.') ...@@ -31,9 +23,21 @@ task('deposit', 'Deposits WETH9 onto L2.')
'http://localhost:7545', 'http://localhost:7545',
types.string types.string
) )
.addOptionalParam('to', 'Recipient of the ether', '', types.string)
.addOptionalParam(
'amount',
'Amount of ether to send (in ETH)',
'',
types.string
)
.addOptionalParam(
'withdraw',
'Follow up with a withdrawal',
true,
types.boolean
)
.addOptionalParam('withdrawAmount', 'Amount to withdraw', '', types.string)
.setAction(async (args, hre) => { .setAction(async (args, hre) => {
const { utils } = hre.ethers
const signers = await hre.ethers.getSigners() const signers = await hre.ethers.getSigners()
if (signers.length === 0) { if (signers.length === 0) {
throw new Error('No configured signers') throw new Error('No configured signers')
...@@ -50,28 +54,37 @@ task('deposit', 'Deposits WETH9 onto L2.') ...@@ -50,28 +54,37 @@ task('deposit', 'Deposits WETH9 onto L2.')
throw new Error('Signer has no balance') throw new Error('Signer has no balance')
} }
const l2Provider = new hre.ethers.providers.StaticJsonRpcProvider( const l2Provider = new providers.StaticJsonRpcProvider(args.l2ProviderUrl)
args.l2ProviderUrl
)
const Deployment__L2OutputOracleProxy = await hre.deployments.get( const Deployment__L2OutputOracleProxy = await hre.deployments.get(
'L2OutputOracleProxy' 'L2OutputOracleProxy'
) )
// send to self if not specified
const to = args.to ? args.to : address
const amount = args.amount
? utils.parseEther(args.amount)
: utils.parseEther('1')
const withdrawAmount = args.withdrawAmount
? utils.parseEther(args.withdrawAmount)
: utils.parseEther(amount.div(2).toString())
const l2Signer = new hre.ethers.Wallet( const l2Signer = new hre.ethers.Wallet(
hre.network.config.accounts[0], hre.network.config.accounts[0],
l2Provider l2Provider
) )
const Artifact__WETH9 = await hre.deployments.getArtifact('WETH9') const Artifact__L2ToL1MessagePasser = await hre.deployments.getArtifact(
const Factory__WETH9 = new hre.ethers.ContractFactory( 'L2ToL1MessagePasser'
Artifact__WETH9.abi,
Artifact__WETH9.bytecode,
signer
) )
const Deployment__OptimismMintableERC20TokenFactory = const Artifact__L2CrossDomainMessenger = await hre.deployments.getArtifact(
await hre.deployments.get('OptimismMintableERC20Factory') 'L2CrossDomainMessenger'
)
const Artifact__L2StandardBridge = await hre.deployments.getArtifact(
'L2StandardBridge'
)
const Deployment__OptimismPortal = await hre.deployments.get( const Deployment__OptimismPortal = await hre.deployments.get(
'OptimismPortal' 'OptimismPortal'
...@@ -85,16 +98,51 @@ task('deposit', 'Deposits WETH9 onto L2.') ...@@ -85,16 +98,51 @@ task('deposit', 'Deposits WETH9 onto L2.')
'L1StandardBridgeProxy' 'L1StandardBridgeProxy'
) )
const Deployment__L1CrossDomainMessenger = await hre.deployments.get(
'L1CrossDomainMessenger'
)
const Deployment__L1CrossDomainMessengerProxy = await hre.deployments.get( const Deployment__L1CrossDomainMessengerProxy = await hre.deployments.get(
'L1CrossDomainMessengerProxy' 'L1CrossDomainMessengerProxy'
) )
const Deployment__L1StandardBridge = await hre.deployments.get(
'L1StandardBridge'
)
const OptimismPortal = new hre.ethers.Contract( const OptimismPortal = new hre.ethers.Contract(
Deployment__OptimismPortalProxy.address, Deployment__OptimismPortalProxy.address,
Deployment__OptimismPortal.abi, Deployment__OptimismPortal.abi,
signer signer
) )
const L1CrossDomainMessenger = new hre.ethers.Contract(
Deployment__L1CrossDomainMessengerProxy.address,
Deployment__L1CrossDomainMessenger.abi,
signer
)
const L1StandardBridge = new hre.ethers.Contract(
Deployment__L1StandardBridgeProxy.address,
Deployment__L1StandardBridge.abi,
signer
)
const L2ToL1MessagePasser = new hre.ethers.Contract(
predeploys.L2ToL1MessagePasser,
Artifact__L2ToL1MessagePasser.abi
)
const L2CrossDomainMessenger = new hre.ethers.Contract(
predeploys.L2CrossDomainMessenger,
Artifact__L2CrossDomainMessenger.abi
)
const L2StandardBridge = new hre.ethers.Contract(
predeploys.L2StandardBridge,
Artifact__L2StandardBridge.abi
)
const messenger = new CrossChainMessenger({ const messenger = new CrossChainMessenger({
l1SignerOrProvider: signer, l1SignerOrProvider: signer,
l2SignerOrProvider: l2Signer, l2SignerOrProvider: l2Signer,
...@@ -125,30 +173,72 @@ task('deposit', 'Deposits WETH9 onto L2.') ...@@ -125,30 +173,72 @@ task('deposit', 'Deposits WETH9 onto L2.')
// Deposit ETH // Deposit ETH
console.log('Depositing ETH through StandardBridge') console.log('Depositing ETH through StandardBridge')
const ethDeposit = await messenger.depositETH(utils.parseEther('1')) const ethDeposit = await messenger.depositETH(amount, { recipient: to })
const depositMessageReceipt = await messenger.waitForMessageReceipt( const depositMessageReceipt = await messenger.waitForMessageReceipt(
ethDeposit ethDeposit
) )
if (depositMessageReceipt.receiptStatus !== 1) { if (depositMessageReceipt.receiptStatus !== 1) {
throw new Error('deposit failed') throw new Error('deposit failed')
} }
console.log('Deposit complete') console.log(
`Deposit complete - ${depositMessageReceipt.transactionReceipt.transactionHash}`
)
const opBalanceAfter = await signer.provider.getBalance( const opBalanceAfter = await signer.provider.getBalance(
OptimismPortal.address OptimismPortal.address
) )
if (!opBalanceBefore.add(utils.parseEther('1')).eq(opBalanceAfter)) { if (!opBalanceBefore.add(amount).eq(opBalanceAfter)) {
throw new Error(`OptimismPortal balance mismatch`) throw new Error(`OptimismPortal balance mismatch`)
} }
if (!args.withdraw) {
return
}
console.log('Withdrawing ETH') console.log('Withdrawing ETH')
const ethWithdraw = await messenger.withdrawETH(utils.parseEther('1')) const ethWithdraw = await messenger.withdrawETH(withdrawAmount)
const ethWithdrawReceipt = await ethWithdraw.wait() const ethWithdrawReceipt = await ethWithdraw.wait()
console.log('Withdrawal on L2 complete') console.log(`ETH withdrawn on L2 - ${ethWithdrawReceipt.transactionHash}`)
console.log('Waiting to be able to withdraw')
{
// check the logs
for (const log of ethWithdrawReceipt.logs) {
switch (log.address) {
case L2ToL1MessagePasser.address: {
const parsed = L2ToL1MessagePasser.interface.parseLog(log)
console.log(parsed.name)
console.log(parsed.args)
console.log()
break
}
case L2StandardBridge.address: {
const parsed = L2StandardBridge.interface.parseLog(log)
console.log(parsed.name)
console.log(parsed.args)
console.log()
break
}
case L2CrossDomainMessenger.address: {
const parsed = L2CrossDomainMessenger.interface.parseLog(log)
console.log(parsed.name)
console.log(parsed.args)
console.log()
break
}
default: {
console.log(`Unknown log from ${log.address} - ${log.topics[0]}`)
}
}
}
}
const id = setInterval(async () => { console.log(
`Withdrawal on L2 complete: ${ethWithdrawReceipt.transactionHash}`
)
console.log('Waiting to be able to withdraw')
setInterval(async () => {
const currentStatus = await messenger.getMessageStatus(ethWithdrawReceipt) const currentStatus = await messenger.getMessageStatus(ethWithdrawReceipt)
console.log(`Message status: ${MessageStatus[currentStatus]}`) console.log(`Message status: ${MessageStatus[currentStatus]}`)
}, 3000) }, 3000)
...@@ -157,128 +247,80 @@ task('deposit', 'Deposits WETH9 onto L2.') ...@@ -157,128 +247,80 @@ task('deposit', 'Deposits WETH9 onto L2.')
ethWithdrawReceipt, ethWithdrawReceipt,
MessageStatus.READY_FOR_RELAY MessageStatus.READY_FOR_RELAY
) )
clearInterval(id)
const ethFinalize = await messenger.finalizeMessage(ethWithdrawReceipt) const ethFinalize = await messenger.finalizeMessage(ethWithdrawReceipt)
const ethFinalizeReceipt = await ethFinalize.wait() const ethFinalizeReceipt = await ethFinalize.wait()
if (ethFinalizeReceipt.status !== 1) { if (ethFinalizeReceipt.status !== 1) {
throw new Error('Finalize withdrawal reverted') throw new Error('Finalize withdrawal reverted')
} }
console.log('ETH withdrawal complete')
console.log(
`ETH withdrawal complete: ${ethFinalizeReceipt.transactionHash}`
)
{
// Check that the logs are correct
for (const log of ethFinalizeReceipt.logs) {
switch (log.address) {
case L1StandardBridge.address: {
const parsed = L1StandardBridge.interface.parseLog(log)
console.log(parsed.name)
console.log(parsed.args)
console.log()
if (parsed.name !== 'ETHBridgeFinalized') {
throw new Error('Wrong event name from L1StandardBridge')
}
if (!parsed.args.amount.eq(withdrawAmount)) {
throw new Error('Wrong amount in event')
}
if (parsed.args.from !== address) {
throw new Error('Wrong to in event')
}
if (parsed.args.to !== address) {
throw new Error('Wrong from in event')
}
break
}
case L1CrossDomainMessenger.address: {
const parsed = L1CrossDomainMessenger.interface.parseLog(log)
console.log(parsed.name)
console.log(parsed.args)
console.log()
if (parsed.name !== 'RelayedMessage') {
throw new Error('Wrong event from L1CrossDomainMessenger')
}
break
}
case OptimismPortal.address: {
const parsed = OptimismPortal.interface.parseLog(log)
console.log(parsed.name)
console.log(parsed.args)
console.log()
// TODO: remove this if check
if (parsed.name === 'WithdrawalFinalized') {
if (parsed.args.success !== true) {
throw new Error('Unsuccessful withdrawal call')
}
}
break
}
default: {
console.log(`Unknown log from ${log.address} - ${log.topics[0]}`)
}
}
}
}
const opBalanceFinally = await signer.provider.getBalance( const opBalanceFinally = await signer.provider.getBalance(
OptimismPortal.address OptimismPortal.address
) )
// TODO(tynes): fix this bug // TODO(tynes): fix this bug
if (!opBalanceFinally.eq(opBalanceBefore)) { if (!opBalanceFinally.sub(withdrawAmount).eq(opBalanceAfter)) {
console.log('OptimismPortal balance mismatch') console.log('OptimismPortal balance mismatch')
console.log(`Balance before deposit: ${opBalanceBefore.toString()}`) console.log(`Balance before deposit: ${opBalanceBefore.toString()}`)
console.log(`Balance after deposit: ${opBalanceAfter.toString()}`) console.log(`Balance after deposit: ${opBalanceAfter.toString()}`)
console.log(`Balance after withdrawal: ${opBalanceFinally.toString()}`) console.log(`Balance after withdrawal: ${opBalanceFinally.toString()}`)
return
// throw new Error('OptimismPortal balance mismatch') // throw new Error('OptimismPortal balance mismatch')
} }
console.log('Withdraw success')
const OptimismMintableERC20TokenFactory = await hre.ethers.getContractAt(
Deployment__OptimismMintableERC20TokenFactory.abi,
predeploys.OptimismMintableERC20Factory,
l2Signer
)
console.log('Deploying WETH9 to L1')
const WETH9 = await Factory__WETH9.deploy()
await WETH9.deployTransaction.wait()
console.log(`Deployed to ${WETH9.address}`)
console.log('Creating L2 WETH9')
const deployTx =
await OptimismMintableERC20TokenFactory.createOptimismMintableERC20(
WETH9.address,
'L2 Wrapped Ether',
'L2-WETH9'
)
const receipt = await deployTx.wait()
const event = receipt.events.find(
(e: Event) => e.event === 'OptimismMintableERC20Created'
)
if (!event) {
throw new Error('Unable to find OptimismMintableERC20Created event')
}
// TODO(tynes): may need to be updated based on
// https://github.com/ethereum-optimism/optimism/pull/3104
const l2WethAddress = event.args.remoteToken
console.log(`Deployed to ${l2WethAddress}`)
console.log('Wrapping ETH')
const deposit = await signer.sendTransaction({
value: utils.parseEther('1'),
to: WETH9.address,
})
await deposit.wait()
console.log('ETH wrapped')
console.log(`Approving WETH9 for deposit`)
const approvalTx = await messenger.approveERC20(
WETH9.address,
l2WethAddress,
hre.ethers.constants.MaxUint256
)
await approvalTx.wait()
console.log('WETH9 approved')
console.log('Depositing WETH9 to L2')
const depositTx = await messenger.depositERC20(
WETH9.address,
l2WethAddress,
utils.parseEther('1')
)
await depositTx.wait()
console.log('ERC20 deposited')
const messageReceipt = await messenger.waitForMessageReceipt(depositTx)
if (messageReceipt.receiptStatus !== 1) {
throw new Error('deposit failed')
}
const L2WETH9 = new hre.ethers.Contract(
l2WethAddress,
getContractInterface('OptimismMintableERC20'),
l2Signer
)
const l2Balance = await L2WETH9.balanceOf(await signer.getAddress())
if (l2Balance.lt(utils.parseEther('1'))) {
throw new Error('bad deposit')
}
console.log('Deposit success')
console.log('Starting withdrawal')
const preBalance = await WETH9.balanceOf(signer.address)
const tx = await messenger.withdrawERC20(
WETH9.address,
l2WethAddress,
utils.parseEther('1')
)
await tx.wait()
setInterval(async () => {
const currentStatus = await messenger.getMessageStatus(tx)
console.log(`Message status: ${MessageStatus[currentStatus]}`)
}, 3000)
const now = Math.floor(Date.now() / 1000)
console.log('Waiting for message to be able to be relayed')
await messenger.waitForMessageStatus(tx, MessageStatus.READY_FOR_RELAY)
const finalize = await messenger.finalizeMessage(tx)
await finalize.wait()
console.log(`Took ${Math.floor(Date.now() / 1000) - now} seconds`)
const postBalance = await WETH9.balanceOf(signer.address)
const expectedBalance = preBalance.add(utils.parseEther('1'))
if (!expectedBalance.eq(postBalance)) {
throw new Error('Balance mismatch')
}
console.log('Withdrawal success')
}) })
import './deposit-eth'
import './deposit-erc20'
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