From 3517ddb565fdee4a232298fa19556b5e046fae32 Mon Sep 17 00:00:00 2001 From: Mark Tyneway Date: Thu, 28 Jul 2022 16:16:45 -0700 Subject: [PATCH] more fixes --- packages/sdk/hardhat.config.ts | 22 ++ packages/sdk/package.json | 1 + packages/sdk/src/adapters/standard-bridge.ts | 4 +- packages/sdk/src/cross-chain-messenger.ts | 2 +- packages/sdk/tasks/deposit.ts | 199 +++++++++++++++++++ packages/sdk/tsconfig.json | 5 +- 6 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 packages/sdk/tasks/deposit.ts diff --git a/packages/sdk/hardhat.config.ts b/packages/sdk/hardhat.config.ts index aeea1c1de447..6d3290f54cf1 100644 --- a/packages/sdk/hardhat.config.ts +++ b/packages/sdk/hardhat.config.ts @@ -2,6 +2,9 @@ import { HardhatUserConfig } from 'hardhat/types' import '@nomiclabs/hardhat-ethers' import '@nomiclabs/hardhat-waffle' +import 'hardhat-deploy' + +import './tasks/deposit' const config: HardhatUserConfig = { solidity: { @@ -10,6 +13,25 @@ const config: HardhatUserConfig = { paths: { sources: './test/contracts', }, + networks: { + devnetL1: { + url: 'http://localhost:8545', + accounts: [ + 'ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', + ], + }, + }, + external: { + contracts: [ + { + artifacts: '../contracts-bedrock/artifacts', + }, + ], + deployments: { + devnetL1: ['../contracts-bedrock/deployments/devnetL1'], + goerli: ['../contracts-bedrock/deployments/goerli'], + }, + }, } export default config diff --git a/packages/sdk/package.json b/packages/sdk/package.json index df86928dcc95..51584ec2f566 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -41,6 +41,7 @@ "ethereum-waffle": "^3.4.0", "ethers": "^5.6.8", "hardhat": "^2.9.6", + "hardhat-deploy": "^0.11.4", "nyc": "^15.1.0", "typedoc": "^0.22.13", "mocha": "^10.0.0" diff --git a/packages/sdk/src/adapters/standard-bridge.ts b/packages/sdk/src/adapters/standard-bridge.ts index 0ad1606e532b..22d9a7d562cd 100644 --- a/packages/sdk/src/adapters/standard-bridge.ts +++ b/packages/sdk/src/adapters/standard-bridge.ts @@ -160,7 +160,6 @@ export class StandardBridgeAdapter implements IBridgeAdapter { getContractInterface('OptimismMintableERC20'), this.messenger.l2Provider ) - // Don't support ETH deposits or withdrawals via this bridge. if ( hexStringEquals(toAddress(l1Token), ethers.constants.AddressZero) || @@ -171,6 +170,7 @@ export class StandardBridgeAdapter implements IBridgeAdapter { // Make sure the L1 token matches. const remoteL1Token = await contract.l1Token() + if (!hexStringEquals(remoteL1Token, toAddress(l1Token))) { return false } @@ -271,7 +271,7 @@ export class StandardBridgeAdapter implements IBridgeAdapter { const token = new Contract( toAddress(l1Token), - getContractInterface('L2StandardERC20'), // Any ERC20 will do + getContractInterface('OptimismMintableERC20'), // Any ERC20 will do this.messenger.l1Provider ) diff --git a/packages/sdk/src/cross-chain-messenger.ts b/packages/sdk/src/cross-chain-messenger.ts index 1664a2d85ae0..87ed5fb08213 100644 --- a/packages/sdk/src/cross-chain-messenger.ts +++ b/packages/sdk/src/cross-chain-messenger.ts @@ -730,7 +730,7 @@ export class CrossChainMessenger implements ICrossChainMessenger { // TODO: Handle old messages from before Bedrock upgrade. const events = await this.contracts.l1.L2OutputOracle.queryFilter( - this.contracts.l1.L2OutputOracle.filters.L2OutputAppended( + this.contracts.l1.L2OutputOracle.filters.OutputProposed( undefined, undefined, Math.ceil( diff --git a/packages/sdk/tasks/deposit.ts b/packages/sdk/tasks/deposit.ts new file mode 100644 index 000000000000..69b449c1e0ca --- /dev/null +++ b/packages/sdk/tasks/deposit.ts @@ -0,0 +1,199 @@ +import { task, types } from 'hardhat/config' +import '@nomiclabs/hardhat-ethers' +import 'hardhat-deploy' +import { + predeploys, + getContractInterface, +} from '@eth-optimism/contracts-bedrock' +import { Event } from 'ethers' + +import { + CrossChainMessenger, + StandardBridgeAdapter, + MessageStatus, +} from '../src' + +task('deposit', 'Deposits funds onto L2.') + .addParam( + 'l1ProviderUrl', + 'L1 provider URL.', + 'http://localhost:8545', + types.string + ) + .addParam( + 'l2ProviderUrl', + 'L2 provider URL.', + 'http://localhost:9545', + types.string + ) + /* + .addParam('to', 'Recipient address.', null, types.string) + .addParam('amountEth', 'Amount in ETH to send.', null, 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}`) + + { + const balance = await signer.getBalance() + if (balance.eq(0)) { + throw new Error('Signer has no balance') + } + } + + const l2Provider = new hre.ethers.providers.JsonRpcProvider( + args.l2ProviderUrl + ) + const l2Signer = new hre.ethers.Wallet( + hre.network.config.accounts[0], + l2Provider + ) + + const Artifact__WETH9 = await hre.deployments.getArtifact('WETH9') + const Factory__WETH9 = new hre.ethers.ContractFactory( + Artifact__WETH9.abi, + Artifact__WETH9.bytecode, + signer + ) + + console.log('Deploying WETH9') + const WETH9 = await Factory__WETH9.deploy() + await WETH9.deployTransaction.wait() + console.log(`Deployed to ${WETH9.address}`) + + const Deployment__OptimismMintableERC20TokenFactory = + await hre.deployments.get('OptimismMintableERC20Factory') + console.log( + `OptimismMintableERC20Factory address ${Deployment__OptimismMintableERC20TokenFactory.address}` + ) + + const Deployment__L1StandardBridgeProxy = await hre.deployments.get( + 'L1StandardBridgeProxy' + ) + + const Deployment__L1CrossDomainMessengerProxy = await hre.deployments.get( + 'L1CrossDomainMessengerProxy' + ) + + const OptimismMintableERC20TokenFactory = await hre.ethers.getContractAt( + Deployment__OptimismMintableERC20TokenFactory.abi, + predeploys.OptimismMintableERC20Factory, + l2Signer + ) + + let l2WethAddress: string + { + 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: update this when bugfix is merged + l2WethAddress = event.args.remoteToken + } + console.log(`L2 WETH9 deployed to ${l2WethAddress}`) + + { + console.log('Wrapping ETH') + const deposit = await signer.sendTransaction({ + value: hre.ethers.utils.parseEther('1'), + to: WETH9.address, + }) + await deposit.wait() + + const balance = await WETH9.balanceOf(address) + console.log(`${address} has ${balance.toString()}`) + } + + 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, + }, + }, + bedrock: true, + }) + + { + console.log(`Approving WETH9`) + const approvalTx = await messenger.approveERC20( + WETH9.address, + l2WethAddress, + hre.ethers.constants.MaxUint256 + ) + await approvalTx.wait() + console.log('WETH9 approved') + } + + { + console.log('Depositing ERC20') + const depositTx = await messenger.depositERC20( + WETH9.address, + l2WethAddress, + hre.ethers.utils.parseEther('1') + ) + await depositTx.wait() + console.log('ERC20 deposited') + + const receipt = await messenger.waitForMessageReceipt(tx) + if (receipt.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(hre.ethers.utils.parseEther('1'))) { + throw new Error('bad deposit') + } + console.log('Deposit success') + } + + console.log('Starting withdrawal') + + const tx = await messenger.withdrawERC20( + WETH9.address, + l2WethAddress, + hre.ethers.utils.parseEther('1') + ) + await tx.wait() + + console.log('Waiting for message to be able to be relayed') + await messenger.waitForMessageStatus(tx, MessageStatus.READY_FOR_RELAY) + + // TODO: how to wait until the state root has been posted? + const finalize = await messenger.finalizeMessage(tx) + console.log(finalize) + }) diff --git a/packages/sdk/tsconfig.json b/packages/sdk/tsconfig.json index a58b672ec1f6..4374e026d976 100644 --- a/packages/sdk/tsconfig.json +++ b/packages/sdk/tsconfig.json @@ -1,11 +1,10 @@ { "extends": "../../tsconfig.json", - "compilerOptions": { "rootDir": "./src", - "outDir": "./dist" + "outDir": "./dist", + "resolveJsonModule": true }, - "include": [ "src/**/*" ]