From 59c28114b7619c7dc082ad367a6e6297636d5cba Mon Sep 17 00:00:00 2001 From: zkJoaquin <158016937+zkJoaquin@users.noreply.github.com> Date: Thu, 21 Mar 2024 10:34:09 +0800 Subject: [PATCH] optimize op stack series example scripts (#83) * optimize the optimism example * optimize the manta example * optimize the base example * lint fix * optimize syncBatchRoot and syncL2Requests case * optimize blast example * update the manta network config * update the blast example * update the manta config * optimize tx params --- examples/base/hardhat.config.js | 5 +- examples/base/scripts/baseTasks.js | 129 +++++++ examples/base/scripts/changeFeeParams.js | 124 ------- examples/base/scripts/setValidator.js | 140 -------- examples/base/scripts/syncBatchRoot.js | 109 ------ examples/base/scripts/syncL2Requests.js | 131 ------- examples/blast/hardhat.config.js | 5 +- examples/blast/scripts/blastTasks.js | 273 ++++++++++++++ examples/blast/scripts/changeFeeParams.js | 161 --------- examples/blast/scripts/constants.js | 5 + examples/blast/scripts/contractABIs.json | 63 ++++ examples/blast/scripts/setValidator.js | 173 --------- examples/blast/scripts/syncBatchRoot.js | 122 ------- examples/blast/scripts/syncL2Requests.js | 96 ----- examples/manta/.env-sample | 6 +- examples/manta/hardhat.config.js | 5 +- examples/manta/scripts/changeFeeParams.js | 109 ------ examples/manta/scripts/constants.js | 28 ++ examples/manta/scripts/mantaTasks.js | 116 ++++++ examples/manta/scripts/setValidator.js | 114 ------ examples/manta/scripts/syncBatchRoot.js | 119 ------- examples/manta/scripts/syncL2Requests.js | 127 ------- examples/optimism/hardhat.config.js | 5 +- examples/optimism/scripts/changeFeeParams.js | 100 ------ examples/optimism/scripts/optimismTasks.js | 108 ++++++ examples/optimism/scripts/setValidator.js | 105 ------ examples/optimism/scripts/syncBatchRoot.js | 110 ------ examples/optimism/scripts/syncL2Requests.js | 96 ----- examples/utils/opstack-utils.js | 353 +++++++++++++++++++ script/ChainConfig.json | 4 +- 30 files changed, 1084 insertions(+), 1957 deletions(-) create mode 100644 examples/base/scripts/baseTasks.js delete mode 100644 examples/base/scripts/changeFeeParams.js delete mode 100644 examples/base/scripts/setValidator.js delete mode 100644 examples/base/scripts/syncBatchRoot.js delete mode 100644 examples/base/scripts/syncL2Requests.js create mode 100644 examples/blast/scripts/blastTasks.js delete mode 100644 examples/blast/scripts/changeFeeParams.js delete mode 100644 examples/blast/scripts/setValidator.js delete mode 100644 examples/blast/scripts/syncBatchRoot.js delete mode 100644 examples/blast/scripts/syncL2Requests.js delete mode 100644 examples/manta/scripts/changeFeeParams.js create mode 100644 examples/manta/scripts/constants.js create mode 100644 examples/manta/scripts/mantaTasks.js delete mode 100644 examples/manta/scripts/setValidator.js delete mode 100644 examples/manta/scripts/syncBatchRoot.js delete mode 100644 examples/manta/scripts/syncL2Requests.js delete mode 100644 examples/optimism/scripts/changeFeeParams.js create mode 100644 examples/optimism/scripts/optimismTasks.js delete mode 100644 examples/optimism/scripts/setValidator.js delete mode 100644 examples/optimism/scripts/syncBatchRoot.js delete mode 100644 examples/optimism/scripts/syncL2Requests.js create mode 100644 examples/utils/opstack-utils.js diff --git a/examples/base/hardhat.config.js b/examples/base/hardhat.config.js index ef15cb5..c7d1ff6 100644 --- a/examples/base/hardhat.config.js +++ b/examples/base/hardhat.config.js @@ -1,8 +1,5 @@ require('@nomiclabs/hardhat-ethers'); -require('./scripts/syncL2Requests'); -require('./scripts/syncBatchRoot'); -require('./scripts/setValidator'); -require('./scripts/changeFeeParams'); +require('./scripts/baseTasks'); const BaseConfig = require('../../hardhat.base.config'); diff --git a/examples/base/scripts/baseTasks.js b/examples/base/scripts/baseTasks.js new file mode 100644 index 0000000..e200e4a --- /dev/null +++ b/examples/base/scripts/baseTasks.js @@ -0,0 +1,129 @@ +const base = require('@eth-optimism/sdk'); +const ethers = require('ethers'); +const { + syncBatchRoot, + syncL2Requests, + setValidator, + changeFeeParams, + encodeSetValidator, + encodeChangeFeeParams, +} = require('../../utils/opstack-utils'); +const { L1_MAINNET_CONTRACTS, L1_TESTNET_CONTRACTS } = require('./constants'); +const { task, types } = require('hardhat/config'); +require('dotenv').config(); + +async function initMessenger() { + const walletPrivateKey = process.env.DEVNET_PRIVKEY; + const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); + const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); + const ethereumName = process.env.ETHEREUM; + const baseName = process.env.BASE; + const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); + const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); + + const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; + const messenger = new base.CrossChainMessenger({ + l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum + l2ChainId: await l2Wallet.getChainId(), // 84532 for Base Sepolia, 8453 for Base Mainnet + l1SignerOrProvider: l1Wallet, + l2SignerOrProvider: l2Wallet, + bedrock: true, + contracts: { + l1: messengerL1Contracts, + }, + }); + + return { messenger, ethereumName, baseName }; +} + +task('syncBatchRoot', 'Forward message to L2').setAction(async (_, hre) => { + const { messenger, ethereumName, baseName } = await initMessenger(); + + const l2Wallet = messenger.l2Signer; + const l2CurrentBlock = await l2Wallet.provider.getBlockNumber(); + console.log(`Current block on l2: ${l2CurrentBlock}`); + + const message = await syncBatchRoot(hre, messenger, ethereumName, baseName, 'base'); + // Waiting for the official base bridge to forward the message to L2 + await messenger.waitForMessageStatus(message, base.MessageStatus.RELAYED); + const rec = await messenger.getMessageReceipt(message, 0, l2CurrentBlock, 'latest'); + console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); + console.log('Done'); + + // Example txs: + // https://sepolia.etherscan.io/tx/0x00524d9723521e7459581e34013e9a28b5b6d8c4566c3e0b23b2f5fa1726741a + // https://sepolia.basescan.org/tx/0xcca496f9fa90e776e6d8e696f12a67c639e0786dab9c84628e039ad5af22bcf7 +}); + +task('syncL2Requests', 'Send sync point to arbitrator') + .addParam('txs', 'New sync point', 100, types.int, true) + .setAction(async (taskArgs, hre) => { + const txs = taskArgs.txs; + console.log(`The sync point: txs: ${txs}`); + + const { messenger, ethereumName, baseName } = await initMessenger(); + + await syncL2Requests(hre, messenger, ethereumName, baseName, 'base', txs); + + console.log('Done!'); + + // Example txs: + // https://sepolia.basescan.org/tx/0x5ae6195c0b103bee7fbfb855bf23e9afde809ea2527fa9b0209c63038627959b + // https://sepolia.etherscan.io/tx/0xb1b968732830a8c0481cecf0a85fdcb3950b2841819154ab4e366c3ee7770834 + }); + +task('setValidator', 'Set validator for zkLink') + .addParam('validator', 'Validator Address', undefined, types.string) + .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) + .setAction(async (taskArgs, hre) => { + const validatorAddr = taskArgs.validator; + const isActive = taskArgs.active; + console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); + + const { messenger, ethereumName, baseName } = await initMessenger(); + + const l2Wallet = messenger.l2Signer; + const l2CurrentBlock = await l2Wallet.provider.getBlockNumber(); + console.log(`Current block on l2: ${l2CurrentBlock}`); + + const message = await setValidator(hre, messenger, ethereumName, baseName, 'base', validatorAddr, isActive); + // Waiting for the official base bridge to forward the message to L2 + await messenger.waitForMessageStatus(message, base.MessageStatus.RELAYED); + const rec = await messenger.getMessageReceipt(message, 0, l2CurrentBlock, 'latest'); + console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); + console.log('Done'); + }); + +task('changeFeeParams', 'Change fee params for zkLink').setAction(async (_, hre) => { + const { messenger, ethereumName, baseName } = await initMessenger(); + + const l2Wallet = messenger.l2Signer; + const l2CurrentBlock = await l2Wallet.provider.getBlockNumber(); + console.log(`Current block on l2: ${l2CurrentBlock}`); + + const message = await changeFeeParams(hre, messenger, ethereumName, baseName, 'base'); + // Waiting for the official base bridge to forward the message to L2 + await messenger.waitForMessageStatus(message, base.MessageStatus.RELAYED); + const rec = await messenger.getMessageReceipt(message, 0, l2CurrentBlock, 'latest'); + console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); + console.log('Done'); +}); + +task('encodeChangeFeeParams', 'Get the calldata of changing fee params for zkLink').setAction(async (_, hre) => { + const { messenger, ethereumName, baseName } = await initMessenger(); + + await encodeChangeFeeParams(hre, messenger, ethereumName, baseName, 'base'); +}); + +task('encodeSetValidator', 'Get the calldata of set validator for zkLink') + .addParam('validator', 'Validator Address', undefined, types.string) + .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) + .setAction(async (taskArgs, hre) => { + const validatorAddr = taskArgs.validator; + const isActive = taskArgs.active; + console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); + + const { messenger, ethereumName, baseName } = await initMessenger(); + + await encodeSetValidator(hre, messenger, ethereumName, baseName, 'base', validatorAddr, isActive); + }); diff --git a/examples/base/scripts/changeFeeParams.js b/examples/base/scripts/changeFeeParams.js deleted file mode 100644 index 4fb68bf..0000000 --- a/examples/base/scripts/changeFeeParams.js +++ /dev/null @@ -1,124 +0,0 @@ -const base = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { INIT_FEE_PARAMS } = require('../../../script/zksync_era'); -const { L1_MAINNET_CONTRACTS, L1_TESTNET_CONTRACTS } = require('./constants'); -const { task } = require('hardhat/config'); -require('dotenv').config(); - -async function preProcess(hre) { - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const ethereumName = process.env.ETHEREUM; - const baseName = process.env.BASE; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - - const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; - const messenger = new base.CrossChainMessenger({ - l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: await l2Wallet.getChainId(), // 84532 for Base Sepolia, 8453 for Base Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - bedrock: true, - contracts: { - l1: messengerL1Contracts, - }, - }); - - const l1WalletAddress = await l1Wallet.getAddress(); - const l1WalletBalance = ethers.utils.formatEther(await l1Wallet.getBalance()); - console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); - - const arbitratorAddr = readDeployContract( - logName.DEPLOY_ARBITRATOR_LOG_PREFIX, - logName.DEPLOY_LOG_ARBITRATOR, - ethereumName, - ); - if (arbitratorAddr === undefined) { - console.log('The arbitrator address not exist'); - return; - } - console.log(`The arbitrator address: ${arbitratorAddr}`); - - const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, baseName); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, baseName); - const baseL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (baseL1GatewayAddr === undefined) { - console.log('base l1 gateway address not exist'); - return; - } - console.log(`The base l1 gateway address: ${baseL1GatewayAddr}`); - - const baseL2GatewayAddr = readDeployContract(logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, logName.DEPLOY_GATEWAY, baseName); - if (baseL2GatewayAddr === undefined) { - console.log('base l2 gateway address not exist'); - return; - } - console.log(`The base l2 gateway address: ${baseL2GatewayAddr}`); - - // pre-execution calldata - const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); - const executeCalldata = zkLink.interface.encodeFunctionData('changeFeeParams', [INIT_FEE_PARAMS]); - console.log(`The call data: ${executeCalldata}`); - const gateway = await hre.ethers.getContractAt('OptimismGateway', baseL2GatewayAddr, l2Wallet); - const sendData = gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 1, // L2_TO_L1, Estimating the Gas Required on L2 - target: baseL2GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - - // forward message to L2 - const arbitrator = await hre.ethers.getContractAt('Arbitrator', arbitratorAddr, l1Wallet); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - console.log(`The adapter params: ${adapterParams}`); - - return { - messenger, - arbitrator, - baseL1GatewayAddr, - adapterParams, - }; -} - -task('changeFeeParams', 'Change fee params for zkLink').setAction(async (_, hre) => { - const { messenger, arbitrator, baseL1GatewayAddr, adapterParams } = await preProcess(hre); - - console.log('Prepare to forward the message to L2...'); - let tx = await arbitrator.changeFeeParams(baseL1GatewayAddr, INIT_FEE_PARAMS, adapterParams); - const txHash = tx.hash; - console.log(`The tx hash: ${txHash}`); - await tx.wait(); - console.log(`The transaction has been executed on L1`); - - /** - * Query the message informations on L1 via txHash. - */ - const message = (await messenger.getMessagesByTransaction(txHash)).pop(); - // Waiting for the official base bridge to forward the message to L2 - const rec = await messenger.waitForMessageReceipt(message); - console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); - console.log('Done'); -}); - -task('encodeChangeFeeParams', 'Get the calldata of changing fee params for zkLink').setAction(async (_, hre) => { - const { arbitrator, baseL1GatewayAddr, adapterParams } = await preProcess(hre); - - const calldata = arbitrator.interface.encodeFunctionData('changeFeeParams', [ - baseL1GatewayAddr, - INIT_FEE_PARAMS, - adapterParams, - ]); - console.log(`The changeFeeParams calldata: ${calldata}`); -}); diff --git a/examples/base/scripts/setValidator.js b/examples/base/scripts/setValidator.js deleted file mode 100644 index dfcf324..0000000 --- a/examples/base/scripts/setValidator.js +++ /dev/null @@ -1,140 +0,0 @@ -const base = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { L1_MAINNET_CONTRACTS, L1_TESTNET_CONTRACTS } = require('./constants'); -const { task, types } = require('hardhat/config'); -require('dotenv').config(); - -async function preProcess(hre, validatorAddr, isActive) { - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const ethereumName = process.env.ETHEREUM; - const baseName = process.env.BASE; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - - const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; - const messenger = new base.CrossChainMessenger({ - l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: await l2Wallet.getChainId(), // 84532 for Base Sepolia, 8453 for Base Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - bedrock: true, - contracts: { - l1: messengerL1Contracts, - }, - }); - - const l1WalletAddress = await l1Wallet.getAddress(); - const l1WalletBalance = ethers.utils.formatEther(await l1Wallet.getBalance()); - console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); - - const arbitratorAddr = readDeployContract( - logName.DEPLOY_ARBITRATOR_LOG_PREFIX, - logName.DEPLOY_LOG_ARBITRATOR, - ethereumName, - ); - if (arbitratorAddr === undefined) { - console.log('The arbitrator address not exist'); - return; - } - console.log(`The arbitrator address: ${arbitratorAddr}`); - - const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, baseName); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, baseName); - const baseL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (baseL1GatewayAddr === undefined) { - console.log('base l1 gateway address not exist'); - return; - } - console.log(`The base l1 gateway address: ${baseL1GatewayAddr}`); - - const baseL2GatewayAddr = readDeployContract(logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, logName.DEPLOY_GATEWAY, baseName); - if (baseL2GatewayAddr === undefined) { - console.log('base l2 gateway address not exist'); - return; - } - console.log(`The base l2 gateway address: ${baseL2GatewayAddr}`); - - // pre-execution calldata - const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); - const executeCalldata = zkLink.interface.encodeFunctionData('setValidator', [validatorAddr, isActive]); - console.log(`The call data: ${executeCalldata}`); - - const gateway = await hre.ethers.getContractAt('OptimismGateway', baseL2GatewayAddr, l2Wallet); - const sendData = gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 1, // L2_TO_L1, Estimating the Gas Required on L2 - target: baseL2GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - - // forward message to L2 - const arbitrator = await hre.ethers.getContractAt('Arbitrator', arbitratorAddr, l1Wallet); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - console.log(`The adapter params: ${adapterParams}`); - - return { - messenger, - arbitrator, - baseL1GatewayAddr, - baseL2GatewayAddr, - adapterParams, - }; -} - -task('setValidator', 'Set validator for zkLink') - .addParam('validator', 'Validator Address', undefined, types.string) - .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) - .setAction(async (taskArgs, hre) => { - const validatorAddr = taskArgs.validator; - const isActive = taskArgs.active; - console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); - - const { messenger, arbitrator, baseL1GatewayAddr, adapterParams } = await preProcess(hre, validatorAddr, isActive); - - console.log('Prepare to forward the message to L2...'); - let tx = await arbitrator.setValidator(baseL1GatewayAddr, validatorAddr, isActive, adapterParams); - const txHash = tx.hash; - console.log(`The tx hash: ${txHash}`); - await tx.wait(); - console.log(`The transaction has been executed on L1`); - - /** - * Query the message informations on L1 via txHash. - */ - const message = (await messenger.getMessagesByTransaction(txHash)).pop(); - // Waiting for the official base bridge to forward the message to L2 - const rec = await messenger.waitForMessageReceipt(message); - console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); - console.log('Done'); - }); - -task('encodeSetValidator', 'Get the calldata of set validator for zkLink') - .addParam('validator', 'Validator Address', undefined, types.string) - .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) - .setAction(async (taskArgs, hre) => { - const validatorAddr = taskArgs.validator; - const isActive = taskArgs.active; - console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); - - const { arbitrator, baseL1GatewayAddr, adapterParams } = await preProcess(hre, validatorAddr, isActive); - - const calldata = arbitrator.interface.encodeFunctionData('setValidator', [ - baseL1GatewayAddr, - validatorAddr, - isActive, - adapterParams, - ]); - console.log(`The setValidator calldata: ${calldata}`); - }); diff --git a/examples/base/scripts/syncBatchRoot.js b/examples/base/scripts/syncBatchRoot.js deleted file mode 100644 index 6a777f2..0000000 --- a/examples/base/scripts/syncBatchRoot.js +++ /dev/null @@ -1,109 +0,0 @@ -const base = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { L1_MAINNET_CONTRACTS, L1_TESTNET_CONTRACTS } = require('./constants'); -const { task } = require('hardhat/config'); -require('dotenv').config(); - -task('syncBatchRoot', 'Forward message to L2').setAction(async (taskArgs, hre) => { - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const ethereumName = process.env.ETHEREUM; - const baseName = process.env.BASE; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - - const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; - const messenger = new base.CrossChainMessenger({ - l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: await l2Wallet.getChainId(), // 84532 for Base Sepolia, 8453 for Base Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - bedrock: true, - contracts: { - l1: messengerL1Contracts, - }, - }); - - const l1WalletAddress = await l1Wallet.getAddress(); - const l1WalletBalance = ethers.utils.formatEther(await l1Wallet.getBalance()); - console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); - - const arbitratorAddr = readDeployContract( - logName.DEPLOY_ARBITRATOR_LOG_PREFIX, - logName.DEPLOY_LOG_ARBITRATOR, - ethereumName, - ); - if (arbitratorAddr === undefined) { - console.log('The arbitrator address not exist'); - return; - } - console.log(`The arbitrator address: ${arbitratorAddr}`); - - const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, baseName); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, baseName); - const baseL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (baseL1GatewayAddr === undefined) { - console.log('base l1 gateway address not exist'); - return; - } - console.log(`The base l1 gateway address: ${baseL1GatewayAddr}`); - - const baseL2GatewayAddr = readDeployContract(logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, logName.DEPLOY_GATEWAY, baseName); - if (baseL2GatewayAddr === undefined) { - console.log('base l2 gateway address not exist'); - return; - } - console.log(`The base l2 gateway address: ${baseL2GatewayAddr}`); - - // pre-execution calldata - const zkLink = await hre.ethers.getContractAt('DummyZkLink', zkLinkAddr, l2Wallet); - const zklinkIface = zkLink.interface; - const blockNumber = await l2Provider.getBlockNumber(); - console.log(`The current block number: ${blockNumber}`); - const l2LogsRootHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(`L2 logs root hash ${blockNumber}`)); - console.log(`The l2 logs root hash: ${l2LogsRootHash}`); - const executeCalldata = zklinkIface.encodeFunctionData('syncBatchRoot', [blockNumber, l2LogsRootHash, 0]); - console.log(`The call data: ${executeCalldata}`); - const gateway = await hre.ethers.getContractAt('OptimismGateway', baseL2GatewayAddr, l2Wallet); - const sendData = gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 1, // L2_TO_L1, Estimating the Gas Required on L2 - target: baseL2GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - - // forward message to L2 - const arbitrator = await hre.ethers.getContractAt('DummyArbitrator', arbitratorAddr, l1Wallet); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - console.log(`The adapter params: ${adapterParams}`); - console.log('Prepare to forward the message to L2...'); - let tx = await arbitrator.forwardMessage(baseL1GatewayAddr, 0, executeCalldata, adapterParams); - const txHash = tx.hash; - console.log(`The tx hash: ${txHash}`); - await tx.wait(); - console.log(`The transaction has been executed on L1`); - - /** - * Query the message informations on L1 via txHash. - */ - const message = (await messenger.getMessagesByTransaction(txHash)).pop(); - // Waiting for the official base bridge to forward the message to L2 - const rec = await messenger.waitForMessageReceipt(message); - console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); - console.log('Done'); - - // Example txs: - // https://sepolia.etherscan.io/tx/0x00524d9723521e7459581e34013e9a28b5b6d8c4566c3e0b23b2f5fa1726741a - // https://sepolia.basescan.org/tx/0xcca496f9fa90e776e6d8e696f12a67c639e0786dab9c84628e039ad5af22bcf7 -}); diff --git a/examples/base/scripts/syncL2Requests.js b/examples/base/scripts/syncL2Requests.js deleted file mode 100644 index 850dc1b..0000000 --- a/examples/base/scripts/syncL2Requests.js +++ /dev/null @@ -1,131 +0,0 @@ -const base = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { L1_MAINNET_CONTRACTS, L1_TESTNET_CONTRACTS } = require('./constants'); -const { task, types } = require('hardhat/config'); - -require('dotenv').config(); -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -task('syncL2Requests', 'Send sync point to arbitrator') - .addParam('txs', 'New sync point', 100, types.int, true) - .setAction(async (taskArgs, hre) => { - const txs = taskArgs.txs; - console.log(`The sync point: txs: ${txs}`); - - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const baseName = process.env.BASE; - const ethereumName = process.env.ETHEREUM; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - - const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; - const messenger = new base.CrossChainMessenger({ - l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: await l2Wallet.getChainId(), // 84532 for Base Sepolia, 8453 for Base Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - bedrock: true, - contracts: { - l1: messengerL1Contracts, - }, - }); - - const l2WalletAddress = await l2Wallet.getAddress(); - const l2WalletBalance = ethers.utils.formatEther(await l2Wallet.getBalance()); - console.log(`${l2WalletAddress} balance on l2: ${l2WalletBalance} ether`); - - const baseL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - baseName, - ); - if (baseL2GatewayAddr === undefined) { - console.log('base l2 gateway address not exist'); - return; - } - console.log(`The base l2 gateway address: ${baseL2GatewayAddr}`); - - const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, baseName); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - // send txs - const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); - const executeCalldata = zkLink.interface.encodeFunctionData('syncL2Requests', [txs]); - const gasLimit = await l2Provider.estimateGas({ - to: zkLinkAddr, - data: executeCalldata, - from: l2WalletAddress, - }); - console.log(`The gas limit: ${gasLimit}`); - - console.log(`Send a l2 message to l1...`); - let tx = await zkLink.syncL2Requests(txs, { - gasLimit: gasLimit, - }); - let txHash = tx.hash; - console.log(`The tx hash: ${txHash}`); - await tx.wait(); - console.log(`The transaction has been executed on L2`); - // txHash = "0x1a81ed28c1b74120753b0edf3d98e80b814ec5f065ad44b26c0cd6131dc04d22" - let status = await messenger.getMessageStatus(txHash); - console.log(`The message status update to: ${base.MessageStatus[status]}`); - - /** - * Wait until the message is ready to prove - * This step takes about 45 minutes. - */ - await messenger.waitForMessageStatus(txHash, base.MessageStatus.READY_TO_PROVE); - /** - * Once the message is ready to be proven, you'll send an L1 transaction to prove that the message was sent on L2. - */ - console.log(`Proving the message...`); - tx = await messenger.proveMessage(txHash); - console.log(`The prove tx hash: ${tx.hash}`); - await tx.wait(); - console.log(`The message has been proven`); - status = await messenger.getMessageStatus(txHash); - console.log(`The message status update to: ${base.MessageStatus[status]}`); - /** - * Wait until the message is ready for relay - * The final step to sending messages from L2 to L1 is to relay the messages on L1. This can only happen after the fault proof period has elapsed. On OP Sepolia, this is only a few seconds. On OP Mainnet, this takes 7 days. - * Basae is same way as Optimism - */ - await messenger.waitForMessageStatus(txHash, base.MessageStatus.READY_FOR_RELAY); - console.log(`The message is ready for relay`); - status = await messenger.getMessageStatus(txHash); - console.log(`The message status update to: ${base.MessageStatus[status]}`); - await sleep(12 * 1000); // 12 seconds, Waiting for a block to ensure the PROVE transaction is on the chain - /** - * Relay the message on L1 - * Once the withdrawal is ready to be relayed you can finally complete the message sending process. - */ - console.log(`Relaying the message...`); - tx = await messenger.finalizeMessage(txHash); - console.log(`The relay tx hash: ${tx.hash}`); - await tx.wait(); - console.log(`The message has been relayed`); - status = await messenger.getMessageStatus(txHash); - console.log(`The message status update to: ${base.MessageStatus[status]}`); - /** - * Wait until the message is relayed - * Now you simply wait until the message is relayed. - */ - // Waiting for the official base bridge to forward the message to L2 - const rec = await messenger.waitForMessageReceipt(txHash); - console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); - console.log('Done!'); - - // Example txs: - // https://sepolia.basescan.org/tx/0x5ae6195c0b103bee7fbfb855bf23e9afde809ea2527fa9b0209c63038627959b - // https://sepolia.etherscan.io/tx/0xb1b968732830a8c0481cecf0a85fdcb3950b2841819154ab4e366c3ee7770834 - }); diff --git a/examples/blast/hardhat.config.js b/examples/blast/hardhat.config.js index ef15cb5..9bea6fb 100644 --- a/examples/blast/hardhat.config.js +++ b/examples/blast/hardhat.config.js @@ -1,8 +1,5 @@ require('@nomiclabs/hardhat-ethers'); -require('./scripts/syncL2Requests'); -require('./scripts/syncBatchRoot'); -require('./scripts/setValidator'); -require('./scripts/changeFeeParams'); +require('./scripts/blastTasks'); const BaseConfig = require('../../hardhat.base.config'); diff --git a/examples/blast/scripts/blastTasks.js b/examples/blast/scripts/blastTasks.js new file mode 100644 index 0000000..b308b1a --- /dev/null +++ b/examples/blast/scripts/blastTasks.js @@ -0,0 +1,273 @@ +const blast = require('@eth-optimism/sdk'); +const ethers = require('ethers'); +const { + syncBatchRoot, + getContractAddresses, + setValidator, + changeFeeParams, + encodeSetValidator, + encodeChangeFeeParams, +} = require('../../utils/opstack-utils'); +const { + MESSAGE_PASSER_ABI, + MESSAGE_PASSER_ADDRESS, + OPTIMISM_PORTAL_ABI, + YIELD_MANAGER_ABI, + L1_MAINNET_CONTRACTS, + L1_TESTNET_CONTRACTS, + YIELD_MANAGER_TESTNET_ADDRESS, + YIELD_MANAGER_MAINNET_ADDRESS, +} = require('./constants'); +const { task, types } = require('hardhat/config'); +require('dotenv').config(); + +async function initMessenger() { + const walletPrivateKey = process.env.DEVNET_PRIVKEY; + const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); + const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); + const blastName = process.env.BLAST; + const ethereumName = process.env.ETHEREUM; + const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); + const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); + + const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; + const yieldManagerAddress = + ethereumName !== 'ETHEREUM' ? YIELD_MANAGER_TESTNET_ADDRESS : YIELD_MANAGER_MAINNET_ADDRESS; + const messenger = new blast.CrossChainMessenger({ + l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum + l2ChainId: await l2Wallet.getChainId(), // 168587773 for Blast Testnet, 81457 for Blast Mainnet + l1SignerOrProvider: l1Wallet, + l2SignerOrProvider: l2Wallet, + bedrock: true, + bridges: { + Standard: { + Adapter: blast.StandardBridgeAdapter, + l1Bridge: messengerL1Contracts.L1StandardBridge, + l2Bridge: '0x4200000000000000000000000000000000000010', + }, + }, + contracts: { + l1: messengerL1Contracts, + }, + }); + + return { messenger, messengerL1Contracts, yieldManagerAddress, ethereumName, blastName }; +} + +task('syncBatchRoot', 'Forward message to L2').setAction(async (_, hre) => { + const { messenger, ethereumName, blastName } = await initMessenger(); + + const l2Wallet = messenger.l2Signer; + const l2CurrentBlock = await l2Wallet.provider.getBlockNumber(); + console.log(`Current block on l2: ${l2CurrentBlock}`); + + const message = await syncBatchRoot(hre, messenger, ethereumName, blastName, 'blast'); + + await messenger.waitForMessageStatus(message, blast.MessageStatus.RELAYED); + const rec = await messenger.getMessageReceipt(message, 0, l2CurrentBlock, 'latest'); + console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); + console.log('Done'); + + // Example txs: + // https://sepolia.etherscan.io/tx/0xfa6168b68e37d2838589733b0dce76d0e489ade267627f3371546935b2aa393d + // https://sepolia.blastscan.io/tx/0x77c77aa0ebcdcc1537eee9fa00cab394332608228e2d8fcff0eefb422d2bb451 +}); + +task('syncL2Requests', 'Send sync point to arbitrator') + .addParam('txs', 'New sync point', 100, types.int, true) + .setAction(async (taskArgs, hre) => { + const txs = taskArgs.txs; + console.log(`The sync point: txs: ${txs}`); + + const { messenger, messengerL1Contracts, yieldManagerAddress, ethereumName, blastName } = await initMessenger(); + const l1Wallet = messenger.l1Signer; + const l2Wallet = messenger.l2Signer; + + const optimismPortalContract = await hre.ethers.getContractAt( + OPTIMISM_PORTAL_ABI, + messengerL1Contracts.OptimismPortal, + l1Wallet, + ); + console.log(`The optimism portal contract address: ${optimismPortalContract.address}`); + + const yieldManagerContract = await hre.ethers.getContractAt(YIELD_MANAGER_ABI, yieldManagerAddress, l1Wallet); + console.log(`The yield manager contract address: ${yieldManagerContract.address}`); + + const messagePasserContract = await hre.ethers.getContractAt(MESSAGE_PASSER_ABI, MESSAGE_PASSER_ADDRESS, l2Wallet); + console.log(`The message passer contract address: ${messagePasserContract.address}`); + + const l2WalletAddress = await l2Wallet.getAddress(); + const l2WalletBalance = ethers.utils.formatEther(await l2Wallet.getBalance()); + console.log(`${l2WalletAddress} balance on l2: ${l2WalletBalance} ether`); + + const { zkLinkAddr } = await getContractAddresses(ethereumName, blastName, 'blast'); + + const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); + const calldata = zkLink.interface.encodeFunctionData('syncL2Requests', [txs]); + console.log(`The calldata: ${calldata}`); + const gasLimit = await l2Wallet.provider.estimateGas({ + from: l2Wallet.address, + to: zkLinkAddr, + data: calldata, + }); + console.log(`The gas limit: ${gasLimit}`); + + console.log(`Send a l2 message to l1...`); + let tx = await zkLink.syncL2Requests(txs, { + gasLimit: gasLimit, + }); + let txHash = tx.hash; + console.log(`The tx hash: ${txHash}`); + await tx.wait(); + console.log(`The transaction has been executed on L2`); + // const txHash = "0xa84e4ec21c6134edc671008d69934cdbc4750fd98ca06f2fe81c20fab8abafb5"; + let receipt = await l2Wallet.provider.getTransactionReceipt(txHash); + + let messageInfos; + for (const log of receipt.logs) { + switch (log.address.toLowerCase()) { + case messagePasserContract.address.toLowerCase(): { + const parsed = messagePasserContract.interface.parseLog(log); + if (parsed.name === 'MessagePassed') { + messageInfos = { + nonce: parsed.args.nonce, + sender: parsed.args.sender, + target: parsed.args.target, + gasLimit: parsed.args.gasLimit, + data: parsed.args.data, + value: parsed.args.value, + }; + } + } + } + } + console.log(`The messageInfos: ${JSON.stringify(messageInfos, null, 2)}`); + + const message = (await messenger.getMessagesByTransaction(txHash)).pop(); + let status = await messenger.getMessageStatus(message); + console.log(`The message status update to: ${blast.MessageStatus[status]}`); + const feeData = await l1Wallet.getFeeData(); + + /** + * Wait until the message is ready to prove + * This step can take a few minutes. + */ + await messenger.waitForMessageStatus(message, blast.MessageStatus.READY_TO_PROVE); + /** + * Once the message is ready to be proven, you'll send an L1 transaction to prove that the message was sent on L2. + */ + console.log(`Proving the message...`); + tx = await messenger.proveMessage(message, { + maxFeePerGas: feeData.maxFeePerGas.mul(2), + maxPriorityFeePerGas: feeData.maxPriorityFeePerGas.mul(2), + }); + console.log(`The prove tx hash: ${tx.hash}`); + await tx.wait(); + console.log(`The message has been proven`); + let requestId; + receipt = await l1Wallet.provider.getTransactionReceipt(tx.hash); + for (const log of receipt.logs) { + switch (log.address.toLowerCase()) { + case optimismPortalContract.address.toLowerCase(): { + const parsed = optimismPortalContract.interface.parseLog(log); + if (parsed.name === 'WithdrawalProven') { + requestId = parsed.args.requestId; + } + } + } + } + console.log(`The request id: ${requestId}`); + /** + * Wait until the message is ready for relay + * The final step to sending messages from L2 to L1 is to relay the messages on L1. This can only happen after the fault proof period has elapsed. On OP Sepolia, this is only a few seconds. On OP Mainnet, this takes 7 days. + */ + await messenger.waitForMessageStatus(message, blast.MessageStatus.READY_FOR_RELAY); + + let hintId; + if (requestId.toNumber() === 0) { + hintId = 0; + } else { + const lastCheckPoint = await yieldManagerContract.getLastCheckpointId(); + hintId = await yieldManagerContract.findCheckpointHint(requestId, 1, lastCheckPoint); + } + console.log(`The hint id: ${hintId}`); + tx = await optimismPortalContract.finalizeWithdrawalTransaction( + hintId, + [ + messageInfos.nonce, + messageInfos.sender, + messageInfos.target, + messageInfos.value, + messageInfos.gasLimit, + messageInfos.data, + ], + { + maxFeePerGas: feeData.maxFeePerGas.mul(2), + maxPriorityFeePerGas: feeData.maxPriorityFeePerGas.mul(2), + }, + ); + console.log(`The relay tx hash: ${tx.hash}`); + await tx.wait(); + console.log(`The message has been relayed`); + console.log('Done!'); + + // Example txs: + // https://sepolia.blastscan.io/tx/0xf482f09c7085be3cbe6d1ef63b7e67d353fbf86cc40455d560a46b5458ecc2b7 + // https://sepolia.etherscan.io/tx/0x96b3e1ab8fc9777f606f032370dec5184c7769ebd9c14647611766d50b3b8c14 + }); + +task('setValidator', 'Set validator for zkLink') + .addParam('validator', 'Validator Address', undefined, types.string) + .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) + .setAction(async (taskArgs, hre) => { + const validatorAddr = taskArgs.validator; + const isActive = taskArgs.active; + console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); + + const { messenger, ethereumName, blastName } = await initMessenger(); + + const l2Wallet = messenger.l2Signer; + const l2CurrentBlock = await l2Wallet.provider.getBlockNumber(); + console.log(`Current block on l2: ${l2CurrentBlock}`); + + const message = await setValidator(hre, messenger, ethereumName, blastName, 'blast', validatorAddr, isActive); + + await messenger.waitForMessageStatus(message, blast.MessageStatus.RELAYED); + const rec = await messenger.getMessageReceipt(message, 0, l2CurrentBlock, 'latest'); + console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); + console.log('Done'); + }); + +task('changeFeeParams', 'Change fee params for zkLink').setAction(async (taskArgs, hre) => { + const { messenger, ethereumName, blastName } = await initMessenger(); + + const l2Wallet = messenger.l2Signer; + const l2CurrentBlock = await l2Wallet.provider.getBlockNumber(); + console.log(`Current block on l2: ${l2CurrentBlock}`); + + const message = await changeFeeParams(hre, messenger, ethereumName, blastName, 'blast'); + + await messenger.waitForMessageStatus(message, blast.MessageStatus.RELAYED); + const rec = await messenger.getMessageReceipt(message, 0, l2CurrentBlock, 'latest'); + console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); + console.log('Done'); +}); + +task('encodeChangeFeeParams', 'Get the calldata of changing fee params for zkLink').setAction(async (_, hre) => { + const { messenger, ethereumName, blastName } = await initMessenger(); + + await encodeChangeFeeParams(hre, messenger, ethereumName, blastName, 'blast'); +}); + +task('encodeSetValidator', 'Get the calldata of set validator for zkLink') + .addParam('validator', 'Validator Address', undefined, types.string) + .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) + .setAction(async (taskArgs, hre) => { + const validatorAddr = taskArgs.validator; + const isActive = taskArgs.active; + console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); + + const { messenger, ethereumName, blastName } = await initMessenger(); + + await encodeSetValidator(hre, messenger, ethereumName, blastName, 'blast', validatorAddr, isActive); + }); diff --git a/examples/blast/scripts/changeFeeParams.js b/examples/blast/scripts/changeFeeParams.js deleted file mode 100644 index f32f665..0000000 --- a/examples/blast/scripts/changeFeeParams.js +++ /dev/null @@ -1,161 +0,0 @@ -const blast = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { L1_MAINNET_CONTRACTS, L1_TESTNET_CONTRACTS } = require('./constants'); -const { task } = require('hardhat/config'); -const { INIT_FEE_PARAMS } = require('../../../script/zksync_era'); -require('dotenv').config(); - -task('changeFeeParams', 'Change fee params for zkLink').setAction(async (taskArgs, hre) => { - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const blastName = process.env.BLAST; - const ethereumName = process.env.ETHEREUM; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - - const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; - const messenger = new blast.CrossChainMessenger({ - l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: await l2Wallet.getChainId(), // 168587773 for Blast Testnet, 81457 for Blast Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - bedrock: false, - bridges: { - Standard: { - Adapter: blast.StandardBridgeAdapter, - l1Bridge: messengerL1Contracts.L1StandardBridge, - l2Bridge: '0x4200000000000000000000000000000000000010', - }, - }, - contracts: { - l1: messengerL1Contracts, - }, - }); - - const l1WalletAddress = await l1Wallet.getAddress(); - const l1WalletBalance = ethers.utils.formatEther(await l1Wallet.getBalance()); - console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); - - const arbitratorAddr = readDeployContract( - logName.DEPLOY_ARBITRATOR_LOG_PREFIX, - logName.DEPLOY_LOG_ARBITRATOR, - ethereumName, - ); - if (arbitratorAddr === undefined) { - console.log('The arbitrator address not exist'); - return; - } - console.log(`The arbitrator address: ${arbitratorAddr}`); - - const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, blastName); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, blastName); - const blastL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (blastL1GatewayAddr === undefined) { - console.log('blast l1 gateway address not exist'); - return; - } - console.log(`The blast l1 gateway address: ${blastL1GatewayAddr}`); - - const blastL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - blastName, - ); - if (blastL2GatewayAddr === undefined) { - console.log('blast l2 gateway address not exist'); - return; - } - console.log(`The blast l2 gateway address: ${blastL2GatewayAddr}`); - - // pre-execution calldata - const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); - const executeCalldata = zkLink.interface.encodeFunctionData('changeFeeParams', [INIT_FEE_PARAMS]); - const gateway = await hre.ethers.getContractAt('OptimismGateway', blastL1GatewayAddr, l1Wallet); - const sendData = gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 0, // L1_TO_L2, Estimating the Gas Required on L2 - target: blastL1GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - - // forward message to L2 - const arbitrator = await hre.ethers.getContractAt('Arbitrator', arbitratorAddr, l1Wallet); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - console.log('Prepare to forward the message to L2...'); - let tx = await arbitrator.changeFeeParams(blastL1GatewayAddr, INIT_FEE_PARAMS, adapterParams); - console.log(`The tx hash: ${tx.hash}`); - await tx.wait(); - console.log(`The tx confirmed`); - - /** - * Query the message informations on L1 via txHash. - */ - const message = (await messenger.getMessagesByTransaction(tx.hash)).pop(); - console.log(`The message: ${JSON.stringify(message, null, 2)}`); - console.log('Done'); - // Waiting for the official blast bridge to forward the message to L2 -}); - -task('encodeChangeFeeParams', 'Get the calldata of changing fee params for zkLink').setAction(async (taskArgs, hre) => { - const blastName = process.env.BLAST; - const ethereumName = process.env.ETHEREUM; - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, blastName); - const blastL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (blastL1GatewayAddr === undefined) { - console.log('blast l1 gateway address not exist'); - return; - } - console.log(`The blast l1 gateway address: ${blastL1GatewayAddr}`); - - const zkLinkFactory = await hre.ethers.getContractFactory('ZkLink'); - const executeCalldata = zkLinkFactory.interface.encodeFunctionData('changeFeeParams', [INIT_FEE_PARAMS]); - const gatewayFactory = await hre.ethers.getContractFactory('OptimismL2Gateway'); - const sendData = gatewayFactory.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; - const messenger = new blast.CrossChainMessenger({ - l1ChainId: (await l1Provider.getNetwork()).chainId, // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: (await l2Provider.getNetwork()).chainId, // 168587773 for Blast Testnet, 81457 for Blast Mainnet - l1SignerOrProvider: l1Provider, - l2SignerOrProvider: l2Provider, - bedrock: false, - bridges: { - Standard: { - Adapter: blast.StandardBridgeAdapter, - l1Bridge: messengerL1Contracts.L1StandardBridge, - l2Bridge: '0x4200000000000000000000000000000000000010', - }, - }, - contracts: { - l1: messengerL1Contracts, - }, - }); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 0, // L1_TO_L2, Estimating the Gas Required on L2 - target: blastL1GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - const arbitratorFactory = await hre.ethers.getContractFactory('Arbitrator'); - const calldata = arbitratorFactory.interface.encodeFunctionData('changeFeeParams', [ - blastL1GatewayAddr, - INIT_FEE_PARAMS, - adapterParams, - ]); - console.log(`The changeFeeParams calldata: ${calldata}`); -}); diff --git a/examples/blast/scripts/constants.js b/examples/blast/scripts/constants.js index 7e1d5cb..8f36e03 100644 --- a/examples/blast/scripts/constants.js +++ b/examples/blast/scripts/constants.js @@ -4,6 +4,9 @@ const OPTIMISM_PORTAL_ABI = contractABIs.OptimismPortal; const YIELD_MANAGER_ABI = contractABIs.YieldManager; +const MESSAGE_PASSER_ABI = contractABIs.MessagePasser; +const MESSAGE_PASSER_ADDRESS = '0x4200000000000000000000000000000000000016'; + // Testnet const YIELD_MANAGER_TESTNET_ADDRESS = '0xeD530bA33B4dC14572864Bb9a776C9a42CF89fA5'; const L1_TESTNET_CONTRACTS = { @@ -33,6 +36,8 @@ const L1_MAINNET_CONTRACTS = { module.exports = { OPTIMISM_PORTAL_ABI, YIELD_MANAGER_ABI, + MESSAGE_PASSER_ABI, + MESSAGE_PASSER_ADDRESS, YIELD_MANAGER_MAINNET_ADDRESS, YIELD_MANAGER_TESTNET_ADDRESS, L1_TESTNET_CONTRACTS, diff --git a/examples/blast/scripts/contractABIs.json b/examples/blast/scripts/contractABIs.json index 6d56d72..b1f1699 100644 --- a/examples/blast/scripts/contractABIs.json +++ b/examples/blast/scripts/contractABIs.json @@ -739,5 +739,68 @@ "type": "function" }, { "stateMutability": "payable", "type": "receive" } + ], + "MessagePasser": [ + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { "indexed": true, "internalType": "address", "name": "sender", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "target", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, + { "indexed": false, "internalType": "bytes", "name": "data", "type": "bytes" }, + { "indexed": false, "internalType": "bytes32", "name": "withdrawalHash", "type": "bytes32" } + ], + "name": "MessagePassed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": true, "internalType": "uint256", "name": "amount", "type": "uint256" }], + "name": "WithdrawerBalanceBurnt", + "type": "event" + }, + { + "inputs": [], + "name": "MESSAGE_VERSION", + "outputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "burn", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { "internalType": "address", "name": "_target", "type": "address" }, + { "internalType": "uint256", "name": "_gasLimit", "type": "uint256" }, + { "internalType": "bytes", "name": "_data", "type": "bytes" } + ], + "name": "initiateWithdrawal", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "messageNonce", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "name": "sentMessages", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { "stateMutability": "payable", "type": "receive" } ] } diff --git a/examples/blast/scripts/setValidator.js b/examples/blast/scripts/setValidator.js deleted file mode 100644 index aa55771..0000000 --- a/examples/blast/scripts/setValidator.js +++ /dev/null @@ -1,173 +0,0 @@ -const blast = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { L1_MAINNET_CONTRACTS, L1_TESTNET_CONTRACTS } = require('./constants'); -const { task, types } = require('hardhat/config'); -require('dotenv').config(); - -task('setValidator', 'Set validator for zkLink') - .addParam('validator', 'Validator Address', undefined, types.string) - .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) - .setAction(async (taskArgs, hre) => { - const validatorAddr = taskArgs.validator; - const isActive = taskArgs.active; - console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); - - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const blastName = process.env.BLAST; - const ethereumName = process.env.ETHEREUM; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - - const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; - const messenger = new blast.CrossChainMessenger({ - l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: await l2Wallet.getChainId(), // 168587773 for Blast Testnet, 81457 for Blast Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - bedrock: false, - bridges: { - Standard: { - Adapter: blast.StandardBridgeAdapter, - l1Bridge: messengerL1Contracts.L1StandardBridge, - l2Bridge: '0x4200000000000000000000000000000000000010', - }, - }, - contracts: { - l1: messengerL1Contracts, - }, - }); - - const l1WalletAddress = await l1Wallet.getAddress(); - const l1WalletBalance = ethers.utils.formatEther(await l1Wallet.getBalance()); - console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); - - const arbitratorAddr = readDeployContract( - logName.DEPLOY_ARBITRATOR_LOG_PREFIX, - logName.DEPLOY_LOG_ARBITRATOR, - ethereumName, - ); - if (arbitratorAddr === undefined) { - console.log('The arbitrator address not exist'); - return; - } - console.log(`The arbitrator address: ${arbitratorAddr}`); - - const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, blastName); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, blastName); - const blastL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (blastL1GatewayAddr === undefined) { - console.log('blast l1 gateway address not exist'); - return; - } - console.log(`The blast l1 gateway address: ${blastL1GatewayAddr}`); - - const blastL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - blastName, - ); - if (blastL2GatewayAddr === undefined) { - console.log('blast l2 gateway address not exist'); - return; - } - console.log(`The blast l2 gateway address: ${blastL2GatewayAddr}`); - - // pre-execution calldata - const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); - const executeCalldata = zkLink.interface.encodeFunctionData('setValidator', [validatorAddr, isActive]); - const gateway = await hre.ethers.getContractAt('OptimismGateway', blastL1GatewayAddr, l1Wallet); - const sendData = gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 0, // L1_TO_L2, Estimating the Gas Required on L2 - target: blastL1GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - - // forward message to L2 - const arbitrator = await hre.ethers.getContractAt('Arbitrator', arbitratorAddr, l1Wallet); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - let tx = await arbitrator.setValidator(blastL1GatewayAddr, validatorAddr, isActive, adapterParams); - console.log(`The tx hash: ${tx.hash}`); - await tx.wait(); - console.log(`The tx confirmed`); - /** - * Query the message informations on L1 via txHash. - */ - const message = (await messenger.getMessagesByTransaction(tx.hash)).pop(); - console.log(`The message: ${JSON.stringify(message, null, 2)}`); - console.log('Done'); - // Waiting for the official blast bridge to forward the message to L2 - }); - -task('encodeSetValidator', 'Get the calldata of set validator for zkLink') - .addParam('validator', 'Validator Address', undefined, types.string) - .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) - .setAction(async (taskArgs, hre) => { - const validatorAddr = taskArgs.validator; - const isActive = taskArgs.active; - console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); - - const blastName = process.env.BLAST; - const ethereumName = process.env.ETHEREUM; - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, blastName); - const blastL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (blastL1GatewayAddr === undefined) { - console.log('blast l1 gateway address not exist'); - return; - } - console.log(`The blast l1 gateway address: ${blastL1GatewayAddr}`); - - const zkLinkFactory = await hre.ethers.getContractFactory('ZkLink'); - const executeCalldata = zkLinkFactory.interface.encodeFunctionData('setValidator', [validatorAddr, isActive]); - const gatewayFactory = await hre.ethers.getContractFactory('OptimismL2Gateway'); - const sendData = gatewayFactory.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; - const messenger = new blast.CrossChainMessenger({ - l1ChainId: (await l1Provider.getNetwork()).chainId, // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: (await l2Provider.getNetwork()).chainId, // 168587773 for Blast Testnet, 81457 for Blast Mainnet - l1SignerOrProvider: l1Provider, - l2SignerOrProvider: l2Provider, - bedrock: false, - bridges: { - Standard: { - Adapter: blast.StandardBridgeAdapter, - l1Bridge: messengerL1Contracts.L1StandardBridge, - l2Bridge: '0x4200000000000000000000000000000000000010', - }, - }, - contracts: { - l1: messengerL1Contracts, - }, - }); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 0, // L1_TO_L2, Estimating the Gas Required on L2 - target: blastL1GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - const arbitratorFactory = await hre.ethers.getContractFactory('Arbitrator'); - const calldata = arbitratorFactory.interface.encodeFunctionData('setValidator', [ - blastL1GatewayAddr, - validatorAddr, - isActive, - adapterParams, - ]); - console.log(`The changeFeeParams calldata: ${calldata}`); - }); diff --git a/examples/blast/scripts/syncBatchRoot.js b/examples/blast/scripts/syncBatchRoot.js deleted file mode 100644 index 5fe56d5..0000000 --- a/examples/blast/scripts/syncBatchRoot.js +++ /dev/null @@ -1,122 +0,0 @@ -const blast = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { L1_MAINNET_CONTRACTS, L1_TESTNET_CONTRACTS } = require('./constants'); -const { task } = require('hardhat/config'); -require('dotenv').config(); - -task('syncBatchRoot', 'Forward message to L2').setAction(async (taskArgs, hre) => { - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const blastName = process.env.BLAST; - const ethereumName = process.env.ETHEREUM; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - - const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; - const messenger = new blast.CrossChainMessenger({ - l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: await l2Wallet.getChainId(), // 168587773 for Blast Testnet, 81457 for Blast Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - bedrock: false, - bridges: { - Standard: { - Adapter: blast.StandardBridgeAdapter, - l1Bridge: messengerL1Contracts.L1StandardBridge, - l2Bridge: '0x4200000000000000000000000000000000000010', - }, - }, - contracts: { - l1: messengerL1Contracts, - }, - }); - - const l1WalletAddress = await l1Wallet.getAddress(); - const l1WalletBalance = ethers.utils.formatEther(await l1Wallet.getBalance()); - console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); - - const arbitratorAddr = readDeployContract( - logName.DEPLOY_ARBITRATOR_LOG_PREFIX, - logName.DEPLOY_LOG_ARBITRATOR, - ethereumName, - ); - if (arbitratorAddr === undefined) { - console.log('The arbitrator address not exist'); - return; - } - console.log(`The arbitrator address: ${arbitratorAddr}`); - - const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, blastName); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, blastName); - const blastL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (blastL1GatewayAddr === undefined) { - console.log('blast l1 gateway address not exist'); - return; - } - console.log(`The blast l1 gateway address: ${blastL1GatewayAddr}`); - - const blastL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - blastName, - ); - if (blastL2GatewayAddr === undefined) { - console.log('blast l2 gateway address not exist'); - return; - } - console.log(`The blast l2 gateway address: ${blastL2GatewayAddr}`); - - // pre-execution calldata - const zkLink = await hre.ethers.getContractAt('DummyZkLink', zkLinkAddr, l2Wallet); - const zklinkIface = zkLink.interface; - const blockNumber = await l2Provider.getBlockNumber(); - console.log(`The current block number: ${blockNumber}`); - const l2LogsRootHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(`L2 logs root hash ${blockNumber}`)); - console.log(`The l2 logs root hash: ${l2LogsRootHash}`); - const executeCalldata = zklinkIface.encodeFunctionData('syncBatchRoot', [blockNumber, l2LogsRootHash, 0]); - console.log(`The call data: ${executeCalldata}`); - const gateway = await hre.ethers.getContractAt('OptimismGateway', blastL1GatewayAddr, l2Wallet); - const sendData = gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 0, // L1_TO_L2, Estimating the Gas Required on L2 - target: blastL1GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - - // forward message to L2 - const arbitrator = await hre.ethers.getContractAt('DummyArbitrator', arbitratorAddr, l1Wallet); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - console.log(`The adapter params: ${adapterParams}`); - console.log('Prepare to forward the message to L2...'); - let tx = await arbitrator.forwardMessage(blastL1GatewayAddr, 0, executeCalldata, adapterParams); - const txHash = tx.hash; - console.log(`The tx hash: ${txHash}`); - await tx.wait(); - console.log(`The transaction has been executed on L1`); - // const txHash = "0x742c8aedb51057196d55f2a908c4f7704ad5b4d5fcf1d10a333002dedb7beaf6" - - const status = await messenger.waitForMessageStatus(txHash, blast.MessageStatus.RELAYED); - console.log(`The message status: ${status}`); - /** - * Query the message informations on L1 via txHash. - */ - const message = (await messenger.getMessagesByTransaction(txHash)).pop(); - console.log(`The message: ${JSON.stringify(message, null, 2)}`); - console.log('Done'); - // Waiting for the official blast bridge to forward the message to L2 - - // Example txs: - // - // -}); diff --git a/examples/blast/scripts/syncL2Requests.js b/examples/blast/scripts/syncL2Requests.js deleted file mode 100644 index 5b1959f..0000000 --- a/examples/blast/scripts/syncL2Requests.js +++ /dev/null @@ -1,96 +0,0 @@ -const blast = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { - OPTIMISM_PORTAL_ABI, - YIELD_MANAGER_ABI, - YIELD_MANAGER_MAINNET_ADDRESS, - YIELD_MANAGER_TESTNET_ADDRESS, - L1_MAINNET_CONTRACTS, - L1_TESTNET_CONTRACTS, -} = require('./constants'); -const { task, types } = require('hardhat/config'); - -require('dotenv').config(); - -task('syncL2Requests', 'Send sync point to arbitrator') - .addParam('txs', 'New sync point', 100, types.int, true) - .setAction(async (taskArgs, hre) => { - const txs = taskArgs.txs; - console.log(`The sync point: txs: ${txs}`); - - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - console.log(`The l1 block number: ${await l1Provider.getBlockNumber()}`); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const blastName = process.env.BLAST; - const ethereumName = process.env.ETHEREUM; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; - const yieldManagerAddress = - ethereumName !== 'ETHEREUM' ? YIELD_MANAGER_TESTNET_ADDRESS : YIELD_MANAGER_MAINNET_ADDRESS; - const messenger = new blast.CrossChainMessenger({ - l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: await l2Wallet.getChainId(), // 168587773 for Blast Testnet, 81457 for Blast Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - bridges: { - Standard: { - Adapter: blast.StandardBridgeAdapter, - l1Bridge: messengerL1Contracts.L1StandardBridge, - l2Bridge: '0x4200000000000000000000000000000000000010', - }, - }, - contracts: { - l1: messengerL1Contracts, - }, - }); - - const optimismPortalContract = await hre.ethers.getContractAt( - OPTIMISM_PORTAL_ABI, - messengerL1Contracts.OptimismPortal, - l1Wallet, - ); - console.log(`The optimism portal contract address: ${optimismPortalContract.address}`); - - const yieldManagerContract = await hre.ethers.getContractAt(YIELD_MANAGER_ABI, yieldManagerAddress, l1Wallet); - console.log(`The yield manager contract address: ${yieldManagerContract.address}`); - - const l2WalletAddress = await l2Wallet.getAddress(); - const l2WalletBalance = ethers.utils.formatEther(await l2Wallet.getBalance()); - console.log(`${l2WalletAddress} balance on l2: ${l2WalletBalance} ether`); - - const blastL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - blastName, - ); - if (blastL2GatewayAddr === undefined) { - console.log('blast l2 gateway address not exist'); - return; - } - console.log(`The blast l2 gateway address: ${blastL2GatewayAddr}`); - - const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, blastName); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - // send txs - const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); - console.log(`Send a l2 message to l1...`); - let tx = await zkLink.syncL2Requests(txs); - let txHash = tx.hash; - console.log(`The tx hash: ${txHash}`); - await tx.wait(); - console.log(`The transaction has been executed on L2`); - const message = (await messenger.getMessagesByTransaction(txHash)).pop(); - console.log(`The message: ${JSON.stringify(message, null, 2)}`); - - let status = await messenger.getMessageStatus(txHash); - console.log(`The message status: ${status}`); - }); diff --git a/examples/manta/.env-sample b/examples/manta/.env-sample index fefb188..fcce803 100644 --- a/examples/manta/.env-sample +++ b/examples/manta/.env-sample @@ -8,9 +8,9 @@ DEVNET_PRIVKEY="0x your key here" # Hosted Aggregator Node (JSON-RPC Endpoint). This is Manta pacific Testnet, can use any Manta chain -L2RPC="https://pacific-rpc.testnet.manta.network/http" +L2RPC="https://pacific-rpc.sepolia-testnet.manta.network/http" -# Ethereum RPC; i.e., for Goerli https://goerli.infura.io/v3/ +# Ethereum RPC; i.e., for Sepolia https://sepolia.infura.io/v3/ L1RPC="" @@ -18,4 +18,4 @@ L1RPC="" MANTA="MANTATEST" # Ethereum chain name -ETHEREUM="GOERLI" \ No newline at end of file +ETHEREUM="SEPOLIA" \ No newline at end of file diff --git a/examples/manta/hardhat.config.js b/examples/manta/hardhat.config.js index ef15cb5..a2af763 100644 --- a/examples/manta/hardhat.config.js +++ b/examples/manta/hardhat.config.js @@ -1,8 +1,5 @@ require('@nomiclabs/hardhat-ethers'); -require('./scripts/syncL2Requests'); -require('./scripts/syncBatchRoot'); -require('./scripts/setValidator'); -require('./scripts/changeFeeParams'); +require('./scripts/mantaTasks'); const BaseConfig = require('../../hardhat.base.config'); diff --git a/examples/manta/scripts/changeFeeParams.js b/examples/manta/scripts/changeFeeParams.js deleted file mode 100644 index a40a1ed..0000000 --- a/examples/manta/scripts/changeFeeParams.js +++ /dev/null @@ -1,109 +0,0 @@ -const manta = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { task } = require('hardhat/config'); -require('dotenv').config(); - -task('changeFeeParams', 'Change fee params for zkLink').setAction(async (taskArgs, hre) => { - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const ethereumName = process.env.ETHEREUM; - const mantaName = process.env.MANTA; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - const messenger = new manta.CrossChainMessenger({ - l1ChainId: ethereumName !== 'ETHEREUM' ? 5 : 1, // 5 for Goerli, 1 for Ethereum - l2ChainId: ethereumName !== 'ETHEREUM' ? 3441005 : 169, // 3441005 for Manta Pacific Testnet, 169 for Manta Pacific Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - bedrock: true, - contracts: { - l1: { - StateCommitmentChain: '0x0000000000000000000000000000000000000000', - BondManager: '0x0000000000000000000000000000000000000000', - CanonicalTransactionChain: '0x0000000000000000000000000000000000000000', - AddressManager: '0x0AaeDFF2961D05021832cA093cf9409eDF5ECa8C', - L1CrossDomainMessenger: '0x7Ad11bB9216BC9Dc4CBd488D7618CbFD433d1E75', - L1StandardBridge: '0x4638aC6b5727a8b9586D3eba5B44Be4b74ED41Fc', - OptimismPortal: '0x7FD7eEA37c53ABf356cc80e71144D62CD8aF27d3', - L2OutputOracle: '0x8553D4d201ef97F2b76A28F5E543701b25e55B1b', - }, - }, - }); - - const l1WalletAddress = await l1Wallet.getAddress(); - const l1WalletBalance = ethers.utils.formatEther(await l1Wallet.getBalance()); - console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); - - const arbitratorAddr = readDeployContract( - logName.DEPLOY_ARBITRATOR_LOG_PREFIX, - logName.DEPLOY_LOG_ARBITRATOR, - ethereumName, - ); - if (arbitratorAddr === undefined) { - console.log('The arbitrator address not exist'); - return; - } - console.log(`The arbitrator address: ${arbitratorAddr}`); - - const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, mantaName); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, mantaName); - const mantaL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (mantaL1GatewayAddr === undefined) { - console.log('manta l1 gateway address not exist'); - return; - } - console.log(`The manta l1 gateway address: ${mantaL1GatewayAddr}`); - - const mantaL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - mantaName, - ); - if (mantaL2GatewayAddr === undefined) { - console.log('manta l2 gateway address not exist'); - return; - } - console.log(`The manta l2 gateway address: ${mantaL2GatewayAddr}`); - - // pre-execution calldata - const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); - const { INIT_FEE_PARAMS } = require('../../../script/zksync_era'); - const executeCalldata = zkLink.interface.encodeFunctionData('changeFeeParams', [INIT_FEE_PARAMS]); - const mantaL2Gateway = await hre.ethers.getContractAt('OptimismGateway', mantaL2GatewayAddr, l1Wallet); - const sendData = mantaL2Gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 1, // L2_TO_L1, Estimating the Gas Required on L2 - target: mantaL2GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - - // forward message to L2 - const arbitrator = await hre.ethers.getContractAt('Arbitrator', arbitratorAddr, l1Wallet); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - console.log('Prepare to forward the message to L2...'); - let tx = await arbitrator.changeFeeParams(mantaL1GatewayAddr, INIT_FEE_PARAMS, adapterParams); - const txHash = tx.hash; - await tx.wait(); - console.log(`The tx hash: ${txHash}`); - - /** - * Query the message information on L1 via txHash. - */ - const message = (await messenger.getMessagesByTransaction(txHash)).pop(); - console.log(`The message: ${JSON.stringify(message)}`); - // Waiting for the official manta bridge to forward the message to L2 - const rec = await messenger.waitForMessageReceipt(message); - console.log(`The tx receipt: ${JSON.stringify(rec)}`); - console.log('Done'); -}); diff --git a/examples/manta/scripts/constants.js b/examples/manta/scripts/constants.js new file mode 100644 index 0000000..4b9d9f8 --- /dev/null +++ b/examples/manta/scripts/constants.js @@ -0,0 +1,28 @@ +// Testnet +const L1_TESTNET_CONTRACTS = { + StateCommitmentChain: '0x0000000000000000000000000000000000000000', + BondManager: '0x0000000000000000000000000000000000000000', + CanonicalTransactionChain: '0x0000000000000000000000000000000000000000', + AddressManager: '0x0691B7aaAc9B903c9a99B2371bCFB43601B45711', + L1CrossDomainMessenger: '0xFe7cF31c4579bb1C578716e04E1Ae16Ac5549fF0', + L1StandardBridge: '0xCAD25C95679839996F3162d8657B1CAe4517F78f', + OptimismPortal: '0x80f86c5d3AE8cF84596FF22DB2829F1b7a9Fe83d', + L2OutputOracle: '0x2dd44d1b04170C5623cCc55DD5ed43FAB08b0B46', +}; + +// Mainnet +const L1_MAINNET_CONTRACTS = { + StateCommitmentChain: '0x0000000000000000000000000000000000000000', + BondManager: '0x0000000000000000000000000000000000000000', + CanonicalTransactionChain: '0x0000000000000000000000000000000000000000', + AddressManager: '0x3Ad319BB4872F8cB75a26Ac30CC4bD2d56b67b05', + L1CrossDomainMessenger: '0x635ba609680c55C3bDd0B3627b4c5dB21b13c310', + L1StandardBridge: '0x3B95bC951EE0f553ba487327278cAc44f29715E5', + OptimismPortal: '0x9168765EE952de7C6f8fC6FaD5Ec209B960b7622', + L2OutputOracle: '0x30c789674ad3B458886BBC9abf42EEe19EA05C1D', +}; + +module.exports = { + L1_TESTNET_CONTRACTS, + L1_MAINNET_CONTRACTS, +}; diff --git a/examples/manta/scripts/mantaTasks.js b/examples/manta/scripts/mantaTasks.js new file mode 100644 index 0000000..2364262 --- /dev/null +++ b/examples/manta/scripts/mantaTasks.js @@ -0,0 +1,116 @@ +const manta = require('@eth-optimism/sdk'); +const ethers = require('ethers'); +const { + syncBatchRoot, + syncL2Requests, + setValidator, + changeFeeParams, + encodeSetValidator, + encodeChangeFeeParams, +} = require('../../utils/opstack-utils'); +const { L1_MAINNET_CONTRACTS, L1_TESTNET_CONTRACTS } = require('./constants'); +const { task, types } = require('hardhat/config'); +require('dotenv').config(); + +async function initMessenger() { + const walletPrivateKey = process.env.DEVNET_PRIVKEY; + const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); + const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); + const ethereumName = process.env.ETHEREUM; + const mantaName = process.env.MANTA; + const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); + const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); + // https://github.com/Manta-Network/bridging-tutorial/blob/ad640a17264e2f009065811a0ff0872d8063b27b/standard-bridge-custom-token/README.md?plain=1#L152 + const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; + const messenger = new manta.CrossChainMessenger({ + l1ChainId: await l1Wallet.getChainId(), // 5 for Goerli, 1 for Ethereum + l2ChainId: await l2Wallet.getChainId(), // 3441005 for Manta Pacific Testnet, 169 for Manta Pacific Mainnet + l1SignerOrProvider: l1Wallet, + l2SignerOrProvider: l2Wallet, + bedrock: true, + contracts: { + l1: messengerL1Contracts, + }, + }); + + return { messenger, ethereumName, mantaName }; +} + +task('syncBatchRoot', 'Forward message to L2').setAction(async (_, hre) => { + const { messenger, ethereumName, mantaName } = await initMessenger(); + + const message = await syncBatchRoot(hre, messenger, ethereumName, mantaName, 'manta'); + // Waiting for the official manta bridge to forward the message to L2 + const rec = await messenger.waitForMessageReceipt(message); + console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); + console.log('Done'); + + // Example txs: + // https://goerli.etherscan.io/tx/0x12b283959163783e7faf186b70fd4513560a3a41f79099f56ae984c2ac81be6d + // https://pacific-explorer.testnet.manta.network/tx/0xbce746d631ac613b61f224138779cbcf3a2f744864b50443440c1c9346cc4c11 +}); + +task('syncL2Requests', 'Send sync point to arbitrator') + .addParam('txs', 'New sync point', 100, types.int, true) + .setAction(async (taskArgs, hre) => { + const txs = taskArgs.txs; + console.log(`The sync point: txs: ${txs}`); + + const { messenger, ethereumName, mantaName } = await initMessenger(); + + await syncL2Requests(hre, messenger, ethereumName, mantaName, 'manta', txs); + + console.log('Done!'); + + // Example txs: + // https://pacific-explorer.testnet.manta.network/tx/0x1a81ed28c1b74120753b0edf3d98e80b814ec5f065ad44b26c0cd6131dc04d22 + // https://goerli.etherscan.io/tx/0x54ce6421e1d9c1e7d2c35af292c9e3bbaf632b60115556a94b7fb61e53905599 + }); + +task('changeFeeParams', 'Change fee params for zkLink').setAction(async (_, hre) => { + const { messenger, ethereumName, mantaName } = await initMessenger(); + + const message = await changeFeeParams(hre, messenger, ethereumName, mantaName, 'manta'); + + // Waiting for the official manta bridge to forward the message to L2 + const rec = await messenger.waitForMessageReceipt(message); + console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); + console.log('Done'); +}); + +task('setValidator', 'Set validator for zkLink') + .addParam('validator', 'Validator Address', undefined, types.string) + .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) + .setAction(async (taskArgs, hre) => { + const validatorAddr = taskArgs.validator; + const isActive = taskArgs.active; + console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); + + const { messenger, ethereumName, mantaName } = await initMessenger(); + + const message = await setValidator(hre, messenger, ethereumName, mantaName, 'manta', validatorAddr, isActive); + + // Waiting for the official manta bridge to forward the message to L2 + const rec = await messenger.waitForMessageReceipt(message); + console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); + console.log('Done'); + }); + +task('encodeSetValidator', 'Get the calldata of set validator for zkLink') + .addParam('validator', 'Validator Address', undefined, types.string) + .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) + .setAction(async (taskArgs, hre) => { + const validatorAddr = taskArgs.validator; + const isActive = taskArgs.active; + console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); + + const { messenger, ethereumName, mantaName } = await initMessenger(); + + await encodeSetValidator(hre, messenger, ethereumName, mantaName, 'manta', validatorAddr, isActive); + }); + +task('encodeChangeFeeParams', 'Get the calldata of changing fee params for zkLink').setAction(async (_, hre) => { + const { messenger, ethereumName, mantaName } = await initMessenger(); + + await encodeChangeFeeParams(hre, messenger, ethereumName, mantaName, 'manta'); +}); diff --git a/examples/manta/scripts/setValidator.js b/examples/manta/scripts/setValidator.js deleted file mode 100644 index 22479a9..0000000 --- a/examples/manta/scripts/setValidator.js +++ /dev/null @@ -1,114 +0,0 @@ -const manta = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { task, types } = require('hardhat/config'); -require('dotenv').config(); - -task('setValidator', 'Set validator for zkLink') - .addParam('validator', 'Validator Address', undefined, types.string) - .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) - .setAction(async (taskArgs, hre) => { - const validatorAddr = taskArgs.validator; - const isActive = taskArgs.active; - console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); - - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const ethereumName = process.env.ETHEREUM; - const mantaName = process.env.MANTA; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - const messenger = new manta.CrossChainMessenger({ - l1ChainId: ethereumName !== 'ETHEREUM' ? 5 : 1, // 5 for Goerli, 1 for Ethereum - l2ChainId: ethereumName !== 'ETHEREUM' ? 3441005 : 169, // 3441005 for Manta Pacific Testnet, 169 for Manta Pacific Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - bedrock: true, - contracts: { - l1: { - StateCommitmentChain: '0x0000000000000000000000000000000000000000', - BondManager: '0x0000000000000000000000000000000000000000', - CanonicalTransactionChain: '0x0000000000000000000000000000000000000000', - AddressManager: '0x0AaeDFF2961D05021832cA093cf9409eDF5ECa8C', - L1CrossDomainMessenger: '0x7Ad11bB9216BC9Dc4CBd488D7618CbFD433d1E75', - L1StandardBridge: '0x4638aC6b5727a8b9586D3eba5B44Be4b74ED41Fc', - OptimismPortal: '0x7FD7eEA37c53ABf356cc80e71144D62CD8aF27d3', - L2OutputOracle: '0x8553D4d201ef97F2b76A28F5E543701b25e55B1b', - }, - }, - }); - - const l1WalletAddress = await l1Wallet.getAddress(); - const l1WalletBalance = ethers.utils.formatEther(await l1Wallet.getBalance()); - console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); - - const arbitratorAddr = readDeployContract( - logName.DEPLOY_ARBITRATOR_LOG_PREFIX, - logName.DEPLOY_LOG_ARBITRATOR, - ethereumName, - ); - if (arbitratorAddr === undefined) { - console.log('The arbitrator address not exist'); - return; - } - console.log(`The arbitrator address: ${arbitratorAddr}`); - - const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, mantaName); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, mantaName); - const mantaL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (mantaL1GatewayAddr === undefined) { - console.log('manta l1 gateway address not exist'); - return; - } - console.log(`The manta l1 gateway address: ${mantaL1GatewayAddr}`); - - const mantaL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - mantaName, - ); - if (mantaL2GatewayAddr === undefined) { - console.log('manta l2 gateway address not exist'); - return; - } - console.log(`The manta l2 gateway address: ${mantaL2GatewayAddr}`); - - const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); - const executeCalldata = zkLink.interface.encodeFunctionData('setValidator', [validatorAddr, isActive]); - const mantaL2Gateway = await hre.ethers.getContractAt('OptimismGateway', mantaL2GatewayAddr, l1Wallet); - const sendData = mantaL2Gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 1, // L2_TO_L1, Estimating the Gas Required on L2 - target: mantaL2GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - - // forward message to L2 - const arbitrator = await hre.ethers.getContractAt('Arbitrator', arbitratorAddr, l1Wallet); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - console.log('Prepare to forward the message to L2...'); - let tx = await arbitrator.setValidator(mantaL1GatewayAddr, validatorAddr, isActive, adapterParams); - const txHash = tx.hash; - await tx.wait(); - console.log(`The tx hash: ${txHash}`); - - /** - * Query the message informations on L1 via txHash. - */ - const message = (await messenger.getMessagesByTransaction(txHash)).pop(); - console.log(`The message: ${JSON.stringify(message)}`); - // Waiting for the official manta bridge to forward the message to L2 - const rec = await messenger.waitForMessageReceipt(message); - console.log(`The tx receipt: ${JSON.stringify(rec)}`); - console.log('Done'); - }); diff --git a/examples/manta/scripts/syncBatchRoot.js b/examples/manta/scripts/syncBatchRoot.js deleted file mode 100644 index 71536c8..0000000 --- a/examples/manta/scripts/syncBatchRoot.js +++ /dev/null @@ -1,119 +0,0 @@ -const manta = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { task } = require('hardhat/config'); -require('dotenv').config(); - -task('syncBatchRoot', 'Forward message to L2').setAction(async (taskArgs, hre) => { - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const ethereumName = process.env.ETHEREUM; - const mantaName = process.env.MANTA; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - // https://github.com/Manta-Network/bridging-tutorial/blob/ad640a17264e2f009065811a0ff0872d8063b27b/standard-bridge-custom-token/README.md?plain=1#L152 - const messenger = new manta.CrossChainMessenger({ - l1ChainId: ethereumName !== 'ETHEREUM' ? 5 : 1, // 5 for Goerli, 1 for Ethereum - l2ChainId: ethereumName !== 'ETHEREUM' ? 3441005 : 169, // 3441005 for Manta Pacific Testnet, 169 for Manta Pacific Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - bedrock: true, - contracts: { - l1: { - StateCommitmentChain: '0x0000000000000000000000000000000000000000', - BondManager: '0x0000000000000000000000000000000000000000', - CanonicalTransactionChain: '0x0000000000000000000000000000000000000000', - AddressManager: '0x0AaeDFF2961D05021832cA093cf9409eDF5ECa8C', - L1CrossDomainMessenger: '0x7Ad11bB9216BC9Dc4CBd488D7618CbFD433d1E75', - L1StandardBridge: '0x4638aC6b5727a8b9586D3eba5B44Be4b74ED41Fc', - OptimismPortal: '0x7FD7eEA37c53ABf356cc80e71144D62CD8aF27d3', - L2OutputOracle: '0x8553D4d201ef97F2b76A28F5E543701b25e55B1b', - }, - }, - }); - - const l1WalletAddress = await l1Wallet.getAddress(); - const l1WalletBalance = ethers.utils.formatEther(await l1Wallet.getBalance()); - console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); - - const arbitratorAddr = readDeployContract( - logName.DEPLOY_ARBITRATOR_LOG_PREFIX, - logName.DEPLOY_LOG_ARBITRATOR, - ethereumName, - ); - if (arbitratorAddr === undefined) { - console.log('The arbitrator address not exist'); - return; - } - console.log(`The arbitrator address: ${arbitratorAddr}`); - - const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, mantaName); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, mantaName); - const mantaL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (mantaL1GatewayAddr === undefined) { - console.log('manta l1 gateway address not exist'); - return; - } - console.log(`The manta l1 gateway address: ${mantaL1GatewayAddr}`); - - const mantaL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - mantaName, - ); - if (mantaL2GatewayAddr === undefined) { - console.log('manta l2 gateway address not exist'); - return; - } - console.log(`The manta l2 gateway address: ${mantaL2GatewayAddr}`); - - // pre-execution calldata - const zkLink = await hre.ethers.getContractAt('DummyZkLink', zkLinkAddr, l2Wallet); - const zklinkIface = zkLink.interface; - const blockNumber = await l2Provider.getBlockNumber(); - console.log(`The current block number: ${blockNumber}`); - const l2LogsRootHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(`L2 logs root hash ${blockNumber}`)); - console.log(`The l2 logs root hash: ${l2LogsRootHash}`); - const executeCalldata = zklinkIface.encodeFunctionData('syncBatchRoot', [blockNumber, l2LogsRootHash, 0]); - console.log(`The call data: ${executeCalldata}`); - const gateway = await hre.ethers.getContractAt('OptimismGateway', mantaL2GatewayAddr, l2Wallet); - const sendData = gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 1, // L2_TO_L1, Estimating the Gas Required on L2 - target: mantaL2GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - - // forward message to L2 - const arbitrator = await hre.ethers.getContractAt('DummyArbitrator', arbitratorAddr, l1Wallet); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - console.log('Prepare to forward the message to L2...'); - let tx = await arbitrator.forwardMessage(mantaL1GatewayAddr, 0, executeCalldata, adapterParams); - const txHash = tx.hash; - console.log(`The tx hash: ${txHash}`); - await tx.wait(); - console.log(`The transaction has been executed on L1`); - - /** - * Query the message informations on L1 via txHash. - */ - const message = (await messenger.getMessagesByTransaction(txHash)).pop(); - // Waiting for the official manta bridge to forward the message to L2 - const rec = await messenger.waitForMessageReceipt(message); - console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); - console.log('Done'); - - // Example txs: - // https://goerli.etherscan.io/tx/0x12b283959163783e7faf186b70fd4513560a3a41f79099f56ae984c2ac81be6d - // https://pacific-explorer.testnet.manta.network/tx/0xbce746d631ac613b61f224138779cbcf3a2f744864b50443440c1c9346cc4c11 -}); diff --git a/examples/manta/scripts/syncL2Requests.js b/examples/manta/scripts/syncL2Requests.js deleted file mode 100644 index 07f8780..0000000 --- a/examples/manta/scripts/syncL2Requests.js +++ /dev/null @@ -1,127 +0,0 @@ -const manta = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { task, types } = require('hardhat/config'); - -require('dotenv').config(); -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -task('syncL2Requests', 'Send sync point to arbitrator') - .addParam('txs', 'New sync point', 100, types.int, true) - .setAction(async (taskArgs, hre) => { - const txs = taskArgs.txs; - console.log(`The sync point: txs: ${txs}`); - - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const mantaName = process.env.MANTA; - const ethereumName = process.env.ETHEREUM; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - const messenger = new manta.CrossChainMessenger({ - l1ChainId: ethereumName !== 'ETHEREUM' ? 5 : 1, // 5 for Goerli, 1 for Ethereum - l2ChainId: ethereumName !== 'ETHEREUM' ? 3441005 : 169, // 3441005 for Manta Pacific Testnet, 169 for Manta Pacific Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - bedrock: true, - contracts: { - l1: { - StateCommitmentChain: '0x0000000000000000000000000000000000000000', - BondManager: '0x0000000000000000000000000000000000000000', - CanonicalTransactionChain: '0x0000000000000000000000000000000000000000', - AddressManager: '0x0AaeDFF2961D05021832cA093cf9409eDF5ECa8C', - L1CrossDomainMessenger: '0x7Ad11bB9216BC9Dc4CBd488D7618CbFD433d1E75', - L1StandardBridge: '0x4638aC6b5727a8b9586D3eba5B44Be4b74ED41Fc', - OptimismPortal: '0x7FD7eEA37c53ABf356cc80e71144D62CD8aF27d3', - L2OutputOracle: '0x8553D4d201ef97F2b76A28F5E543701b25e55B1b', - }, - }, - }); - - const l2WalletAddress = await l2Wallet.getAddress(); - const l2WalletBalance = ethers.utils.formatEther(await l2Wallet.getBalance()); - console.log(`${l2WalletAddress} balance on l2: ${l2WalletBalance} ether`); - - const mantaL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - mantaName, - ); - if (mantaL2GatewayAddr === undefined) { - console.log('manta l2 gateway address not exist'); - return; - } - console.log(`The manta l2 gateway address: ${mantaL2GatewayAddr}`); - - const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, mantaName); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - // send txs - const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); - console.log(`Send a l2 message to l1...`); - let tx = await zkLink.syncL2Requests(txs); - let txHash = tx.hash; - console.log(`The tx hash: ${txHash}`); - await tx.wait(); - console.log(`The transaction has been executed on L2`); - // txHash = "0x1a81ed28c1b74120753b0edf3d98e80b814ec5f065ad44b26c0cd6131dc04d22" - let status = await messenger.getMessageStatus(txHash); - console.log(`The message status update to: ${status}`); - - /** - * Wait until the message is ready to prove - * This step takes about 45 minutes. - */ - await messenger.waitForMessageStatus(txHash, manta.MessageStatus.READY_TO_PROVE); - /** - * Once the message is ready to be proven, you'll send an L1 transaction to prove that the message was sent on L2. - */ - console.log(`Proving the message...`); - tx = await messenger.proveMessage(txHash); - console.log(`The prove tx hash: ${tx.hash}`); - await tx.wait(); - console.log(`The message has been proven`); - status = await messenger.getMessageStatus(txHash); - console.log(`The message status update to: ${status}`); - /** - * Wait until the message is ready for relay - * The final step to sending messages from L2 to L1 is to relay the messages on L1. This can only happen after the fault proof period has elapsed. On OP Sepolia, this is only a few seconds. On OP Mainnet, this takes 7 days. - * Manta is same way as Optimism - */ - await messenger.waitForMessageStatus(txHash, manta.MessageStatus.READY_FOR_RELAY); - console.log(`The message is ready for relay`); - status = await messenger.getMessageStatus(txHash); - console.log(`The message status update to: ${status}`); - await sleep(12 * 1000); // 12 seconds, Waiting for a block to ensure the PROVE transaction is on the chain - /** - * Relay the message on L1 - * Once the withdrawal is ready to be relayed you can finally complete the message sending process. - */ - console.log(`Relaying the message...`); - tx = await messenger.finalizeMessage(txHash); - console.log(`The relay tx hash: ${tx.hash}`); - await tx.wait(); - console.log(`The message has been relayed`); - status = await messenger.getMessageStatus(txHash); - console.log(`The message status update to: ${status}`); - /** - * Wait until the message is relayed - * Now you simply wait until the message is relayed. - */ - // Waiting for the official manta bridge to forward the message to L2 - const rec = await messenger.waitForMessageReceipt(txHash); - console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); - console.log('Done!'); - - // Example txs: - // https://pacific-explorer.testnet.manta.network/tx/0x1a81ed28c1b74120753b0edf3d98e80b814ec5f065ad44b26c0cd6131dc04d22 - // https://goerli.etherscan.io/tx/0x54ce6421e1d9c1e7d2c35af292c9e3bbaf632b60115556a94b7fb61e53905599 - }); diff --git a/examples/optimism/hardhat.config.js b/examples/optimism/hardhat.config.js index ef15cb5..43bb537 100644 --- a/examples/optimism/hardhat.config.js +++ b/examples/optimism/hardhat.config.js @@ -1,8 +1,5 @@ require('@nomiclabs/hardhat-ethers'); -require('./scripts/syncL2Requests'); -require('./scripts/syncBatchRoot'); -require('./scripts/setValidator'); -require('./scripts/changeFeeParams'); +require('./scripts/optimismTasks'); const BaseConfig = require('../../hardhat.base.config'); diff --git a/examples/optimism/scripts/changeFeeParams.js b/examples/optimism/scripts/changeFeeParams.js deleted file mode 100644 index 7e32b7c..0000000 --- a/examples/optimism/scripts/changeFeeParams.js +++ /dev/null @@ -1,100 +0,0 @@ -const optimism = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { task } = require('hardhat/config'); -require('dotenv').config(); - -task('changeFeeParams', 'Change fee params for zkLink').setAction(async (taskArgs, hre) => { - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const ethereumName = process.env.ETHEREUM; - const optimismName = process.env.OPTIMISM; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - const messenger = new optimism.CrossChainMessenger({ - l1ChainId: ethereumName !== 'ETHEREUM' ? 11155111 : 1, // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: ethereumName !== 'ETHEREUM' ? 11155420 : 10, // 11155420 for OP Sepolia, 10 for OP Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - }); - - const l1WalletAddress = await l1Wallet.getAddress(); - const l1WalletBalance = ethers.utils.formatEther(await l1Wallet.getBalance()); - console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); - - const arbitratorAddr = readDeployContract( - logName.DEPLOY_ARBITRATOR_LOG_PREFIX, - logName.DEPLOY_LOG_ARBITRATOR, - ethereumName, - ); - if (arbitratorAddr === undefined) { - console.log('The arbitrator address not exist'); - return; - } - console.log(`The arbitrator address: ${arbitratorAddr}`); - - const zkLinkAddr = readDeployContract( - logName.DEPLOY_ZKLINK_LOG_PREFIX, - logName.DEPLOY_LOG_ZKLINK_PROXY, - optimismName, - ); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, optimismName); - const optimismL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (optimismL1GatewayAddr === undefined) { - console.log('optimism l1 gateway address not exist'); - return; - } - console.log(`The optimism l1 gateway address: ${optimismL1GatewayAddr}`); - - const optimismL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - optimismName, - ); - if (optimismL2GatewayAddr === undefined) { - console.log('optimism l2 gateway address not exist'); - return; - } - console.log(`The optimism l2 gateway address: ${optimismL2GatewayAddr}`); - - // pre-execution calldata - const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); - const { INIT_FEE_PARAMS } = require('../../../script/zksync_era'); - const executeCalldata = zkLink.interface.encodeFunctionData('changeFeeParams', [INIT_FEE_PARAMS]); - const optimismL2Gateway = await hre.ethers.getContractAt('OptimismGateway', optimismL2GatewayAddr, l1Wallet); - const sendData = optimismL2Gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 1, // L2_TO_L1, Estimating the Gas Required on L2 - target: optimismL2GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - - // forward message to L2 - const arbitrator = await hre.ethers.getContractAt('Arbitrator', arbitratorAddr, l1Wallet); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - console.log('Prepare to forward the message to L2...'); - let tx = await arbitrator.changeFeeParams(optimismL1GatewayAddr, INIT_FEE_PARAMS, adapterParams); - const txHash = tx.hash; - await tx.wait(); - console.log(`The tx hash: ${txHash}`); - - /** - * Query the message informations on L1 via txHash. - */ - const message = (await messenger.getMessagesByTransaction(txHash)).pop(); - console.log(`The message: ${JSON.stringify(message)}`); - // Waiting for the official optimism bridge to forward the message to L2 - const rec = await messenger.waitForMessageReceipt(message); - console.log(`The tx receipt: ${JSON.stringify(rec)}`); - console.log('Done'); -}); diff --git a/examples/optimism/scripts/optimismTasks.js b/examples/optimism/scripts/optimismTasks.js new file mode 100644 index 0000000..b278f31 --- /dev/null +++ b/examples/optimism/scripts/optimismTasks.js @@ -0,0 +1,108 @@ +const optimism = require('@eth-optimism/sdk'); +const ethers = require('ethers'); +const { + syncBatchRoot, + syncL2Requests, + setValidator, + changeFeeParams, + encodeSetValidator, + encodeChangeFeeParams, +} = require('../../utils/opstack-utils'); +const { task, types } = require('hardhat/config'); +require('dotenv').config(); + +async function initMessenger() { + const walletPrivateKey = process.env.DEVNET_PRIVKEY; + const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); + const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); + const ethereumName = process.env.ETHEREUM; + const optimismName = process.env.OPTIMISM; + const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); + const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); + const messenger = new optimism.CrossChainMessenger({ + l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum + l2ChainId: await l2Wallet.getChainId(), // 11155420 for OP Sepolia, 10 for OP Mainnet + l1SignerOrProvider: l1Wallet, + l2SignerOrProvider: l2Wallet, + }); + + return { messenger, ethereumName, optimismName }; +} + +task('syncBatchRoot', 'Forward message to L2').setAction(async (_, hre) => { + const { messenger, ethereumName, optimismName } = await initMessenger(); + + const message = await syncBatchRoot(hre, messenger, ethereumName, optimismName, 'optimism'); + // Waiting for the official optimism bridge to forward the message to L2 + const rec = await messenger.waitForMessageReceipt(message); + console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); + console.log('Done'); + + // Example txs: + // https://sepolia.etherscan.io/tx/0x4245b341b159a79d6cf35b917b849ccc8d5b3ae6fac947bc7376650844bdc43c + // https://sepolia-optimistic.etherscan.io/tx/0x7779fbaf0358f34d2303d77019d09c39a0a0b178d9f6c4235c7bc5519ba9b58b +}); + +task('syncL2Requests', 'Send sync point to arbitrator') + .addParam('txs', 'New sync point', 100, types.int, true) + .setAction(async (taskArgs, hre) => { + const txs = taskArgs.txs; + console.log(`The sync point: txs: ${txs}`); + + const { messenger, ethereumName, optimismName } = await initMessenger(); + + await syncL2Requests(hre, messenger, ethereumName, optimismName, 'optimism', txs); + + console.log('Done! Your transaction is executed'); + + // Example txs: + // https://sepolia-optimistic.etherscan.io/tx/0xd1be4141ad192ddb978bfb324aaa41c2bddfdabce159de710e658db98d7c6885 + // https://sepolia.etherscan.io/tx/0x18be026ceed349625363f84a75c0384e69c549a972d79e78f327c2a1647a183d + }); + +task('setValidator', 'Set validator for zkLink') + .addParam('validator', 'Validator Address', undefined, types.string) + .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) + .setAction(async (taskArgs, hre) => { + const validatorAddr = taskArgs.validator; + const isActive = taskArgs.active; + console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); + + const { messenger, ethereumName, optimismName } = await initMessenger(); + + const message = await setValidator(hre, messenger, ethereumName, optimismName, 'optimism', validatorAddr, isActive); + // Waiting for the official optimism bridge to forward the message to L2 + const rec = await messenger.waitForMessageReceipt(message); + console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); + console.log('Done'); + }); + +task('changeFeeParams', 'Change fee params for zkLink').setAction(async (_, hre) => { + const { messenger, ethereumName, optimismName } = await initMessenger(); + + const message = await changeFeeParams(hre, messenger, ethereumName, optimismName, 'optimism'); + + // Waiting for the official optimism bridge to forward the message to L2 + const rec = await messenger.waitForMessageReceipt(message); + console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); + console.log('Done'); +}); + +task('encodeSetValidator', 'Get the calldata of set validator for zkLink') + .addParam('validator', 'Validator Address', undefined, types.string) + .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) + .setAction(async (taskArgs, hre) => { + const validatorAddr = taskArgs.validator; + const isActive = taskArgs.active; + console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); + + const { messenger, ethereumName, optimismName } = await initMessenger(); + + await encodeSetValidator(hre, messenger, ethereumName, optimismName, 'optimism', validatorAddr, isActive); + }); + +task('encodeChangeFeeParams', 'Get the calldata of changing fee params for zkLink').setAction(async (_, hre) => { + const { messenger, ethereumName, optimismName } = await initMessenger(); + + await encodeChangeFeeParams(hre, messenger, ethereumName, optimismName, 'optimism'); +}); diff --git a/examples/optimism/scripts/setValidator.js b/examples/optimism/scripts/setValidator.js deleted file mode 100644 index 81f3856..0000000 --- a/examples/optimism/scripts/setValidator.js +++ /dev/null @@ -1,105 +0,0 @@ -const optimism = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { task, types } = require('hardhat/config'); -require('dotenv').config(); - -task('setValidator', 'Set validator for zkLink') - .addParam('validator', 'Validator Address', undefined, types.string) - .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) - .setAction(async (taskArgs, hre) => { - const validatorAddr = taskArgs.validator; - const isActive = taskArgs.active; - console.log(`The validator: address: ${validatorAddr}, active: ${isActive}`); - - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const ethereumName = process.env.ETHEREUM; - const optimismName = process.env.OPTIMISM; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - const messenger = new optimism.CrossChainMessenger({ - l1ChainId: ethereumName !== 'ETHEREUM' ? 11155111 : 1, // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: ethereumName !== 'ETHEREUM' ? 11155420 : 10, // 11155420 for OP Sepolia, 10 for OP Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - }); - - const l1WalletAddress = await l1Wallet.getAddress(); - const l1WalletBalance = ethers.utils.formatEther(await l1Wallet.getBalance()); - console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); - - const arbitratorAddr = readDeployContract( - logName.DEPLOY_ARBITRATOR_LOG_PREFIX, - logName.DEPLOY_LOG_ARBITRATOR, - ethereumName, - ); - if (arbitratorAddr === undefined) { - console.log('The arbitrator address not exist'); - return; - } - console.log(`The arbitrator address: ${arbitratorAddr}`); - - const zkLinkAddr = readDeployContract( - logName.DEPLOY_ZKLINK_LOG_PREFIX, - logName.DEPLOY_LOG_ZKLINK_PROXY, - optimismName, - ); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, optimismName); - const optimismL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (optimismL1GatewayAddr === undefined) { - console.log('optimism l1 gateway address not exist'); - return; - } - console.log(`The optimism l1 gateway address: ${optimismL1GatewayAddr}`); - - const optimismL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - optimismName, - ); - if (optimismL2GatewayAddr === undefined) { - console.log('optimism l2 gateway address not exist'); - return; - } - console.log(`The optimism l2 gateway address: ${optimismL2GatewayAddr}`); - - const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); - const executeCalldata = zkLink.interface.encodeFunctionData('setValidator', [validatorAddr, isActive]); - const optimismL2Gateway = await hre.ethers.getContractAt('OptimismGateway', optimismL2GatewayAddr, l1Wallet); - const sendData = optimismL2Gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 1, // L2_TO_L1, Estimating the Gas Required on L2 - target: optimismL2GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - - // forward message to L2 - const arbitrator = await hre.ethers.getContractAt('Arbitrator', arbitratorAddr, l1Wallet); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - console.log('Prepare to forward the message to L2...'); - let tx = await arbitrator.setValidator(optimismL1GatewayAddr, validatorAddr, isActive, adapterParams); - const txHash = tx.hash; - await tx.wait(); - console.log(`The tx hash: ${txHash}`); - - /** - * Query the message informations on L1 via txHash. - */ - const message = (await messenger.getMessagesByTransaction(txHash)).pop(); - console.log(`The message: ${JSON.stringify(message)}`); - // Waiting for the official optimism bridge to forward the message to L2 - const rec = await messenger.waitForMessageReceipt(message); - console.log(`The tx receipt: ${JSON.stringify(rec)}`); - console.log('Done'); - }); diff --git a/examples/optimism/scripts/syncBatchRoot.js b/examples/optimism/scripts/syncBatchRoot.js deleted file mode 100644 index 4e1739e..0000000 --- a/examples/optimism/scripts/syncBatchRoot.js +++ /dev/null @@ -1,110 +0,0 @@ -const optimism = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { task } = require('hardhat/config'); -require('dotenv').config(); - -task('syncBatchRoot', 'Forward message to L2').setAction(async (taskArgs, hre) => { - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const ethereumName = process.env.ETHEREUM; - const optimismName = process.env.OPTIMISM; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - const messenger = new optimism.CrossChainMessenger({ - l1ChainId: ethereumName !== 'ETHEREUM' ? 11155111 : 1, // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: ethereumName !== 'ETHEREUM' ? 11155420 : 10, // 11155420 for OP Sepolia, 10 for OP Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - }); - - const l1WalletAddress = await l1Wallet.getAddress(); - const l1WalletBalance = ethers.utils.formatEther(await l1Wallet.getBalance()); - console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); - - const arbitratorAddr = readDeployContract( - logName.DEPLOY_ARBITRATOR_LOG_PREFIX, - logName.DEPLOY_LOG_ARBITRATOR, - ethereumName, - ); - if (arbitratorAddr === undefined) { - console.log('The arbitrator address not exist'); - return; - } - console.log(`The arbitrator address: ${arbitratorAddr}`); - - const zkLinkAddr = readDeployContract( - logName.DEPLOY_ZKLINK_LOG_PREFIX, - logName.DEPLOY_LOG_ZKLINK_PROXY, - optimismName, - ); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, optimismName); - const optimismL1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); - if (optimismL1GatewayAddr === undefined) { - console.log('optimism l1 gateway address not exist'); - return; - } - console.log(`The optimism l1 gateway address: ${optimismL1GatewayAddr}`); - - const optimismL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - optimismName, - ); - if (optimismL2GatewayAddr === undefined) { - console.log('optimism l2 gateway address not exist'); - return; - } - console.log(`The optimism l2 gateway address: ${optimismL2GatewayAddr}`); - - // pre-execution calldata - const zkLink = await hre.ethers.getContractAt('DummyZkLink', zkLinkAddr, l2Wallet); - const zklinkIface = zkLink.interface; - const blockNumber = await l2Provider.getBlockNumber(); - console.log(`The current block number: ${blockNumber}`); - const l2LogsRootHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(`L2 logs root hash ${blockNumber}`)); - console.log(`The l2 logs root hash: ${l2LogsRootHash}`); - const executeCalldata = zklinkIface.encodeFunctionData('syncBatchRoot', [blockNumber, l2LogsRootHash, 0]); - console.log(`The call data: ${executeCalldata}`); - const optimismL2Gateway = await hre.ethers.getContractAt('OptimismGateway', optimismL2GatewayAddr, l1Wallet); - const sendData = optimismL2Gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); - - const gasLimit = await messenger.estimateGas.sendMessage({ - direction: 1, // L2_TO_L1, Estimating the Gas Required on L2 - target: optimismL2GatewayAddr, - message: sendData, - }); - console.log(`The gas limit: ${gasLimit}`); - - // forward message to L2 - const arbitrator = await hre.ethers.getContractAt('DummyArbitrator', arbitratorAddr, l1Wallet); - const adapterParams = ethers.utils.defaultAbiCoder.encode(['uint256'], [gasLimit]); - console.log('Prepare to forward the message to L2...'); - let tx = await arbitrator.forwardMessage(optimismL1GatewayAddr, 0, executeCalldata, adapterParams); - const txHash = tx.hash; - await tx.wait(); - console.log(`The tx hash: ${txHash}`); - // const txHash = "0x61e78c71aca383f9e15ccebae7ecca355131227319a80a338ac9f809d752a344"; - - /** - * Query the message informations on L1 via txHash. - */ - const message = (await messenger.getMessagesByTransaction(txHash)).pop(); - console.log(`The message: ${JSON.stringify(message)}`); - // Waiting for the official optimism bridge to forward the message to L2 - const rec = await messenger.waitForMessageReceipt(message); - console.log(`The tx receipt: ${JSON.stringify(rec)}`); - console.log('Done'); - - // Example txs: - // https://sepolia.etherscan.io/tx/0x4245b341b159a79d6cf35b917b849ccc8d5b3ae6fac947bc7376650844bdc43c - // https://sepolia-optimistic.etherscan.io/tx/0x7779fbaf0358f34d2303d77019d09c39a0a0b178d9f6c4235c7bc5519ba9b58b -}); diff --git a/examples/optimism/scripts/syncL2Requests.js b/examples/optimism/scripts/syncL2Requests.js deleted file mode 100644 index 67b6d32..0000000 --- a/examples/optimism/scripts/syncL2Requests.js +++ /dev/null @@ -1,96 +0,0 @@ -const optimism = require('@eth-optimism/sdk'); -const ethers = require('ethers'); -const { readDeployContract } = require('../../../script/utils'); -const logName = require('../../../script/deploy_log_name'); -const { task, types } = require('hardhat/config'); - -require('dotenv').config(); - -task('syncL2Requests', 'Send sync point to arbitrator') - .addParam('txs', 'New sync point', 100, types.int, true) - .setAction(async (taskArgs, hre) => { - const txs = taskArgs.txs; - console.log(`The sync point: txs: ${txs}`); - - const walletPrivateKey = process.env.DEVNET_PRIVKEY; - const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); - const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); - const optimismName = process.env.OPTIMISM; - const ethereumName = process.env.ETHEREUM; - const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); - const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - const messenger = new optimism.CrossChainMessenger({ - l1ChainId: ethereumName !== 'ETHEREUM' ? 11155111 : 1, // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: ethereumName !== 'ETHEREUM' ? 11155420 : 10, // 11155420 for OP Sepolia, 10 for OP Mainnet - l1SignerOrProvider: l1Wallet, - l2SignerOrProvider: l2Wallet, - }); - - const l2WalletAddress = await l2Wallet.getAddress(); - const l2WalletBalance = ethers.utils.formatEther(await l2Wallet.getBalance()); - console.log(`${l2WalletAddress} balance on l2: ${l2WalletBalance} ether`); - - const optimismL2GatewayAddr = readDeployContract( - logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, - logName.DEPLOY_GATEWAY, - optimismName, - ); - if (optimismL2GatewayAddr === undefined) { - console.log('optimism l2 gateway address not exist'); - return; - } - console.log(`The optimism l2 gateway address: ${optimismL2GatewayAddr}`); - - const zkLinkAddr = readDeployContract( - logName.DEPLOY_ZKLINK_LOG_PREFIX, - logName.DEPLOY_LOG_ZKLINK_PROXY, - optimismName, - ); - if (zkLinkAddr === undefined) { - console.log('zkLink address not exist'); - return; - } - console.log(`The zkLink address: ${zkLinkAddr}`); - - // send txs - const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); - console.log(`Send a l2 message to l1...`); - let tx = await zkLink.syncL2Requests(txs); - let txHash = tx.hash; - await tx.wait(); - console.log(`The tx hash: ${txHash}`); - - /** - * Wait until the message is ready to prove - * This step can take a few minutes. - */ - await messenger.waitForMessageStatus(txHash, optimism.MessageStatus.READY_TO_PROVE); - /** - * Once the message is ready to be proven, you'll send an L1 transaction to prove that the message was sent on L2. - */ - await messenger.proveMessage(txHash); - /** - * Wait until the message is ready for relay - * The final step to sending messages from L2 to L1 is to relay the messages on L1. This can only happen after the fault proof period has elapsed. On OP Sepolia, this is only a few seconds. On OP Mainnet, this takes 7 days. - */ - await messenger.waitForMessageStatus(txHash, optimism.MessageStatus.READY_FOR_RELAY); - /** - * Relay the message on L1 - * Once the withdrawal is ready to be relayed you can finally complete the message sending process. - */ - await messenger.finalizeMessage(txHash); - /** - * Wait until the message is relayed - * Now you simply wait until the message is relayed. - */ - await messenger.waitForMessageStatus(txHash, optimism.MessageStatus.RELAYED); - const message = (await messenger.getMessagesByTransaction(txHash)).pop(); - // Waiting for the official optimism bridge to forward the message to L2 - const rec = await messenger.waitForMessageReceipt(message); - console.log(`The tx receipt: ${JSON.stringify(rec)}`); - console.log('Done! Your transaction is executed'); - - // Example txs: - // https://sepolia-optimistic.etherscan.io/tx/0xd1be4141ad192ddb978bfb324aaa41c2bddfdabce159de710e658db98d7c6885 - // https://sepolia.etherscan.io/tx/0x18be026ceed349625363f84a75c0384e69c549a972d79e78f327c2a1647a183d - }); diff --git a/examples/utils/opstack-utils.js b/examples/utils/opstack-utils.js new file mode 100644 index 0000000..537336d --- /dev/null +++ b/examples/utils/opstack-utils.js @@ -0,0 +1,353 @@ +const ethers = require('ethers'); +const { readDeployContract, getLogName } = require('../../script/utils'); +const logName = require('../../script/deploy_log_name'); +const { INIT_FEE_PARAMS } = require('../../script/zksync_era'); + +const MessageStatus = { + UNCONFIRMED_L1_TO_L2_MESSAGE: 0, + FAILED_L1_TO_L2_MESSAGE: 1, + STATE_ROOT_NOT_PUBLISHED: 2, + READY_TO_PROVE: 3, + IN_CHALLENGE_PERIOD: 4, + READY_FOR_RELAY: 5, + RELAYED: 6, +}; + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +async function getContractAddresses(ethereumName, opChainName, chainName) { + if (chainName === undefined) { + chainName = 'op stack chain'; + } + + const arbitratorAddr = readDeployContract( + logName.DEPLOY_ARBITRATOR_LOG_PREFIX, + logName.DEPLOY_LOG_ARBITRATOR, + ethereumName, + ); + if (arbitratorAddr === undefined) { + console.log('The arbitrator address not exist'); + return; + } + console.log(`The arbitrator address: ${arbitratorAddr}`); + + const zkLinkAddr = readDeployContract(logName.DEPLOY_ZKLINK_LOG_PREFIX, logName.DEPLOY_LOG_ZKLINK_PROXY, opChainName); + if (zkLinkAddr === undefined) { + console.log('zkLink address not exist'); + return; + } + console.log(`The zkLink address: ${zkLinkAddr}`); + + const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, opChainName); + const l1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); + if (l1GatewayAddr === undefined) { + console.log(`${chainName} l1 gateway address not exist`); + return; + } + console.log(`The ${chainName} l1 gateway address: ${l1GatewayAddr}`); + + const l2GatewayAddr = readDeployContract(logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, logName.DEPLOY_GATEWAY, opChainName); + if (l2GatewayAddr === undefined) { + console.log(`${chainName} l2 gateway address not exist`); + return; + } + console.log(`The ${chainName} l2 gateway address: ${l2GatewayAddr}`); + + return { + arbitratorAddr, + zkLinkAddr, + l1GatewayAddr, + l2GatewayAddr, + }; +} + +async function generateAdapterParams(hre, messenger, l2GatewayAddr, executeCalldata) { + const l2Gateway = await hre.ethers.getContractAt('IMessageClaimer', l2GatewayAddr); + const sendData = l2Gateway.interface.encodeFunctionData('claimMessageCallback', [0, executeCalldata]); + + const gasLimit = await messenger.estimateGas.sendMessage({ + direction: 1, // L2_TO_L1, Estimating the Gas Required on L2 + target: l2GatewayAddr, + message: sendData, + }); + console.log(`The gas limit: ${gasLimit.toString()}`); + + const adapterParams = ethers.AbiCoder.defaultAbiCoder().encode(['uint256'], [gasLimit.toString()]); + console.log(`The adapter params: ${adapterParams}`); + + return adapterParams; +} + +async function syncBatchRoot(hre, messenger, ethereumName, opChainName, chainName) { + const { arbitratorAddr, zkLinkAddr, l1GatewayAddr, l2GatewayAddr } = await getContractAddresses( + ethereumName, + opChainName, + chainName, + ); + const l1Wallet = messenger.l1Signer; + const l2Provider = messenger.l2Provider; + + const l1WalletAddress = await l1Wallet.getAddress(); + const l1WalletBalance = ethers.formatEther((await l1Wallet.getBalance()).toString()); + console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); + + // pre-execution calldata + const zkLink = await hre.ethers.getContractAt('DummyZkLink', zkLinkAddr); + const zklinkIface = zkLink.interface; + const blockNumber = await l2Provider.getBlockNumber(); + console.log(`The current block number on l1: ${blockNumber}`); + const l2LogsRootHash = ethers.keccak256(ethers.toUtf8Bytes(`L2 logs root hash ${blockNumber}`)); + console.log(`The l2 logs root hash: ${l2LogsRootHash}`); + const executeCalldata = zklinkIface.encodeFunctionData('syncBatchRoot', [blockNumber, l2LogsRootHash, 0]); + console.log(`The call data: ${executeCalldata}`); + const adapterParams = await generateAdapterParams(hre, messenger, l2GatewayAddr, executeCalldata); + // forward message to L2 + const arbitrator = await hre.ethers.getContractAt('DummyArbitrator', arbitratorAddr, l1Wallet); + const sendData = arbitrator.interface.encodeFunctionData('forwardMessage', [ + l1GatewayAddr, + 0, + executeCalldata, + adapterParams, + ]); + const feeData = await l1Wallet.getFeeData(); + const gasLimit = await l1Wallet.provider.estimateGas({ + from: l1Wallet.address, + to: arbitratorAddr, + data: sendData, + }); + console.log('Prepare to forward the message to L2...'); + let tx = await arbitrator.forwardMessage(l1GatewayAddr, 0, executeCalldata, adapterParams, { + maxFeePerGas: feeData.maxFeePerGas.mul(2), + maxPriorityFeePerGas: feeData.maxPriorityFeePerGas.mul(2), + gasLimit: gasLimit.mul(2), + }); + const txHash = tx.hash; + console.log(`The tx hash: ${txHash}`); + await tx.wait(); + console.log(`The transaction has been executed on L1`); + // const txHash = "0x61e78c71aca383f9e15ccebae7ecca355131227319a80a338ac9f809d752a344"; + + /** + * Query the message informations on L1 via txHash. + */ + const message = (await messenger.getMessagesByTransaction(txHash)).pop(); + console.log(`The message: ${JSON.stringify(message)}`); + + return message; +} + +async function setValidator(hre, messenger, ethereumName, opChainName, chainName, validatorAddr, isActive) { + const { arbitratorAddr, zkLinkAddr, l1GatewayAddr, l2GatewayAddr } = await getContractAddresses( + ethereumName, + opChainName, + chainName, + ); + const l1Wallet = messenger.l1Signer; + const l1WalletAddress = await l1Wallet.getAddress(); + const l1WalletBalance = ethers.formatEther((await l1Wallet.getBalance()).toString()); + console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); + + // pre-execution calldata + const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr); + const executeCalldata = zkLink.interface.encodeFunctionData('setValidator', [validatorAddr, isActive]); + const adapterParams = await generateAdapterParams(hre, messenger, l2GatewayAddr, executeCalldata); + + // forward message to L2 + const arbitrator = await hre.ethers.getContractAt('Arbitrator', arbitratorAddr, l1Wallet); + const sendData = arbitrator.interface.encodeFunctionData('setValidator', [ + l1GatewayAddr, + validatorAddr, + isActive, + adapterParams, + ]); + const feeData = await l1Wallet.getFeeData(); + const gasLimit = await l1Wallet.provider.estimateGas({ + from: l1Wallet.address, + to: arbitratorAddr, + data: sendData, + }); + console.log('Prepare to forward the message to L2...'); + let tx = await arbitrator.setValidator(l1GatewayAddr, validatorAddr, isActive, adapterParams, { + maxFeePerGas: feeData.maxFeePerGas.mul(2), + maxPriorityFeePerGas: feeData.maxPriorityFeePerGas.mul(2), + gasLimit: gasLimit.mul(2), + }); + const txHash = tx.hash; + console.log(`The tx hash: ${txHash}`); + await tx.wait(); + console.log(`The transaction has been executed on L1`); + + /** + * Query the message informations on L1 via txHash. + */ + const message = (await messenger.getMessagesByTransaction(txHash)).pop(); + console.log(`The message: ${JSON.stringify(message)}`); + + return message; +} + +async function changeFeeParams(hre, messenger, ethereumName, opChainName, chainName) { + const { arbitratorAddr, zkLinkAddr, l1GatewayAddr, l2GatewayAddr } = await getContractAddresses( + ethereumName, + opChainName, + chainName, + ); + const l1Wallet = messenger.l1Signer; + const l1WalletAddress = await l1Wallet.getAddress(); + const l1WalletBalance = ethers.formatEther((await l1Wallet.getBalance()).toString()); + console.log(`${l1WalletAddress} balance on l1: ${l1WalletBalance} ether`); + + // pre-execution calldata + const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr); + const executeCalldata = zkLink.interface.encodeFunctionData('changeFeeParams', [INIT_FEE_PARAMS]); + const adapterParams = await generateAdapterParams(hre, messenger, l2GatewayAddr, executeCalldata); + + // forward message to L2 + const arbitrator = await hre.ethers.getContractAt('Arbitrator', arbitratorAddr, l1Wallet); + const sendData = arbitrator.interface.encodeFunctionData('changeFeeParams', [ + l1GatewayAddr, + INIT_FEE_PARAMS, + adapterParams, + ]); + const feeData = await l1Wallet.getFeeData(); + const gasLimit = await l1Wallet.provider.estimateGas({ + from: l1Wallet.address, + to: arbitratorAddr, + data: sendData, + }); + console.log('Prepare to forward the message to L2...'); + let tx = await arbitrator.changeFeeParams(l1GatewayAddr, INIT_FEE_PARAMS, adapterParams, { + maxFeePerGas: feeData.maxFeePerGas.mul(2), + maxPriorityFeePerGas: feeData.maxPriorityFeePerGas.mul(2), + gasLimit: gasLimit.mul(2), + }); + const txHash = tx.hash; + console.log(`The tx hash: ${txHash}`); + await tx.wait(); + console.log(`The transaction has been executed on L1`); + + /** + * Query the message informations on L1 via txHash. + */ + const message = (await messenger.getMessagesByTransaction(txHash)).pop(); + console.log(`The message: ${JSON.stringify(message)}`); + + return message; +} + +async function syncL2Requests(hre, messenger, ethereumName, opChainName, chainName, txs) { + const { zkLinkAddr } = await getContractAddresses(ethereumName, opChainName, chainName); + const l2Wallet = messenger.l2Signer; + const l1Wallet = messenger.l1Signer; + + const l2WalletAddress = await l2Wallet.getAddress(); + const l2WalletBalance = ethers.formatEther((await l2Wallet.getBalance()).toString()); + console.log(`${l2WalletAddress} balance on l2: ${l2WalletBalance} ether`); + + const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); + const calldata = zkLink.interface.encodeFunctionData('syncL2Requests', [txs]); + const gasLimit = await l2Wallet.provider.estimateGas({ + from: l2Wallet.address, + to: zkLinkAddr, + data: calldata, + }); + console.log(`The gas limit: ${gasLimit}`); + console.log(`Send a l2 message to l1...`); + let tx = await zkLink.syncL2Requests(txs, { + gasLimit: gasLimit, + }); + let txHash = tx.hash; + console.log(`The tx hash: ${txHash}`); + await tx.wait(); + console.log(`The transaction has been executed on L2`); + + // const txHash = "0xcebb6da21e5992821a897bdcbf8fbf00dda22d46881a0ebe29d390cdc3150631"; + const status = await messenger.getMessageStatus(txHash); + console.log(`The message status update to: ${status}`); + const feeData = await l1Wallet.getFeeData(); + console.log(`The fee data: ${JSON.stringify(feeData)}`); + /** + * Wait until the message is ready to prove + * This step can take a few minutes. + */ + await messenger.waitForMessageStatus(txHash, MessageStatus.READY_TO_PROVE); + /** + * Once the message is ready to be proven, you'll send an L1 transaction to prove that the message was sent on L2. + */ + console.log(`Proving the message...`); + tx = await messenger.proveMessage(txHash, { + maxFeePerGas: feeData.maxFeePerGas.mul(2), + maxPriorityFeePerGas: feeData.maxPriorityFeePerGas.mul(2), + }); + console.log(`The prove tx hash: ${tx.hash}`); + await tx.wait(); + console.log(`The message has been proven`); + await sleep(60 * 1000); // wait for 60 seconds + /** + * Wait until the message is ready for relay + * The final step to sending messages from L2 to L1 is to relay the messages on L1. This can only happen after the fault proof period has elapsed. On OP Sepolia, this is only a few seconds. On OP Mainnet, this takes 7 days. + */ + await messenger.waitForMessageStatus(txHash, MessageStatus.READY_FOR_RELAY); + /** + * Relay the message on L1 + * Once the withdrawal is ready to be relayed you can finally complete the message sending process. + */ + console.log(`Relaying the message...`); + tx = await messenger.finalizeMessage(txHash, { + maxFeePerGas: feeData.maxFeePerGas.mul(2), + maxPriorityFeePerGas: feeData.maxPriorityFeePerGas.mul(2), + }); + console.log(`The relay tx hash: ${tx.hash}`); + await tx.wait(); + console.log(`The message has been relayed`); +} + +async function encodeSetValidator(hre, messenger, ethereumName, opChainName, chainName, validatorAddr, isActive) { + const { zkLinkAddr, l1GatewayAddr, l2GatewayAddr } = await getContractAddresses(ethereumName, opChainName, chainName); + // pre-execution calldata + const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr); + const executeCalldata = zkLink.interface.encodeFunctionData('setValidator', [validatorAddr, isActive]); + const adapterParams = await generateAdapterParams(hre, messenger, l2GatewayAddr, executeCalldata); + + const arbitratorFactory = await hre.ethers.getContractFactory('Arbitrator'); + const calldata = arbitratorFactory.interface.encodeFunctionData('setValidator', [ + l1GatewayAddr, + validatorAddr, + isActive, + adapterParams, + ]); + console.log(`The setValidator calldata: ${calldata}`); + + return calldata; +} + +async function encodeChangeFeeParams(hre, messenger, ethereumName, opChainName, chainName) { + const { zkLinkAddr, l1GatewayAddr, l2GatewayAddr } = await getContractAddresses(ethereumName, opChainName, chainName); + // pre-execution calldata + const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr); + console.log(`The zkLink address: ${zkLink.address}`); + const executeCalldata = zkLink.interface.encodeFunctionData('changeFeeParams', [INIT_FEE_PARAMS]); + const adapterParams = await generateAdapterParams(hre, messenger, l2GatewayAddr, executeCalldata); + + const arbitratorFactory = await hre.ethers.getContractFactory('Arbitrator'); + const calldata = arbitratorFactory.interface.encodeFunctionData('changeFeeParams', [ + l1GatewayAddr, + INIT_FEE_PARAMS, + adapterParams, + ]); + console.log(`The changeFeeParams calldata: ${calldata}`); + + return calldata; +} + +module.exports = { + getContractAddresses, + syncBatchRoot, + setValidator, + changeFeeParams, + syncL2Requests, + encodeSetValidator, + encodeChangeFeeParams, +}; diff --git a/script/ChainConfig.json b/script/ChainConfig.json index f18d070..85d2cef 100644 --- a/script/ChainConfig.json +++ b/script/ChainConfig.json @@ -240,9 +240,9 @@ "initializeParams": [] }, "l1Gateway": { - "netName": "GOERLI", + "netName": "SEPOLIA", "contractName": "OptimismL1Gateway", - "constructParams": ["0x7Ad11bB9216BC9Dc4CBd488D7618CbFD433d1E75"], + "constructParams": ["0xFe7cF31c4579bb1C578716e04E1Ae16Ac5549fF0"], "initializeParams": [] } },