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", 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..2df51be6 --- /dev/null +++ b/scripts/deploymentUtils.ts @@ -0,0 +1,191 @@ +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' +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( + 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) + + 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) + + if (verify) + await verifyContract(contractName, contract.address, constructorArgs) + + return contract +} + +// Deploy upgrade executor from imported bytecode +export async function deployUpgradeExecutor(signer: any): Promise { + const upgradeExecutorFac = await ethers.getContractFactory( + UpgradeExecutorABI, + UpgradeExecutorBytecode + ) + const connectedFactory: ContractFactory = upgradeExecutorFac.connect(signer) + const upgradeExecutor = await connectedFactory.deploy() + return upgradeExecutor +} + +// Function to handle all deployments of core contracts using deployContract function +export async function deployAllContracts( + signer: any +): Promise> { + const isOnArb = await _isRunningOnArbitrum(signer) + + const ethBridge = await deployContract('Bridge', signer, []) + const reader4844 = isOnArb + ? ethers.constants.AddressZero + : (await Toolkit4844.deployReader4844(signer)).address + + const ethSequencerInbox = await deployContract('SequencerInbox', signer, [ + maxDataSize, + reader4844, + 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, + reader4844, + 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(signer) + 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, + } +} + +// 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 + } +} 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) + })