diff --git a/packages/contracts/deploy/001-Lib_AddressManager.deploy.ts b/packages/contracts/deploy/001-Lib_AddressManager.deploy.ts index e69de29bb..0bf565dc9 100644 --- a/packages/contracts/deploy/001-Lib_AddressManager.deploy.ts +++ b/packages/contracts/deploy/001-Lib_AddressManager.deploy.ts @@ -0,0 +1,29 @@ +/* Imports: Internal */ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +import { names } from '../src/address-names' +import { hexStringEquals } from '@mantleio/core-utils' + +/* Imports: External */ + +const deployFn: DeployFunction = async (hre) => { + const { deploy } = hre.deployments + const { deployer } = await hre.getNamedAccounts() + const owner = hre.deployConfig.bvmAddressManagerOwner + + if (hexStringEquals(deployer, owner)) { + console.log("deployer ", deployer, "can not be owner ", owner) + process.exit(1) + } + await deploy(names.unmanaged.Lib_AddressManager, { + from: deployer, + args: [], + log: true, + waitConfirmations: hre.deployConfig.numDeployConfirmations, + }) +} + +// This is kept during an upgrade. So no upgrade tag. +deployFn.tags = ['Lib_AddressManager'] + +export default deployFn diff --git a/packages/contracts/deploy/002-BVM_ChainStorageContainer_ctc_batches.deploy.ts b/packages/contracts/deploy/002-BVM_ChainStorageContainer_ctc_batches.deploy.ts index e69de29bb..730481a74 100644 --- a/packages/contracts/deploy/002-BVM_ChainStorageContainer_ctc_batches.deploy.ts +++ b/packages/contracts/deploy/002-BVM_ChainStorageContainer_ctc_batches.deploy.ts @@ -0,0 +1,27 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +/* Imports: Internal */ +import { + deployAndVerifyAndThen, + getContractFromArtifact, +} from '../src/deploy-utils' +import { names } from '../src/address-names' + +const deployFn: DeployFunction = async (hre) => { + const Lib_AddressManager = await getContractFromArtifact( + hre, + names.unmanaged.Lib_AddressManager + ) + + await deployAndVerifyAndThen({ + hre, + name: names.managed.contracts.ChainStorageContainer_CTC_batches, + contract: 'ChainStorageContainer', + args: [Lib_AddressManager.address, 'CanonicalTransactionChain'], + }) +} + +deployFn.tags = ['ChainStorageContainer_ctc_batches', 'upgrade'] + +export default deployFn diff --git a/packages/contracts/deploy/003-BVM_ChainStorageContainer_scc_batches.deploy.ts b/packages/contracts/deploy/003-BVM_ChainStorageContainer_scc_batches.deploy.ts index e69de29bb..64fe83da8 100644 --- a/packages/contracts/deploy/003-BVM_ChainStorageContainer_scc_batches.deploy.ts +++ b/packages/contracts/deploy/003-BVM_ChainStorageContainer_scc_batches.deploy.ts @@ -0,0 +1,27 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +/* Imports: Internal */ +import { + deployAndVerifyAndThen, + getContractFromArtifact, +} from '../src/deploy-utils' +import { names } from '../src/address-names' + +const deployFn: DeployFunction = async (hre) => { + const Lib_AddressManager = await getContractFromArtifact( + hre, + names.unmanaged.Lib_AddressManager + ) + + await deployAndVerifyAndThen({ + hre, + name: names.managed.contracts.ChainStorageContainer_SCC_batches, + contract: 'ChainStorageContainer', + args: [Lib_AddressManager.address, 'StateCommitmentChain'], + }) +} + +deployFn.tags = ['ChainStorageContainer_scc_batches', 'upgrade'] + +export default deployFn diff --git a/packages/contracts/deploy/004-BVM_CanonicalTransactionChain.deploy.ts b/packages/contracts/deploy/004-BVM_CanonicalTransactionChain.deploy.ts index e69de29bb..72fd41b49 100644 --- a/packages/contracts/deploy/004-BVM_CanonicalTransactionChain.deploy.ts +++ b/packages/contracts/deploy/004-BVM_CanonicalTransactionChain.deploy.ts @@ -0,0 +1,31 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +/* Imports: Internal */ +import { + deployAndVerifyAndThen, + getContractFromArtifact, +} from '../src/deploy-utils' +import { names } from '../src/address-names' + +const deployFn: DeployFunction = async (hre) => { + const Lib_AddressManager = await getContractFromArtifact( + hre, + names.unmanaged.Lib_AddressManager + ) + + await deployAndVerifyAndThen({ + hre, + name: names.managed.contracts.CanonicalTransactionChain, + args: [ + Lib_AddressManager.address, + hre.deployConfig.l2BlockGasLimit, + hre.deployConfig.ctcL2GasDiscountDivisor, + hre.deployConfig.ctcEnqueueGasCost, + ], + }) +} + +deployFn.tags = ['CanonicalTransactionChain', 'upgrade'] + +export default deployFn diff --git a/packages/contracts/deploy/005-BVM_BondManager.deploy.ts b/packages/contracts/deploy/005-BVM_BondManager.deploy.ts index e69de29bb..0917c12fd 100644 --- a/packages/contracts/deploy/005-BVM_BondManager.deploy.ts +++ b/packages/contracts/deploy/005-BVM_BondManager.deploy.ts @@ -0,0 +1,26 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +/* Imports: Internal */ +import { + deployAndVerifyAndThen, + getContractFromArtifact, +} from '../src/deploy-utils' +import { names } from '../src/address-names' + +const deployFn: DeployFunction = async (hre) => { + const Lib_AddressManager = await getContractFromArtifact( + hre, + names.unmanaged.Lib_AddressManager + ) + + await deployAndVerifyAndThen({ + hre, + name: names.managed.contracts.BondManager, + args: [Lib_AddressManager.address], + }) +} + +deployFn.tags = ['BondManager', 'upgrade'] + +export default deployFn diff --git a/packages/contracts/deploy/006-BVM_L1CrossDomainMessenger.deploy.ts b/packages/contracts/deploy/006-BVM_L1CrossDomainMessenger.deploy.ts index e69de29bb..afeb315bb 100644 --- a/packages/contracts/deploy/006-BVM_L1CrossDomainMessenger.deploy.ts +++ b/packages/contracts/deploy/006-BVM_L1CrossDomainMessenger.deploy.ts @@ -0,0 +1,84 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' +import { hexStringEquals, awaitCondition } from '@mantleio/core-utils' + +/* Imports: Internal */ +import { + deployAndVerifyAndThen, + getContractFromArtifact, +} from '../src/deploy-utils' +import { names } from '../src/address-names' + +const deployFn: DeployFunction = async (hre) => { + const Lib_AddressManager = await getContractFromArtifact( + hre, + names.unmanaged.Lib_AddressManager + ) + + await deployAndVerifyAndThen({ + hre, + name: names.managed.contracts.BVM_L1CrossDomainMessenger, + contract: 'L1CrossDomainMessenger', + args: [], + postDeployAction: async (contract) => { + // Theoretically it's not necessary to initialize this contract since it sits behind + // a proxy. However, it's best practice to initialize it anyway just in case there's + // some unknown security hole. It also prevents another user from appearing like an + // official address because it managed to call the initialization function. + console.log(`Initializing L1CrossDomainMessenger (implementation)...`) + await contract.initialize(Lib_AddressManager.address) + + console.log(`Checking that contract was correctly initialized...`) + await awaitCondition( + async () => { + return hexStringEquals( + await contract.libAddressManager(), + Lib_AddressManager.address + ) + }, + 5000, + 100 + ) + + // Same thing as above, we want to transfer ownership of this contract to the owner of the + // AddressManager. Not technically necessary but seems like the right thing to do. + console.log( + `set pauseowner of L1CrossDomainMessenger (implementation)...` + ) + // set the pauseowner + const pauseowner = hre.deployConfig.bvmCrossDomainPauseOwner + await contract.setPauseOwner(pauseowner) + console.log(`Checking that contract pause owner was correctly set...`) + await awaitCondition( + async () => { + console.log(contract.getPauseOwner()) + console.log(pauseowner) + return hexStringEquals(await contract.getPauseOwner(), pauseowner) + }, + 5000, + 100 + ) + + // Same thing as above, we want to transfer ownership of this contract to the owner of the + // AddressManager. Not technically necessary but seems like the right thing to do. + console.log( + `Transferring ownership of L1CrossDomainMessenger (implementation)...` + ) + const owner = hre.deployConfig.bvmAddressManagerOwner + await contract.transferOwnership(owner) + + console.log(`Checking that contract owner was correctly set...`) + await awaitCondition( + async () => { + return hexStringEquals(await contract.owner(), owner) + }, + 5000, + 100 + ) + }, + }) +} + +deployFn.tags = ['L1CrossDomainMessenger', 'upgrade'] + +export default deployFn diff --git a/packages/contracts/deploy/007-Proxy__BVM_L1CrossDomainMessenger.deploy.ts b/packages/contracts/deploy/007-Proxy__BVM_L1CrossDomainMessenger.deploy.ts index e69de29bb..33a27bea9 100644 --- a/packages/contracts/deploy/007-Proxy__BVM_L1CrossDomainMessenger.deploy.ts +++ b/packages/contracts/deploy/007-Proxy__BVM_L1CrossDomainMessenger.deploy.ts @@ -0,0 +1,29 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +/* Imports: Internal */ +import { + deployAndVerifyAndThen, + getContractFromArtifact, +} from '../src/deploy-utils' +import { names } from '../src/address-names' + +const deployFn: DeployFunction = async (hre) => { + const Lib_AddressManager = await getContractFromArtifact( + hre, + names.unmanaged.Lib_AddressManager + ) + + await deployAndVerifyAndThen({ + hre, + name: 'Proxy__BVM_L1CrossDomainMessenger', + contract: 'Lib_ResolvedDelegateProxy', + iface: 'L1CrossDomainMessenger', + args: [Lib_AddressManager.address, 'BVM_L1CrossDomainMessenger'], + }) +} + +// This is kept during an upgrade. So no upgrade tag. +deployFn.tags = ['Proxy__BVM_L1CrossDomainMessenger'] + +export default deployFn diff --git a/packages/contracts/deploy/008-BVM_StateCommitmentChain.deploy.ts b/packages/contracts/deploy/008-BVM_StateCommitmentChain.deploy.ts index e69de29bb..fff6f3ab7 100644 --- a/packages/contracts/deploy/008-BVM_StateCommitmentChain.deploy.ts +++ b/packages/contracts/deploy/008-BVM_StateCommitmentChain.deploy.ts @@ -0,0 +1,35 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +/* Imports: Internal */ +import { + deployAndVerifyAndThen, + getContractFromArtifact, +} from '../src/deploy-utils' +import { names } from '../src/address-names' + +const deployFn: DeployFunction = async (hre) => { + const Lib_AddressManager = await getContractFromArtifact( + hre, + names.unmanaged.Lib_AddressManager + ) + const Proxy__BVM_L1CrossDomainMessenger = await getContractFromArtifact( + hre, + names.managed.contracts.Proxy__BVM_L1CrossDomainMessenger + ) + + await deployAndVerifyAndThen({ + hre, + name: names.managed.contracts.StateCommitmentChain, + args: [ + Lib_AddressManager.address, + Proxy__BVM_L1CrossDomainMessenger.address, + hre.deployConfig.sccFaultProofWindowSeconds, + hre.deployConfig.sccSequencerPublishWindowSeconds, + ], + }) +} + +deployFn.tags = ['StateCommitmentChain', 'upgrade'] + +export default deployFn diff --git a/packages/contracts/deploy/009-Proxy__BVM_L1StandardBridge.deploy.ts b/packages/contracts/deploy/009-Proxy__BVM_L1StandardBridge.deploy.ts index e69de29bb..f4bb92b2d 100644 --- a/packages/contracts/deploy/009-Proxy__BVM_L1StandardBridge.deploy.ts +++ b/packages/contracts/deploy/009-Proxy__BVM_L1StandardBridge.deploy.ts @@ -0,0 +1,23 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +/* Imports: Internal */ +import { deployAndVerifyAndThen } from '../src/deploy-utils' +import { names } from '../src/address-names' + +const deployFn: DeployFunction = async (hre) => { + const { deployer } = await hre.getNamedAccounts() + + await deployAndVerifyAndThen({ + hre, + name: names.managed.contracts.Proxy__BVM_L1StandardBridge, + contract: 'L1ChugSplashProxy', + iface: 'L1StandardBridge', + args: [deployer], + }) +} + +// This is kept during an upgrade. So no upgrade tag. +deployFn.tags = ['Proxy__BVM_L1StandardBridge'] + +export default deployFn diff --git a/packages/contracts/deploy/011-AddressDictator.deploy.ts b/packages/contracts/deploy/011-AddressDictator.deploy.ts index e69de29bb..14fef9702 100644 --- a/packages/contracts/deploy/011-AddressDictator.deploy.ts +++ b/packages/contracts/deploy/011-AddressDictator.deploy.ts @@ -0,0 +1,98 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' +import { hexStringEquals, sleep } from '@mantleio/core-utils' + +/* Imports: Internal */ +import { + deployAndVerifyAndThen, + getContractFromArtifact, +} from '../src/deploy-utils' +import { names } from '../src/address-names' +import { predeploys } from '../src/predeploys' + +const deployFn: DeployFunction = async (hre) => { + const Lib_AddressManager = await getContractFromArtifact( + hre, + names.unmanaged.Lib_AddressManager + ) + + let namesAndAddresses: { + name: string + address: string + }[] = await Promise.all( + Object.values(names.managed.contracts).map(async (name) => { + return { + name, + address: (await getContractFromArtifact(hre, name)).address, + } + }) + ) + + // Add non-deployed addresses to the Address Dictator arguments. + namesAndAddresses = [ + ...namesAndAddresses, + // L2CrossDomainMessenger is the address of the predeploy on L2. We can refactor off-chain + // services such that we can remove the need to set this address, but for now it's easier + // to simply keep setting the address. + { + name: 'L2CrossDomainMessenger', + address: predeploys.L2CrossDomainMessenger, + }, + // BVM_Sequencer is the address allowed to submit "Sequencer" blocks to the + // CanonicalTransactionChain. + { + name: names.managed.accounts.BVM_Sequencer, + address: hre.deployConfig.bvmSequencerAddress, + }, + // BVM_Proposer is the address allowed to submit state roots (transaction results) to the + // StateCommitmentChain. + { + name: names.managed.accounts.BVM_Proposer, + address: hre.deployConfig.bvmProposerAddress, + }, + // BVM_Rolluper is the address allowed to submit state roots & assertion (transaction results) to the + // Rollup. + { + name: names.managed.accounts.BVM_Rolluper, + address: hre.deployConfig.bvmRolluperAddress, + }, + // L1_MANTLE_ADDRESS indicate l1 mantle token erc20 contract address + { + name: names.managed.configs.L1_MANTLE_ADDRESS, + address: hre.deployConfig.proxyL1MantleAddress, + }, + ] + + // Filter out all addresses that will not change, so that the log statement is maximally + // verifiable and readable. + const existingAddresses = {} + for (const pair of namesAndAddresses) { + existingAddresses[pair.name] = await Lib_AddressManager.getAddress( + pair.name + ) + } + namesAndAddresses = namesAndAddresses.filter(({ name, address }) => { + return !hexStringEquals(existingAddresses[name], address) + }) + + await sleep(10000) + + await deployAndVerifyAndThen({ + hre, + name: names.unmanaged.AddressDictator, + args: [ + Lib_AddressManager.address, + hre.deployConfig.bvmAddressManagerOwner, + namesAndAddresses.map((pair) => { + return pair.name + }), + namesAndAddresses.map((pair) => { + return pair.address + }), + ], + }) +} + +deployFn.tags = ['upgrade', 'AddressDictator'] + +export default deployFn diff --git a/packages/contracts/deploy/012-set-addresses.ts b/packages/contracts/deploy/012-set-addresses.ts index e69de29bb..4bd1a58fa 100644 --- a/packages/contracts/deploy/012-set-addresses.ts +++ b/packages/contracts/deploy/012-set-addresses.ts @@ -0,0 +1,117 @@ +/* Imports: External */ +import { hexStringEquals, awaitCondition } from '@mantleio/core-utils' +import { DeployFunction } from 'hardhat-deploy/dist/types' + +/* Imports: Internal */ +import { getContractFromArtifact, isHardhatNode } from '../src/deploy-utils' +import { names } from '../src/address-names' + +const deployFn: DeployFunction = async (hre) => { + const { deployer } = await hre.getNamedAccounts() + + // We use this task to print out the list of addresses that will be updated by the + // AddressDictator contract. The idea here is that the owner of the AddressManager will then + // review these names and addresses before transferring ownership to the AddressDictator. + // Once ownership has been transferred to the AddressDictator, we execute `setAddresses` which + // triggers a series of setAddress calls on the AddressManager and then transfers ownership back + // to the original owner. + + // First get relevant contract references. + const AddressDictator = await getContractFromArtifact( + hre, + names.unmanaged.AddressDictator, + { + signerOrProvider: deployer, + } + ) + const Lib_AddressManager = await getContractFromArtifact( + hre, + names.unmanaged.Lib_AddressManager + ) + const namedAddresses: Array<{ name: string; addr: string }> = + await AddressDictator.getNamedAddresses() + const finalOwner = await AddressDictator.finalOwner() + const currentOwner = await Lib_AddressManager.owner() + + console.log(` + The AddressDictator contract (glory to Arstotzka) has been deployed. + + FOLLOW THESE INSTRUCTIONS CAREFULLY! + + (1) Review the Contract Name / Contract Address pairs below and confirm that they match + the addresses found in the contract artifacts of your current deployment. + + ${namedAddresses + .map((namedAddress) => { + const padding = ' '.repeat(40 - namedAddress.name.length) + return ` + ${namedAddress.name}${padding} ${namedAddress.addr} + ` + }) + .join('\n')} + + (2) Review the CURRENT and FINAL AddressManager owners and verify that these are the expected values: + + Current AddressManager owner: (${currentOwner}) + Final AddressManager owner: (${finalOwner}) + + [${ + currentOwner === finalOwner + ? 'THESE ARE THE SAME ADDRESSES' + : 'THESE ARE >>>NOT<<< THE SAME ADDRESSES' + }] + + (3) Transfer ownership of the AddressManager located at (${ + Lib_AddressManager.address + }) + to the AddressDictator contract located at the following address: + + TRANSFER OWNERSHIP TO THE FOLLOWING ADDRESS ONLY: + >>>>> (${AddressDictator.address}) <<<<< + + (4) Wait for the deploy process to continue. + `) + + // Check if if we're on the hardhat chain ID. This will only happen in CI. If this is the case, we + // can skip directly to transferring ownership over to the ChugSplashDictator contract. + if ( + (await isHardhatNode(hre)) || + process.env.AUTOMATICALLY_TRANSFER_OWNERSHIP === 'true' + ) { + const owner = await hre.ethers.getSigner(currentOwner) + await Lib_AddressManager.connect(owner).transferOwnership( + AddressDictator.address + ) + } + + // Wait for ownership to be transferred to the AddressDictator contract. + await awaitCondition( + async () => { + return hexStringEquals( + await Lib_AddressManager.owner(), + AddressDictator.address + ) + }, + // Try every 30 seconds for 500 minutes. + 30000, + 1000 + ) + + // Set the addresses! + console.log('Ownership successfully transferred. Invoking setAddresses...') + await AddressDictator.setAddresses() + + // Make sure ownership has been correctly sent back to the original owner. + console.log('Verifying final ownership of Lib_AddressManager...') + await awaitCondition( + async () => { + return hexStringEquals(await Lib_AddressManager.owner(), finalOwner) + }, + 500, + 1000 + ) +} + +deployFn.tags = ['set-addresses', 'upgrade'] + +export default deployFn diff --git a/packages/contracts/deploy/013-initialize-Proxy__L1CrossDomainMessenger.ts b/packages/contracts/deploy/013-initialize-Proxy__L1CrossDomainMessenger.ts index e69de29bb..3776a7687 100644 --- a/packages/contracts/deploy/013-initialize-Proxy__L1CrossDomainMessenger.ts +++ b/packages/contracts/deploy/013-initialize-Proxy__L1CrossDomainMessenger.ts @@ -0,0 +1,64 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' +import { hexStringEquals, awaitCondition } from '@mantleio/core-utils' + +/* Imports: Internal */ +import { getContractFromArtifact } from '../src/deploy-utils' +import { names } from '../src/address-names' + +const deployFn: DeployFunction = async (hre) => { + const { deployer } = await hre.getNamedAccounts() + + // There's a risk that we could get front-run during a fresh deployment, which would brick this + // contract and require that the proxy be re-deployed. We will not have this risk once we move + // entirely to chugsplash-style deployments. It's unlikely to happen and relatively easy to + // recover from so let's just ignore it for now. + const Proxy__BVM_L1CrossDomainMessenger = await getContractFromArtifact( + hre, + names.managed.contracts.Proxy__BVM_L1CrossDomainMessenger, + { + iface: 'L1CrossDomainMessenger', + signerOrProvider: deployer, + } + ) + + const Lib_AddressManager = await getContractFromArtifact( + hre, + names.unmanaged.Lib_AddressManager + ) + + console.log(`Initializing Proxy__BVM_L1CrossDomainMessenger...`) + await Proxy__BVM_L1CrossDomainMessenger.initialize(Lib_AddressManager.address) + + console.log(`Checking that contract was correctly initialized...`) + await awaitCondition( + async () => { + return hexStringEquals( + await Proxy__BVM_L1CrossDomainMessenger.libAddressManager(), + Lib_AddressManager.address + ) + }, + 5000, + 100 + ) + + console.log(`Setting Proxy__BVM_L1CrossDomainMessenger owner...`) + const owner = hre.deployConfig.bvmAddressManagerOwner + await Proxy__BVM_L1CrossDomainMessenger.transferOwnership(owner) + + console.log(`Checking that the contract owner was correctly set...`) + await awaitCondition( + async () => { + return hexStringEquals( + await Proxy__BVM_L1CrossDomainMessenger.owner(), + owner + ) + }, + 5000, + 100 + ) +} + +deployFn.tags = ['finalize'] + +export default deployFn diff --git a/packages/contracts/deploy/014-ChugSplashDictator.deploy.ts b/packages/contracts/deploy/014-ChugSplashDictator.deploy.ts index e69de29bb..41ddf4873 100644 --- a/packages/contracts/deploy/014-ChugSplashDictator.deploy.ts +++ b/packages/contracts/deploy/014-ChugSplashDictator.deploy.ts @@ -0,0 +1,48 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' +import { ethers } from 'ethers' + +/* Imports: Internal */ +import { predeploys } from '../src/predeploys' +import { getContractDefinition } from '../src/contract-defs' +import { + getContractFromArtifact, + deployAndVerifyAndThen, +} from '../src/deploy-utils' +import { names } from '../src/address-names' + +const deployFn: DeployFunction = async (hre) => { + const Proxy__BVM_L1StandardBridge = await getContractFromArtifact( + hre, + 'Proxy__BVM_L1StandardBridge' + ) + + // Note: if the contract being deployed has immutable values this approach would not work. + const bridgeArtifact = getContractDefinition('L1StandardBridge') + const bridgeCode = bridgeArtifact.deployedBytecode + + const Proxy__BVM_L1CrossDomainMessenger = await getContractFromArtifact( + hre, + names.managed.contracts.Proxy__BVM_L1CrossDomainMessenger + ) + + await deployAndVerifyAndThen({ + hre, + name: names.unmanaged.ChugSplashDictator, + args: [ + Proxy__BVM_L1StandardBridge.address, + hre.deployConfig.bvmAddressManagerOwner, + ethers.utils.keccak256(bridgeCode), + ethers.utils.hexZeroPad('0x00', 32), + ethers.utils.hexZeroPad(Proxy__BVM_L1CrossDomainMessenger.address, 32), + ethers.utils.hexZeroPad('0x01', 32), + ethers.utils.hexZeroPad(predeploys.L2StandardBridge, 32), + ethers.utils.hexZeroPad('0x02', 32), + ethers.utils.hexZeroPad(hre.deployConfig.proxyL1MantleAddress, 32), + ], + }) +} + +deployFn.tags = ['upgrade', 'ChugSplashDictator'] + +export default deployFn diff --git a/packages/contracts/deploy/015-BVM_L1StandardBridge.deploy.ts b/packages/contracts/deploy/015-BVM_L1StandardBridge.deploy.ts index e69de29bb..1ce183ecb 100644 --- a/packages/contracts/deploy/015-BVM_L1StandardBridge.deploy.ts +++ b/packages/contracts/deploy/015-BVM_L1StandardBridge.deploy.ts @@ -0,0 +1,150 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' +import { ethers } from 'ethers' +import { hexStringEquals, awaitCondition } from '@mantleio/core-utils' + +/* Imports: Internal */ +import { getContractDefinition } from '../src/contract-defs' +import { + getContractFromArtifact, + deployAndVerifyAndThen, + isHardhatNode, +} from '../src/deploy-utils' +import { names } from '../src/address-names' + +const deployFn: DeployFunction = async (hre) => { + const { deployer } = await hre.getNamedAccounts() + + const ChugSplashDictator = await getContractFromArtifact( + hre, + names.unmanaged.ChugSplashDictator, + { + signerOrProvider: deployer, + } + ) + + const Proxy__BVM_L1StandardBridge = await getContractFromArtifact( + hre, + names.managed.contracts.Proxy__BVM_L1StandardBridge, + { + iface: 'L1ChugSplashProxy', + signerOrProvider: deployer, + } + ) + + // Make sure the dictator has been initialized with the correct bridge code. + const bridgeArtifact = getContractDefinition('L1StandardBridge') + const bridgeCode = bridgeArtifact.deployedBytecode + const codeHash = await ChugSplashDictator.codeHash() + if (ethers.utils.keccak256(bridgeCode) !== codeHash) { + throw new Error('code hash does not match actual bridge code') + } + + const currentOwner = await Proxy__BVM_L1StandardBridge.connect( + Proxy__BVM_L1StandardBridge.signer.provider + ).callStatic.getOwner({ + from: ethers.constants.AddressZero, + }) + const finalOwner = await ChugSplashDictator.finalOwner() + + const messengerSlotKey = await ChugSplashDictator.messengerSlotKey() + const messengerSlotVal = await ChugSplashDictator.messengerSlotVal() + const bridgeSlotKey = await ChugSplashDictator.bridgeSlotKey() + const bridgeSlotVal = await ChugSplashDictator.bridgeSlotVal() + const mantleAddressSlotKey = await ChugSplashDictator.mantleAddressSlotKey() + const mantleAddressSlotVal = await ChugSplashDictator.mantleAddressSlotVal() + + console.log(` + The ChugSplashDictator contract (glory to Arstotzka) has been deployed. + + FOLLOW THESE INSTRUCTIONS CAREFULLY! + + (1) Review the storage key/value pairs below and make sure they match the expected values: + + ${messengerSlotKey}: ${messengerSlotVal} + ${bridgeSlotKey}: ${bridgeSlotVal} + ${mantleAddressSlotKey}: ${mantleAddressSlotVal} + + (2) Review the CURRENT and FINAL proxy owners and verify that these are the expected values: + + Current proxy owner: (${currentOwner}) + Final proxy owner: (${finalOwner}) + + [${ + currentOwner === finalOwner + ? 'THESE ARE THE SAME ADDRESSES' + : 'THESE ARE >>>NOT<<< THE SAME ADDRESSES' + }] + + (3) Transfer ownership of the L1ChugSplashProxy located at (${ + Proxy__BVM_L1StandardBridge.address + }) + to the ChugSplashDictator contract located at the following address: + + TRANSFER OWNERSHIP TO THE FOLLOWING ADDRESS ONLY: + >>>>> (${ChugSplashDictator.address}) <<<<< + + (4) Wait for the deploy process to continue. + `) + + // Check if if we're on the hardhat chain ID. This will only happen in CI. If this is the case, we + // can skip directly to transferring ownership over to the ChugSplashDictator contract. + if ( + (await isHardhatNode(hre)) || + process.env.AUTOMATICALLY_TRANSFER_OWNERSHIP === 'true' + ) { + const owner = await hre.ethers.getSigner(currentOwner) + await Proxy__BVM_L1StandardBridge.connect(owner).setOwner( + ChugSplashDictator.address + ) + } + + // Wait for ownership to be transferred to the AddressDictator contract. + await awaitCondition( + async () => { + return hexStringEquals( + await Proxy__BVM_L1StandardBridge.connect( + Proxy__BVM_L1StandardBridge.signer.provider + ).callStatic.getOwner({ + from: ethers.constants.AddressZero, + }), + ChugSplashDictator.address + ) + }, + 30000, + 1000 + ) + + // Set the addresses! + console.log('Ownership successfully transferred. Invoking doActions...') + await ChugSplashDictator.doActions(bridgeCode) + + console.log(`Confirming that owner address was correctly set...`) + await awaitCondition( + async () => { + return hexStringEquals( + await Proxy__BVM_L1StandardBridge.connect( + Proxy__BVM_L1StandardBridge.signer.provider + ).callStatic.getOwner({ + from: ethers.constants.AddressZero, + }), + finalOwner + ) + }, + 5000, + 100 + ) + + // Deploy a copy of the implementation so it can be successfully verified on Etherscan. + console.log(`Deploying a copy of the bridge for Etherscan verification...`) + await deployAndVerifyAndThen({ + hre, + name: 'L1StandardBridge_for_verification_only', + contract: 'L1StandardBridge', + args: [], + }) +} + +deployFn.tags = ['L1StandardBridge', 'upgrade'] + +export default deployFn diff --git a/packages/contracts/deploy/016-finalize.ts b/packages/contracts/deploy/016-finalize.ts index e69de29bb..1aa2ef384 100644 --- a/packages/contracts/deploy/016-finalize.ts +++ b/packages/contracts/deploy/016-finalize.ts @@ -0,0 +1,45 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' +import { hexStringEquals, awaitCondition } from '@mantleio/core-utils' + +/* Imports: Internal */ +import { getContractFromArtifact } from '../src/deploy-utils' + +const deployFn: DeployFunction = async (hre) => { + const { deployer } = await hre.getNamedAccounts() + + const Lib_AddressManager = await getContractFromArtifact( + hre, + 'Lib_AddressManager', + { + signerOrProvider: deployer, + } + ) + + const owner = hre.deployConfig.bvmAddressManagerOwner + const remoteOwner = await Lib_AddressManager.owner() + if (hexStringEquals(owner, remoteOwner)) { + console.log( + `✓ Not changing owner of Lib_AddressManager because it's already correctly set` + ) + return + } + + console.log(`Transferring ownership of Lib_AddressManager to ${owner}...`) + await Lib_AddressManager.transferOwnership(owner) + + console.log(`Confirming transfer was successful...`) + await awaitCondition( + async () => { + return hexStringEquals(await Lib_AddressManager.owner(), owner) + }, + 5000, + 100 + ) + + console.log(`✓ Set owner of Lib_AddressManager to: ${owner}`) +} + +deployFn.tags = ['upgrade', 'finalize'] + +export default deployFn diff --git a/packages/contracts/deploy/017-fund-accounts.ts b/packages/contracts/deploy/017-fund-accounts.ts index e69de29bb..d433e4e0c 100644 --- a/packages/contracts/deploy/017-fund-accounts.ts +++ b/packages/contracts/deploy/017-fund-accounts.ts @@ -0,0 +1,60 @@ +/* Imports: External */ +import { sleep } from '@mantleio/core-utils' +import { DeployFunction } from 'hardhat-deploy/dist/types' +import { defaultHardhatNetworkHdAccountsConfigParams } from 'hardhat/internal/core/config/default-config' +import { normalizeHardhatNetworkAccountsConfig } from 'hardhat/internal/core/providers/util' + +/* Imports: Internal */ +import { getContractFromArtifact, isHardhatNode } from '../src/deploy-utils' +import { names } from '../src/address-names' + +// This is a TEMPORARY way to fund the default hardhat accounts on L2. The better way to do this is +// to make a modification to hardhat-bvm. However, I don't have the time right now to figure the +// details of how to make that work cleanly. This is fine in the meantime. +const deployFn: DeployFunction = async (hre) => { + // Only execute this step if we're on the hardhat chain ID. + if (await isHardhatNode(hre)) { + const L1StandardBridge = await getContractFromArtifact( + hre, + names.managed.contracts.Proxy__BVM_L1StandardBridge, + { + iface: 'L1StandardBridge', + } + ) + + // Default has 20 accounts but we restrict to 20 accounts manually as well just to prevent + // future problems if the number of default accounts increases for whatever reason. + const accounts = normalizeHardhatNetworkAccountsConfig( + defaultHardhatNetworkHdAccountsConfigParams + ).slice(0, 10) + + // Fund the accounts in parallel to speed things up. + await Promise.all( + accounts.map(async (account, index) => { + // Add a sleep here to avoid any potential issues with spamming hardhat. Not sure if this + // is strictly necessary but it can't hurt. + await sleep(200 * index ) + + const wallet = new hre.ethers.Wallet( + account.privateKey, + hre.ethers.provider + ) + const balance = await wallet.getBalance() + const depositAmount = balance.div(2) // Deposit half of the wallet's balance into L2. + await L1StandardBridge.connect(wallet).depositETH(8_000_000, '0x', { + value: depositAmount, + gasLimit: 2_000_000, // Idk, gas estimation was broken and this fixes it. + }) + console.log( + `✓ Funded ${wallet.address} on L2 with ${hre.ethers.utils.formatEther( + depositAmount + )} ETH` + ) + }) + ) + } +} + +deployFn.tags = ['fund-accounts'] + +export default deployFn diff --git a/packages/contracts/deploy/018-BVM_EigenDataLayrChain.deploy.ts b/packages/contracts/deploy/018-BVM_EigenDataLayrChain.deploy.ts index e69de29bb..416ed6414 100644 --- a/packages/contracts/deploy/018-BVM_EigenDataLayrChain.deploy.ts +++ b/packages/contracts/deploy/018-BVM_EigenDataLayrChain.deploy.ts @@ -0,0 +1,64 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +import { names } from '../src/address-names' +import { + deployAndVerifyAndThen, + getContractFromArtifact, +} from '../src/deploy-utils' + +const deployFn: DeployFunction = async (hre) => { + const { deployer } = await hre.getNamedAccounts() + + const owner = hre.deployConfig.bvmAddressManagerOwner + // const eigenSequencerAddress = hre.deployConfig.bvmSequencerAddress + const eigenSequencerAddress = hre.deployConfig.bvmEigenSequencerAddress + const dataManagerAddress = hre.deployConfig.dataManagerAddress + const reSubmitterAddress = hre.deployConfig.bvmEigenChallengerAddress + const blockStaleMeasure = hre.deployConfig.blockStaleMeasure + const daFraudProofPeriod = hre.deployConfig.daFraudProofPeriod + const l2SubmittedBlockNumber = hre.deployConfig.l2SubmittedBlockNumber + + const args = [ + eigenSequencerAddress, + dataManagerAddress, + reSubmitterAddress, + blockStaleMeasure, + daFraudProofPeriod, + l2SubmittedBlockNumber, + ] + await deployAndVerifyAndThen({ + hre, + name: names.managed.da.BVM_EigenDataLayrChain, + contract: 'BVM_EigenDataLayrChain', + args: [], + }) + console.log('deploy eigen datalayr chain success') + + const Impl_BVM_EigenDataLayrChain = await getContractFromArtifact( + hre, + names.managed.da.BVM_EigenDataLayrChain, + { + iface: 'BVM_EigenDataLayrChain', + signerOrProvider: deployer, + } + ) + + const callData = Impl_BVM_EigenDataLayrChain.interface.encodeFunctionData( + 'initialize', + args + ) + + await deployAndVerifyAndThen({ + hre, + name: names.managed.da.Proxy__BVM_EigenDataLayrChain, + contract: 'TransparentUpgradeableProxy', + iface: 'BVM_EigenDataLayrChain', + args: [Impl_BVM_EigenDataLayrChain.address, owner, callData], + }) + console.log('deploy eigen da proxy success') +} + +deployFn.tags = ['BVM_EigenDataLayrChain', 'upgrade'] + +export default deployFn diff --git a/packages/contracts/deploy/019-BVM_FraudProof.deploy.ts b/packages/contracts/deploy/019-BVM_FraudProof.deploy.ts index e69de29bb..8613b193b 100644 --- a/packages/contracts/deploy/019-BVM_FraudProof.deploy.ts +++ b/packages/contracts/deploy/019-BVM_FraudProof.deploy.ts @@ -0,0 +1,231 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +// @ts-ignore +import { names } from '../src/address-names' +import { + deployAndVerifyAndThen, + getContractFromArtifact, +} from '../src/deploy-utils' +import {awaitCondition, hexStringEquals} from "@mantleio/core-utils"; +import {deploy} from "../test/helpers"; + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { ethers, upgrades } = require("hardhat"); + +const deployFn: DeployFunction = async (hre) => { + // @ts-ignore + const { deployer } = await hre.getNamedAccounts() + + const Lib_AddressManager = await getContractFromArtifact( + hre, + names.unmanaged.Lib_AddressManager + ) + // @ts-ignore + const owner = hre.deployConfig.bvmAddressManagerOwner + // @ts-ignore + const l1MantleAddress = hre.deployConfig.proxyL1MantleAddress + + // deploy assertionMap impl + await deployAndVerifyAndThen({ + hre, + name: names.managed.fraud_proof.AssertionMap, + contract: 'AssertionMap', + args: [], + }) + const Impl__AssertionMap = await getContractFromArtifact( + hre, + names.managed.fraud_proof.AssertionMap, + { + iface: 'AssertionMap', + signerOrProvider: deployer, + } + ) + console.log('AssertionMap Implementation Address', Impl__AssertionMap.address) + console.log('deploy fraud proof assertionMap success') + + // deploy verifier impl + await deployAndVerifyAndThen({ + hre, + name: names.managed.fraud_proof.VerifierEntry, + contract: 'VerifierEntry', + args: [], + }) + const Impl__VerifierEntry = await getContractFromArtifact( + hre, + names.managed.fraud_proof.VerifierEntry, + { + iface: 'VerifierEntry', + signerOrProvider: deployer, + } + ) + console.log('Verifier Implementation Address', Impl__VerifierEntry.address) + console.log('deploy fraud proof verifier success') + + // deploy rollup impl + await deployAndVerifyAndThen({ + hre, + name: names.managed.fraud_proof.Rollup, + contract: 'Rollup', + args: [], + }) + const Impl__Rollup = await getContractFromArtifact( + hre, + names.managed.fraud_proof.Rollup, + { + iface: 'Rollup', + signerOrProvider: deployer, + } + ) + console.log('Rollup Implementation Address', Impl__Rollup.address) + console.log('deploy fraud proof assertion rollup success') + + // deploy assertionMap proxy + let callData = Impl__AssertionMap.interface.encodeFunctionData('initialize', []) + await deployAndVerifyAndThen({ + hre, + name: names.managed.fraud_proof.Proxy__AssertionMap, + contract: 'TransparentUpgradeableProxy', + iface: 'AssertionMap', + args: [Impl__AssertionMap.address, owner, callData], + }) + console.log('deploy fraud proof assertionMap proxy success') + const Proxy__AssertionMap = await getContractFromArtifact( + hre, + names.managed.fraud_proof.Proxy__AssertionMap, + { + iface: 'AssertionMap', + signerOrProvider: deployer, + } + ) + console.log('Proxy__AssertionMap Address', Proxy__AssertionMap.address) + console.log('deploy fraud proof Proxy__AssertionMap success') + + callData = Impl__VerifierEntry.interface.encodeFunctionData('initialize', []) + await deployAndVerifyAndThen({ + hre, + name: names.managed.fraud_proof.Proxy__Verifier, + contract: 'TransparentUpgradeableProxy', + iface: 'VerifierEntry', + args: [Impl__VerifierEntry.address, owner, callData], + }) + + const Proxy__VerifierEntry = await getContractFromArtifact( + hre, + names.managed.fraud_proof.Proxy__Verifier, + { + iface: 'VerifierEntry', + signerOrProvider: deployer, + } + ) + console.log('deploy fraud proof verifier proxy success') + + // deploy rollup proxy + const rollupArgs = [ + deployer, // address _owner + Proxy__VerifierEntry.address, // address _verifier, + l1MantleAddress, // address _stakeToken, + Lib_AddressManager.address, // address _libAddressManager, + Proxy__AssertionMap.address, // address _assertionMap, + 0, // uint256 _minimumAssertionPeriod, + 0, // uint256 _baseStakeAmount + '0x0000000000000000000000000000000000000000000000000000000000000000', // bytes32 _initialVMhash //TODO-FIXME + [], + [], + ] + callData = Impl__Rollup.interface.encodeFunctionData('initialize', rollupArgs) + await deployAndVerifyAndThen({ + hre, + name: names.managed.fraud_proof.Proxy__Rollup, + contract: 'TransparentUpgradeableProxy', + iface: 'Rollup', + args: [Impl__Rollup.address, owner, callData], + postDeployAction: async (contract) => { + // Theoretically it's not necessary to initialize this contract since it sits behind + // a proxy. However, it's best practice to initialize it anyway just in case there's + // some unknown security hole. It also prevents another user from appearing like an + // official address because it managed to call the initialization function. + // console.log(`Initializing fraud-proof Rollup (implementation)...`) + // await contract.initialize(...rollupArgs) + + console.log(`Checking that contract was correctly initialized...`) + await awaitCondition( + async () => { + return hexStringEquals( + await contract.libAddressManager(), + Lib_AddressManager.address + ) + }, + 5000, + 100 + ) + console.log('>>>> assertions ',await contract.assertions()) + await awaitCondition( + async () => { + return hexStringEquals( + await contract.assertions(), + Proxy__AssertionMap.address + ) + }, + 5000, + 100 + ) + console.log('>>>> owner ',await contract.owner()) + await awaitCondition( + async () => { + return hexStringEquals( + await contract.owner(), + deployer + ) + }, + 5000, + 100 + ) + // console.log('>>>> whitelists', contract.whitelist()) + // await awaitCondition( + // async () => { + // return hexStringEquals( + // await contract.whitelist().length, + // "3" + // ) + // }, + // 5000, + // 100 + // ) + }, + }) + console.log('deploy fraud proof rollup proxy success') + const Proxy__Rollup = await getContractFromArtifact( + hre, + names.managed.fraud_proof.Proxy__Rollup, + { + iface: 'Rollup', + signerOrProvider: deployer, + } + ) + console.log('Proxy__Rollup Address', Proxy__Rollup.address) + console.log('deploy fraud proof Proxy__Rollup success') + // @ts-ignore + // await awaitCondition( + // async () => { + // // @ts-ignore + // // eslint-disable-next-line @typescript-eslint/no-shadow + // const wl1 = Rollup.whitelist('0xd5b002298b2e81b4ced1b6c8cf1964023cdc3758') + // // @ts-ignore + // // eslint-disable-next-line @typescript-eslint/no-shadow + // const wl2 = Rollup.whitelist('0xd55fe10a1acb32b6183bdfbeb42e9961c3cb8792') + // // @ts-ignore + // // eslint-disable-next-line @typescript-eslint/no-shadow + // const wl3 = Rollup.whitelist('0xd55fe2797c18d721ee197d09fa0dda584f92b5af') + // return wl1 === true && wl2 === true && wl3 === true + // }, + // 5000, + // 100 + // ) + // console.log('>>>> staker all whitelisted !!!!') +} + +// This is kept during an upgrade. So no upgrade tag. +deployFn.tags = ['FraudProof', 'upgrade'] + +export default deployFn diff --git a/packages/contracts/deploy/020-BVM_EigenDataLayrFee.deploy.ts b/packages/contracts/deploy/020-BVM_EigenDataLayrFee.deploy.ts index e69de29bb..3bae2a0fb 100644 --- a/packages/contracts/deploy/020-BVM_EigenDataLayrFee.deploy.ts +++ b/packages/contracts/deploy/020-BVM_EigenDataLayrFee.deploy.ts @@ -0,0 +1,50 @@ +/* Imports: External */ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +import { names } from '../src/address-names' +import { + deployAndVerifyAndThen, + getContractFromArtifact, +} from '../src/deploy-utils' + +const deployFn: DeployFunction = async (hre) => { + const { deployer } = await hre.getNamedAccounts() + const owner = hre.deployConfig.bvmAddressManagerOwner + const eigenFeeAddress = hre.deployConfig.bvmEigenFeeAddress + + await deployAndVerifyAndThen({ + hre, + name: names.managed.da.BVM_EigenDataLayrFee, + contract: 'BVM_EigenDataLayrFee', + args: [], + }) + console.log('deploy eigen datalayr fee success') + + const Impl_EigenDataLayrFee = await getContractFromArtifact( + hre, + names.managed.da.BVM_EigenDataLayrFee, + { + iface: 'BVM_EigenDataLayrFee', + signerOrProvider: deployer, + } + ) + + const args = [eigenFeeAddress] + const callData = Impl_EigenDataLayrFee.interface.encodeFunctionData( + 'initialize', + args + ) + + await deployAndVerifyAndThen({ + hre, + name: names.managed.da.Proxy__BVM_EigenDataLayrFee, + contract: 'TransparentUpgradeableProxy', + iface: 'BVM_EigenDataLayrFee', + args: [Impl_EigenDataLayrFee.address, owner, callData], + }) + console.log('deploy eigen da fee proxy success') +} + +deployFn.tags = ['BVM_EigenDataLayrFee', 'upgrade'] + +export default deployFn