From cd7932494bac1e4f03e937ad6e9c2e78185975a0 Mon Sep 17 00:00:00 2001 From: gzeon Date: Mon, 12 Feb 2024 16:43:36 +0800 Subject: [PATCH 1/6] refactor: deployment utils --- scripts/deployment.ts | 159 +----------------------------------- scripts/deploymentUtils.ts | 161 +++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+), 158 deletions(-) create mode 100644 scripts/deploymentUtils.ts diff --git a/scripts/deployment.ts b/scripts/deployment.ts index 01162c55..fdb51877 100644 --- a/scripts/deployment.ts +++ b/scripts/deployment.ts @@ -1,163 +1,6 @@ import { ethers } from 'hardhat' -import { ContractFactory, Contract } from 'ethers' import '@nomiclabs/hardhat-ethers' -import { run } from 'hardhat' -import { - abi as UpgradeExecutorABI, - bytecode as UpgradeExecutorBytecode, -} from '@offchainlabs/upgrade-executor/build/contracts/src/UpgradeExecutor.sol/UpgradeExecutor.json' -import { maxDataSize } from './config' - -// Define a verification function -async function verifyContract( - contractName: string, - contractAddress: string, - constructorArguments: any[] = [], - contractPathAndName?: string // optional -): Promise { - try { - if (process.env.DISABLE_VERIFICATION) return - // Define the verification options with possible 'contract' property - const verificationOptions: { - contract?: string - address: string - constructorArguments: any[] - } = { - address: contractAddress, - constructorArguments: constructorArguments, - } - - // if contractPathAndName is provided, add it to the verification options - if (contractPathAndName) { - verificationOptions.contract = contractPathAndName - } - - await run('verify:verify', verificationOptions) - console.log(`Verified contract ${contractName} successfully.`) - } catch (error: any) { - if (error.message.includes('Already Verified')) { - console.log(`Contract ${contractName} is already verified.`) - } else { - console.error( - `Verification for ${contractName} failed with the following error: ${error.message}` - ) - } - } -} - -// Function to handle contract deployment -async function deployContract( - contractName: string, - signer: any, - constructorArgs: any[] = [], - verify: boolean = true -): Promise { - const factory: ContractFactory = await ethers.getContractFactory(contractName) - const connectedFactory: ContractFactory = factory.connect(signer) - const contract: Contract = await connectedFactory.deploy(...constructorArgs) - await contract.deployTransaction.wait() - console.log(`New ${contractName} created at address:`, contract.address) - - if (verify) - await verifyContract(contractName, contract.address, constructorArgs) - - return contract -} - -// Deploy upgrade executor from imported bytecode -async function deployUpgradeExecutor(): Promise { - const upgradeExecutorFac = await ethers.getContractFactory( - UpgradeExecutorABI, - UpgradeExecutorBytecode - ) - const upgradeExecutor = await upgradeExecutorFac.deploy() - return upgradeExecutor -} - -// Function to handle all deployments of core contracts using deployContract function -async function deployAllContracts( - signer: any -): Promise> { - const ethBridge = await deployContract('Bridge', signer, []) - const ethSequencerInbox = await deployContract('SequencerInbox', signer, [ - maxDataSize, - false, - ]) - const ethInbox = await deployContract('Inbox', signer, [maxDataSize]) - const ethRollupEventInbox = await deployContract( - 'RollupEventInbox', - signer, - [] - ) - const ethOutbox = await deployContract('Outbox', signer, []) - - const erc20Bridge = await deployContract('ERC20Bridge', signer, []) - const erc20SequencerInbox = await deployContract('SequencerInbox', signer, [ - maxDataSize, - true, - ]) - const erc20Inbox = await deployContract('ERC20Inbox', signer, [maxDataSize]) - const erc20RollupEventInbox = await deployContract( - 'ERC20RollupEventInbox', - signer, - [] - ) - const erc20Outbox = await deployContract('ERC20Outbox', signer, []) - - const bridgeCreator = await deployContract('BridgeCreator', signer, [ - [ - ethBridge.address, - ethSequencerInbox.address, - ethInbox.address, - ethRollupEventInbox.address, - ethOutbox.address, - ], - [ - erc20Bridge.address, - erc20SequencerInbox.address, - erc20Inbox.address, - erc20RollupEventInbox.address, - erc20Outbox.address, - ], - ]) - const prover0 = await deployContract('OneStepProver0', signer) - const proverMem = await deployContract('OneStepProverMemory', signer) - const proverMath = await deployContract('OneStepProverMath', signer) - const proverHostIo = await deployContract('OneStepProverHostIo', signer) - const osp: Contract = await deployContract('OneStepProofEntry', signer, [ - prover0.address, - proverMem.address, - proverMath.address, - proverHostIo.address, - ]) - const challengeManager = await deployContract('ChallengeManager', signer) - const rollupAdmin = await deployContract('RollupAdminLogic', signer) - const rollupUser = await deployContract('RollupUserLogic', signer) - const upgradeExecutor = await deployUpgradeExecutor() - const validatorUtils = await deployContract('ValidatorUtils', signer) - const validatorWalletCreator = await deployContract( - 'ValidatorWalletCreator', - signer - ) - const rollupCreator = await deployContract('RollupCreator', signer) - const deployHelper = await deployContract('DeployHelper', signer) - return { - bridgeCreator, - prover0, - proverMem, - proverMath, - proverHostIo, - osp, - challengeManager, - rollupAdmin, - rollupUser, - upgradeExecutor, - validatorUtils, - validatorWalletCreator, - rollupCreator, - deployHelper, - } -} +import { deployAllContracts } from './deploymentUtils' async function main() { const [signer] = await ethers.getSigners() diff --git a/scripts/deploymentUtils.ts b/scripts/deploymentUtils.ts new file mode 100644 index 00000000..b5c2210d --- /dev/null +++ b/scripts/deploymentUtils.ts @@ -0,0 +1,161 @@ +import { ethers } from 'hardhat' +import { ContractFactory, Contract, Overrides } from 'ethers' +import '@nomiclabs/hardhat-ethers' +import { run } from 'hardhat' +import { + abi as UpgradeExecutorABI, + bytecode as UpgradeExecutorBytecode, +} from '@offchainlabs/upgrade-executor/build/contracts/src/UpgradeExecutor.sol/UpgradeExecutor.json' +import { maxDataSize } from './config' + +// Define a verification function +export async function verifyContract( + contractName: string, + contractAddress: string, + constructorArguments: any[] = [], + contractPathAndName?: string // optional +): Promise { + try { + if (process.env.DISABLE_VERIFICATION) return + // Define the verification options with possible 'contract' property + const verificationOptions: { + contract?: string + address: string + constructorArguments: any[] + } = { + address: contractAddress, + constructorArguments: constructorArguments, + } + + // if contractPathAndName is provided, add it to the verification options + if (contractPathAndName) { + verificationOptions.contract = contractPathAndName + } + + await run('verify:verify', verificationOptions) + console.log(`Verified contract ${contractName} successfully.`) + } catch (error: any) { + if (error.message.includes('Already Verified')) { + console.log(`Contract ${contractName} is already verified.`) + } else { + console.error( + `Verification for ${contractName} failed with the following error: ${error.message}` + ) + } + } +} + +// Function to handle contract deployment +export async function deployContract( + contractName: string, + signer: any, + constructorArgs: any[] = [], + verify: boolean = true, + overrides?: Overrides +): Promise { + const factory: ContractFactory = await ethers.getContractFactory(contractName) + const connectedFactory: ContractFactory = factory.connect(signer) + const contract: Contract = await connectedFactory.deploy(...constructorArgs, overrides) + await contract.deployTransaction.wait() + console.log(`New ${contractName} created at address:`, contract.address) + + if (verify) + await verifyContract(contractName, contract.address, constructorArgs) + + return contract +} + +// Deploy upgrade executor from imported bytecode +export async function deployUpgradeExecutor(): Promise { + const upgradeExecutorFac = await ethers.getContractFactory( + UpgradeExecutorABI, + UpgradeExecutorBytecode + ) + const upgradeExecutor = await upgradeExecutorFac.deploy() + return upgradeExecutor +} + +// Function to handle all deployments of core contracts using deployContract function +export async function deployAllContracts( + signer: any +): Promise> { + const ethBridge = await deployContract('Bridge', signer, []) + const ethSequencerInbox = await deployContract('SequencerInbox', signer, [ + maxDataSize, + false, + ]) + const ethInbox = await deployContract('Inbox', signer, [maxDataSize]) + const ethRollupEventInbox = await deployContract( + 'RollupEventInbox', + signer, + [] + ) + const ethOutbox = await deployContract('Outbox', signer, []) + + const erc20Bridge = await deployContract('ERC20Bridge', signer, []) + const erc20SequencerInbox = await deployContract('SequencerInbox', signer, [ + maxDataSize, + true, + ]) + const erc20Inbox = await deployContract('ERC20Inbox', signer, [maxDataSize]) + const erc20RollupEventInbox = await deployContract( + 'ERC20RollupEventInbox', + signer, + [] + ) + const erc20Outbox = await deployContract('ERC20Outbox', signer, []) + + const bridgeCreator = await deployContract('BridgeCreator', signer, [ + [ + ethBridge.address, + ethSequencerInbox.address, + ethInbox.address, + ethRollupEventInbox.address, + ethOutbox.address, + ], + [ + erc20Bridge.address, + erc20SequencerInbox.address, + erc20Inbox.address, + erc20RollupEventInbox.address, + erc20Outbox.address, + ], + ]) + const prover0 = await deployContract('OneStepProver0', signer) + const proverMem = await deployContract('OneStepProverMemory', signer) + const proverMath = await deployContract('OneStepProverMath', signer) + const proverHostIo = await deployContract('OneStepProverHostIo', signer) + const osp: Contract = await deployContract('OneStepProofEntry', signer, [ + prover0.address, + proverMem.address, + proverMath.address, + proverHostIo.address, + ]) + const challengeManager = await deployContract('ChallengeManager', signer) + const rollupAdmin = await deployContract('RollupAdminLogic', signer) + const rollupUser = await deployContract('RollupUserLogic', signer) + const upgradeExecutor = await deployUpgradeExecutor() + const validatorUtils = await deployContract('ValidatorUtils', signer) + const validatorWalletCreator = await deployContract( + 'ValidatorWalletCreator', + signer + ) + const rollupCreator = await deployContract('RollupCreator', signer) + const deployHelper = await deployContract('DeployHelper', signer) + return { + bridgeCreator, + prover0, + proverMem, + proverMath, + proverHostIo, + osp, + challengeManager, + rollupAdmin, + rollupUser, + upgradeExecutor, + validatorUtils, + validatorWalletCreator, + rollupCreator, + deployHelper, + } +} From 07698cfe02cd99806234a5b7409269c7ca484692 Mon Sep 17 00:00:00 2001 From: gzeon Date: Mon, 12 Feb 2024 16:59:25 +0800 Subject: [PATCH 2/6] deploy: 4844 upgrade --- scripts/upgrade/deploy4844.ts | 69 +++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 scripts/upgrade/deploy4844.ts diff --git a/scripts/upgrade/deploy4844.ts b/scripts/upgrade/deploy4844.ts new file mode 100644 index 00000000..e8823c2e --- /dev/null +++ b/scripts/upgrade/deploy4844.ts @@ -0,0 +1,69 @@ +import { ethers } from 'hardhat' +import { ContractFactory, Contract, Overrides } from 'ethers' +import '@nomiclabs/hardhat-ethers' +import { IReader4844__factory } from '../../build/types' +import { bytecode as Reader4844Bytecode } from '../../out/yul/Reader4844.yul/Reader4844.json' +import { deployContract, verifyContract } from '../deploymentUtils' +import { maxDataSize, isUsingFeeToken } from '../config' + +async function main() { + const [signer] = await ethers.getSigners() + const overrides : Overrides = { + maxFeePerGas: ethers.utils.parseUnits('30', 'gwei'), + maxPriorityFeePerGas: ethers.utils.parseUnits('0.001', 'gwei') + } + + const contractFactory = new ContractFactory( + IReader4844__factory.abi, + Reader4844Bytecode, + signer + ) + const reader4844 = await contractFactory.deploy(overrides) + await reader4844.deployed() + console.log(`Reader4844 deployed at ${reader4844.address}`) + + // skip verification on deployment + const sequencerInbox = await deployContract('SequencerInbox', signer, [ + maxDataSize, + reader4844.address, + isUsingFeeToken + ], false, overrides) + // SequencerInbox logic do not need to be initialized + const prover0 = await deployContract('OneStepProver0', signer, [], false, overrides) + const proverMem = await deployContract('OneStepProverMemory', signer, [], false, overrides) + const proverMath = await deployContract('OneStepProverMath', signer, [], false, overrides) + const proverHostIo = await deployContract('OneStepProverHostIo', signer, [], false, overrides) + const osp: Contract = await deployContract('OneStepProofEntry', signer, [ + prover0.address, + proverMem.address, + proverMath.address, + proverHostIo.address, + ], false, overrides) + const challengeManager = await deployContract('ChallengeManager', signer, [], false, overrides) + // ChallengeManager logic do not need to be initialized + + // verify + await verifyContract('SequencerInbox', sequencerInbox.address, [ + maxDataSize, + reader4844.address, + isUsingFeeToken + ]) + await verifyContract('OneStepProver0', prover0.address, []) + await verifyContract('OneStepProverMemory', proverMem.address, []) + await verifyContract('OneStepProverMath', proverMath.address, []) + await verifyContract('OneStepProverHostIo', proverHostIo.address, []) + await verifyContract('OneStepProofEntry', osp.address, [ + prover0.address, + proverMem.address, + proverMath.address, + proverHostIo.address, + ]) + await verifyContract('ChallengeManager', challengeManager.address, []) +} + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error) + process.exit(1) + }) From 590e3ecba1c09b24dc46cf0a81f38bc0aaa761f7 Mon Sep 17 00:00:00 2001 From: gzeon Date: Mon, 12 Feb 2024 17:00:03 +0800 Subject: [PATCH 3/6] chore: add yul build to release --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a06fc857..2261b35b 100644 --- a/package.json +++ b/package.json @@ -11,13 +11,14 @@ "files": [ "src/", "build/contracts/src", - "build/contracts/@openzeppelin" + "build/contracts/@openzeppelin", + "out/yul/Reader4844.yul/Reader4844.json" ], "bugs": { "url": "https://github.com/offchainlabs/nitro-contracts/issues" }, "scripts": { - "prepublishOnly": "hardhat clean && hardhat compile", + "prepublishOnly": "hardhat clean && forge clean && hardhat compile && yarn build:forge:yul", "build:all": "yarn build && yarn build:forge", "build": "hardhat compile", "build:forge:sol": "forge build --skip *.yul", From 9a8454890219d227913d2ead1882051dbb86fe04 Mon Sep 17 00:00:00 2001 From: Goran Vladika Date: Mon, 12 Feb 2024 16:34:21 +0100 Subject: [PATCH 4/6] Add reader4844 to deployment script --- scripts/deploymentUtils.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/deploymentUtils.ts b/scripts/deploymentUtils.ts index b5c2210d..7ae63e38 100644 --- a/scripts/deploymentUtils.ts +++ b/scripts/deploymentUtils.ts @@ -7,6 +7,7 @@ import { bytecode as UpgradeExecutorBytecode, } from '@offchainlabs/upgrade-executor/build/contracts/src/UpgradeExecutor.sol/UpgradeExecutor.json' import { maxDataSize } from './config' +import { Toolkit4844 } from '../test/contract/toolkit4844' // Define a verification function export async function verifyContract( @@ -55,7 +56,10 @@ export async function deployContract( ): Promise { const factory: ContractFactory = await ethers.getContractFactory(contractName) const connectedFactory: ContractFactory = factory.connect(signer) - const contract: Contract = await connectedFactory.deploy(...constructorArgs, overrides) + const contract: Contract = await connectedFactory.deploy( + ...constructorArgs, + overrides + ) await contract.deployTransaction.wait() console.log(`New ${contractName} created at address:`, contract.address) @@ -80,10 +84,13 @@ export async function deployAllContracts( signer: any ): Promise> { const ethBridge = await deployContract('Bridge', signer, []) + const reader4844 = await Toolkit4844.deployReader4844(signer) const ethSequencerInbox = await deployContract('SequencerInbox', signer, [ maxDataSize, + reader4844.address, false, ]) + const ethInbox = await deployContract('Inbox', signer, [maxDataSize]) const ethRollupEventInbox = await deployContract( 'RollupEventInbox', @@ -95,6 +102,7 @@ export async function deployAllContracts( const erc20Bridge = await deployContract('ERC20Bridge', signer, []) const erc20SequencerInbox = await deployContract('SequencerInbox', signer, [ maxDataSize, + reader4844.address, true, ]) const erc20Inbox = await deployContract('ERC20Inbox', signer, [maxDataSize]) From 2c83dec097b97a460a44246ca0d2b55ab0cce1f5 Mon Sep 17 00:00:00 2001 From: Goran Vladika Date: Tue, 13 Feb 2024 15:56:13 +0100 Subject: [PATCH 5/6] Properly set seq inbox blob reader --- scripts/deploymentUtils.ts | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/scripts/deploymentUtils.ts b/scripts/deploymentUtils.ts index 7ae63e38..e8aec0b7 100644 --- a/scripts/deploymentUtils.ts +++ b/scripts/deploymentUtils.ts @@ -1,5 +1,4 @@ -import { ethers } from 'hardhat' -import { ContractFactory, Contract, Overrides } from 'ethers' +import { ContractFactory, Contract, Overrides, ethers } from 'ethers' import '@nomiclabs/hardhat-ethers' import { run } from 'hardhat' import { @@ -8,6 +7,8 @@ import { } from '@offchainlabs/upgrade-executor/build/contracts/src/UpgradeExecutor.sol/UpgradeExecutor.json' import { maxDataSize } from './config' import { Toolkit4844 } from '../test/contract/toolkit4844' +import { ArbSys__factory } from '../build/types' +import { ARB_SYS_ADDRESS } from '@arbitrum/sdk/dist/lib/dataEntities/constants' // Define a verification function export async function verifyContract( @@ -83,11 +84,15 @@ export async function deployUpgradeExecutor(): Promise { export async function deployAllContracts( signer: any ): Promise> { + const isOnArb = await _isRunningOnArbitrum(signer) + const ethBridge = await deployContract('Bridge', signer, []) - const reader4844 = await Toolkit4844.deployReader4844(signer) + const reader4844 = isOnArb + ? (await Toolkit4844.deployReader4844(signer)).address + : ethers.constants.AddressZero const ethSequencerInbox = await deployContract('SequencerInbox', signer, [ maxDataSize, - reader4844.address, + reader4844, false, ]) @@ -102,7 +107,7 @@ export async function deployAllContracts( const erc20Bridge = await deployContract('ERC20Bridge', signer, []) const erc20SequencerInbox = await deployContract('SequencerInbox', signer, [ maxDataSize, - reader4844.address, + reader4844, true, ]) const erc20Inbox = await deployContract('ERC20Inbox', signer, [maxDataSize]) @@ -167,3 +172,14 @@ export async function deployAllContracts( deployHelper, } } + +// Check if we're deploying to an Arbitrum chain +async function _isRunningOnArbitrum(signer: any): Promise { + const arbSys = ArbSys__factory.connect(ARB_SYS_ADDRESS, signer) + try { + await arbSys.arbOSVersion() + return true + } catch (error) { + return false + } +} From 3e1dccab2b1faa2b2556ddbd41613478bbbae37d Mon Sep 17 00:00:00 2001 From: Goran Vladika Date: Tue, 13 Feb 2024 17:26:14 +0100 Subject: [PATCH 6/6] Update script to work with latest design --- scripts/deploymentUtils.ts | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/scripts/deploymentUtils.ts b/scripts/deploymentUtils.ts index e8aec0b7..2df51be6 100644 --- a/scripts/deploymentUtils.ts +++ b/scripts/deploymentUtils.ts @@ -1,4 +1,5 @@ -import { ContractFactory, Contract, Overrides, ethers } from 'ethers' +import { ethers } from 'hardhat' +import { ContractFactory, Contract, Overrides } from 'ethers' import '@nomiclabs/hardhat-ethers' import { run } from 'hardhat' import { @@ -57,10 +58,13 @@ export async function deployContract( ): Promise { const factory: ContractFactory = await ethers.getContractFactory(contractName) const connectedFactory: ContractFactory = factory.connect(signer) - const contract: Contract = await connectedFactory.deploy( - ...constructorArgs, - overrides - ) + + let deploymentArgs = [...constructorArgs] + if (overrides) { + deploymentArgs.push(overrides) + } + + const contract: Contract = await connectedFactory.deploy(...deploymentArgs) await contract.deployTransaction.wait() console.log(`New ${contractName} created at address:`, contract.address) @@ -71,12 +75,13 @@ export async function deployContract( } // Deploy upgrade executor from imported bytecode -export async function deployUpgradeExecutor(): Promise { +export async function deployUpgradeExecutor(signer: any): Promise { const upgradeExecutorFac = await ethers.getContractFactory( UpgradeExecutorABI, UpgradeExecutorBytecode ) - const upgradeExecutor = await upgradeExecutorFac.deploy() + const connectedFactory: ContractFactory = upgradeExecutorFac.connect(signer) + const upgradeExecutor = await connectedFactory.deploy() return upgradeExecutor } @@ -88,8 +93,9 @@ export async function deployAllContracts( const ethBridge = await deployContract('Bridge', signer, []) const reader4844 = isOnArb - ? (await Toolkit4844.deployReader4844(signer)).address - : ethers.constants.AddressZero + ? ethers.constants.AddressZero + : (await Toolkit4844.deployReader4844(signer)).address + const ethSequencerInbox = await deployContract('SequencerInbox', signer, [ maxDataSize, reader4844, @@ -147,7 +153,7 @@ export async function deployAllContracts( const challengeManager = await deployContract('ChallengeManager', signer) const rollupAdmin = await deployContract('RollupAdminLogic', signer) const rollupUser = await deployContract('RollupUserLogic', signer) - const upgradeExecutor = await deployUpgradeExecutor() + const upgradeExecutor = await deployUpgradeExecutor(signer) const validatorUtils = await deployContract('ValidatorUtils', signer) const validatorWalletCreator = await deployContract( 'ValidatorWalletCreator',