diff --git a/.gitignore b/.gitignore index 1cd604bbb..4d219b574 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ deployments/ /test/prover/proofs/*.json /test/prover/spec-proofs/*.json /test/storage/*-old.dot +scripts/config.ts diff --git a/hardhat.config.ts b/hardhat.config.ts index 89fbc7a63..76929c70b 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -88,6 +88,12 @@ module.exports = { ? [process.env['DEVNET_PRIVKEY']] : [], }, + sepolia: { + url: 'https://sepolia.infura.io/v3/' + process.env['INFURA_KEY'], + accounts: process.env['DEVNET_PRIVKEY'] + ? [process.env['DEVNET_PRIVKEY']] + : [], + }, rinkeby: { url: 'https://rinkeby.infura.io/v3/' + process.env['INFURA_KEY'], accounts: process.env['DEVNET_PRIVKEY'] @@ -126,6 +132,7 @@ module.exports = { apiKey: { mainnet: process.env['ETHERSCAN_API_KEY'], goerli: process.env['ETHERSCAN_API_KEY'], + sepolia: process.env['ETHERSCAN_API_KEY'], rinkeby: process.env['ETHERSCAN_API_KEY'], arbitrumOne: process.env['ARBISCAN_API_KEY'], arbitrumTestnet: process.env['ARBISCAN_API_KEY'], diff --git a/package.json b/package.json index a330b8829..0f6135e29 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,10 @@ "build:0.7": "INTERFACE_TESTER_SOLC_VERSION=0.7.0 yarn run build", "test:compatibility": "yarn run build:0.6 && yarn run build:0.7", "test:storage": "./test/storage/test.bash", - "postinstall": "patch-package" + "postinstall": "patch-package", + "deploy-factory": "hardhat run scripts/deployment.ts", + "deploy-rollup": "hardhat run scripts/rollupCreation.ts" + }, "dependencies": { "@openzeppelin/contracts": "4.5.0", diff --git a/scripts/config.ts.example b/scripts/config.ts.example new file mode 100644 index 000000000..4f2fb29cf --- /dev/null +++ b/scripts/config.ts.example @@ -0,0 +1,22 @@ +import { ethers } from 'ethers' + +export const rollupConfig = { + confirmPeriodBlocks: ethers.BigNumber.from('45818'), + extraChallengeTimeBlocks: ethers.BigNumber.from('200'), + stakeToken: ethers.constants.AddressZero, + baseStake: ethers.utils.parseEther('1'), + wasmModuleRoot: + '0xda4e3ad5e7feacb817c21c8d0220da7650fe9051ece68a3f0b1c5d38bbb27b21', + owner: '0x1234123412341234123412341234123412341234', + loserStakeEscrow: ethers.constants.AddressZero, + chainId: ethers.BigNumber.from('1337'), + chainConfig: + '{"chainId":1337,"homesteadBlock":0,"daoForkBlock":null,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x0000000000000000000000000000000000000000000000000000000000000000","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0,"istanbulBlock":0,"muirGlacierBlock":0,"berlinBlock":0,"londonBlock":0,"clique":{"period":0,"epoch":0},"arbitrum":{"EnableArbOS":true,"AllowDebugPrecompiles":false,"DataAvailabilityCommittee":false,"InitialArbOSVersion":10,"InitialChainOwner":"0x1234123412341234123412341234123412341234","GenesisBlockNum":0}}', + genesisBlockNum: ethers.BigNumber.from('0'), + sequencerInboxMaxTimeVariation: { + delayBlocks: ethers.BigNumber.from('5760'), + futureBlocks: ethers.BigNumber.from('12'), + delaySeconds: ethers.BigNumber.from('86400'), + futureSeconds: ethers.BigNumber.from('3600'), + }, +} diff --git a/scripts/deployment.ts b/scripts/deployment.ts new file mode 100644 index 000000000..9a5bf94f8 --- /dev/null +++ b/scripts/deployment.ts @@ -0,0 +1,163 @@ +import { ethers } from 'hardhat' +import { ContractFactory, Contract } from 'ethers' +import '@nomiclabs/hardhat-ethers' +import { run } from 'hardhat' + +// Define a verification function +async function verifyContract( + contractName: string, + contractAddress: string, + constructorArguments: any[] = [], + contractPathAndName?: string // optional +): Promise { + try { + // 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[] = [] +): 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) + + await verifyContract(contractName, contract.address, constructorArgs) + + return contract +} + +// Function to handle all deployments of core contracts using deployContract function +async function deployAllContracts( + signer: any +): Promise> { + const bridgeCreator = await deployContract('BridgeCreator', signer) + 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 validatorUtils = await deployContract('ValidatorUtils', signer) + const validatorWalletCreator = await deployContract( + 'ValidatorWalletCreator', + signer + ) + const rollupCreator = await deployContract('RollupCreator', signer) + return { + bridgeCreator, + prover0, + proverMem, + proverMath, + proverHostIo, + osp, + challengeManager, + rollupAdmin, + rollupUser, + validatorUtils, + validatorWalletCreator, + rollupCreator, + } +} + +async function main() { + const [signer] = await ethers.getSigners() + + try { + // Deploying all contracts + const contracts = await deployAllContracts(signer) + + // Call setTemplates with the deployed contract addresses + console.log('Waiting for the Template to be set on the Rollup Creator') + await contracts.rollupCreator.setTemplates( + contracts.bridgeCreator.address, + contracts.osp.address, + contracts.challengeManager.address, + contracts.rollupAdmin.address, + contracts.rollupUser.address, + contracts.validatorUtils.address, + contracts.validatorWalletCreator.address + ) + console.log('Template is set on the Rollup Creator') + + const bridgeAddress = await contracts.bridgeCreator.bridgeTemplate() + const sequencerInboxAddress = + await contracts.bridgeCreator.sequencerInboxTemplate() + const inboxAddress = await contracts.bridgeCreator.inboxTemplate() + const outboxAddress = await contracts.bridgeCreator.outboxTemplate() + + console.log( + `"bridge implementation contract" created at address:`, + bridgeAddress + ) + await verifyContract( + 'Bridge', + bridgeAddress, + [], + 'src/bridge/Bridge.sol:Bridge' + ) + console.log( + `"sequencerInbox implementation contract" created at address:`, + sequencerInboxAddress + ) + await verifyContract('SequencerInbox', sequencerInboxAddress, []) + console.log( + `"inbox implementation contract" created at address:`, + inboxAddress + ) + await verifyContract('Inbox', inboxAddress, []) + console.log( + `"outbox implementation contract" created at address:`, + outboxAddress + ) + await verifyContract('Outbox', outboxAddress, []) + } catch (error) { + console.error( + 'Deployment failed:', + error instanceof Error ? error.message : error + ) + } +} + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error) + process.exit(1) + }) diff --git a/scripts/rollupCreation.ts b/scripts/rollupCreation.ts new file mode 100644 index 000000000..fec50d082 --- /dev/null +++ b/scripts/rollupCreation.ts @@ -0,0 +1,125 @@ +import { ethers } from 'hardhat' +import '@nomiclabs/hardhat-ethers' +import { run } from 'hardhat' +import { abi as rollupCreatorAbi } from '../build/contracts/src/rollup/RollupCreator.sol/RollupCreator.json' +import { rollupConfig } from './config' +import { abi as rollupCoreAbi } from '../build/contracts/src/rollup/RollupCore.sol/RollupCore.json' + +interface RollupCreatedEvent { + event: string + address: string + args?: { + rollupAddress: string + inboxAddress: string + adminProxy: string + sequencerInbox: string + bridge: string + } +} + +async function main() { + const rollupCreatorAddress = process.env.ROLLUP_CREATOR_ADDRESS + + if (!rollupCreatorAddress) { + console.error( + 'Please provide ROLLUP_CREATOR_ADDRESS as an environment variable.' + ) + process.exit(1) + } + + if (!rollupCreatorAbi) { + throw new Error( + 'You need to first run script to deploy and compile the contracts first' + ) + } + + const [signer] = await ethers.getSigners() + + const rollupCreator = await new ethers.Contract( + rollupCreatorAddress, + rollupCreatorAbi, + signer + ) + + try { + // Call the createRollup function + console.log('Calling createRollup to generate a new rollup ...') + const createRollupTx = await rollupCreator.createRollup(rollupConfig) + const createRollupReceipt = await createRollupTx.wait() + + const rollupCreatedEvent = createRollupReceipt.events?.find( + (event: RollupCreatedEvent) => + event.event === 'RollupCreated' && + event.address.toLowerCase() === rollupCreatorAddress.toLowerCase() + ) + + // Checking for RollupCreated event for new rollup address + if (rollupCreatedEvent) { + const rollupAddress = rollupCreatedEvent.args?.rollupAddress + const inboxAddress = rollupCreatedEvent.args?.inboxAddress + const adminProxy = rollupCreatedEvent.args?.adminProxy + const sequencerInbox = rollupCreatedEvent.args?.sequencerInbox + const bridge = rollupCreatedEvent.args?.bridge + + const rollupCore = new ethers.Contract( + rollupAddress, + rollupCoreAbi, + signer + ) + + console.log("Congratulations! 🎉🎉🎉 All DONE! Here's your addresses:") + console.log('RollupProxy Contract created at address:', rollupAddress) + console.log( + `Attempting to verify Rollup contract at address ${rollupAddress}...` + ) + try { + await run('verify:verify', { + contract: 'src/rollup/RollupProxy.sol:RollupProxy', + address: rollupAddress, + constructorArguments: [], + }) + } catch (error: any) { + if (error.message.includes('Already Verified')) { + console.log(`Contract RollupProxy is already verified.`) + } else { + console.error( + `Verification for RollupProxy failed with the following error: ${error.message}` + ) + } + } + console.log('Inbox (proxy) Contract created at address:', inboxAddress) + console.log( + 'Outbox (proxy) Contract created at address:', + await rollupCore.outbox() + ) + console.log('AdminProxy Contract created at address:', adminProxy) + console.log('SequencerInbox (proxy) created at address:', sequencerInbox) + console.log('Bridge (proxy) Contract created at address:', bridge) + console.log( + 'ValidatorUtils Contract created at address:', + await rollupCore.validatorUtils() + ) + console.log( + 'ValidatorWalletCreator Contract created at address:', + await rollupCore.validatorWalletCreator() + ) + + const blockNumber = createRollupReceipt.blockNumber + console.log('All deployed at block number:', blockNumber) + } else { + console.error('RollupCreated event not found') + } + } catch (error) { + console.error( + 'Deployment failed:', + error instanceof Error ? error.message : error + ) + } +} + +main() + .then(() => process.exit(0)) + .catch((error: Error) => { + console.error(error) + process.exit(1) + })