Commit 1c42c5f7 authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

Parallelize contract deployments (#3247)

parent c72173e4
import { DeployFunction } from 'hardhat-deploy/dist/types' import { DeployFunction } from 'hardhat-deploy/dist/types'
import 'hardhat-deploy' import 'hardhat-deploy'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config' import '@eth-optimism/hardhat-deploy-config'
// TODO(tynes): This needs to be deployed for fresh networks const proxies = [
// but not for upgrading existing networks 'L2OutputOracleProxy',
'L1CrossDomainMessengerProxy',
'L1StandardBridgeProxy',
'OptimismPortalProxy',
'OptimismMintableERC20FactoryProxy',
]
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments const { deploy } = hre.deployments
const { deployer } = await hre.getNamedAccounts() const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre const { deployConfig } = hre
const l1 = hre.ethers.provider
const promises = []
const nonce = await l1.getTransactionCount(deployer)
for (let i = 0; i < proxies.length; i++) {
const proxy = proxies[i]
promises.push(
deploy(proxy, {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
nonce: nonce + i,
})
)
}
await deploy('AddressManager', { await Promise.all(promises)
from: deployer,
args: [],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
} }
deployFn.tags = ['Lib_AddressManager', 'legacy'] deployFn.tags = ['InitProxies']
export default deployFn export default deployFn
/* Imports: Internal */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { BigNumber } from 'ethers'
import 'hardhat-deploy'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments
const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
let deployL2StartingTimestamp = deployConfig.l2OutputOracleStartingTimestamp
if (deployL2StartingTimestamp < 0) {
const l1 = hre.ethers.provider
const l1StartingBlock = await l1.getBlock(deployConfig.l1StartingBlockTag)
if (l1StartingBlock === null) {
throw new Error(
`Cannot fetch block tag ${deployConfig.l1StartingBlockTag}`
)
}
deployL2StartingTimestamp = l1StartingBlock.timestamp
}
await deploy('L2OutputOracleProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
await deploy('L2OutputOracle', {
from: deployer,
args: [
deployConfig.l2OutputOracleSubmissionInterval,
deployConfig.l2OutputOracleGenesisL2Output,
deployConfig.l2OutputOracleHistoricalTotalBlocks,
deployConfig.l2OutputOracleStartingBlockNumber,
deployL2StartingTimestamp,
deployConfig.l2BlockTime,
deployConfig.l2OutputOracleProposer,
deployConfig.l2OutputOracleOwner,
],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
const oracle = await hre.deployments.get('L2OutputOracle')
const proxy = await hre.deployments.get('L2OutputOracleProxy')
const Proxy = await hre.ethers.getContractAt('Proxy', proxy.address)
const L2OutputOracle = await hre.ethers.getContractAt(
'L2OutputOracle',
proxy.address
)
const tx = await Proxy.upgradeToAndCall(
oracle.address,
L2OutputOracle.interface.encodeFunctionData(
'initialize(bytes32,uint256,address,address)',
[
deployConfig.l2OutputOracleGenesisL2Output,
deployConfig.l2OutputOracleStartingBlockNumber,
deployConfig.l2OutputOracleProposer,
deployConfig.l2OutputOracleOwner,
]
)
)
await tx.wait()
const submissionInterval = await L2OutputOracle.SUBMISSION_INTERVAL()
if (
!submissionInterval.eq(
BigNumber.from(deployConfig.l2OutputOracleSubmissionInterval)
)
) {
throw new Error('submission internal misconfigured')
}
const historicalBlocks = await L2OutputOracle.HISTORICAL_TOTAL_BLOCKS()
if (
!historicalBlocks.eq(
BigNumber.from(deployConfig.l2OutputOracleHistoricalTotalBlocks)
)
) {
throw new Error('historal total blocks misconfigured')
}
const startingBlockNumber = await L2OutputOracle.STARTING_BLOCK_NUMBER()
if (
!startingBlockNumber.eq(
BigNumber.from(deployConfig.l2OutputOracleStartingBlockNumber)
)
) {
throw new Error('starting block number misconfigured')
}
const startingTimestamp = await L2OutputOracle.STARTING_TIMESTAMP()
if (!startingTimestamp.eq(BigNumber.from(deployL2StartingTimestamp))) {
throw new Error('starting timestamp misconfigured')
}
const l2BlockTime = await L2OutputOracle.L2_BLOCK_TIME()
if (!l2BlockTime.eq(BigNumber.from(deployConfig.l2BlockTime))) {
throw new Error('L2 block time misconfigured')
}
}
deployFn.tags = ['L2OutputOracle']
export default deployFn
/* Imports: Internal */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { BigNumber } from 'ethers'
import 'hardhat-deploy'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
const upgradeABIs = {
L2OutputOracleProxy: async (deployConfig) => [
'initialize(bytes32,uint256,address,address)',
[
deployConfig.l2OutputOracleGenesisL2Output,
deployConfig.l2OutputOracleStartingBlockNumber,
deployConfig.l2OutputOracleProposer,
deployConfig.l2OutputOracleOwner,
],
],
OptimismPortalProxy: async () => ['initialize', []],
L1CrossDomainMessengerProxy: async () => ['initialize', []],
L1StandardBridgeProxy: async (deployConfig, hre) => {
const messenger = await hre.deployments.get('L1CrossDomainMessengerProxy')
console.log(messenger.address)
return ['initialize(address)', [messenger.address]]
},
}
const deployFn: DeployFunction = async (hre) => {
const { deploy, get } = hre.deployments
const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
const l1 = hre.ethers.provider
let deployL2StartingTimestamp = deployConfig.l2OutputOracleStartingTimestamp
if (deployL2StartingTimestamp < 0) {
const l1StartingBlock = await l1.getBlock(deployConfig.l1StartingBlockTag)
if (l1StartingBlock === null) {
throw new Error(
`Cannot fetch block tag ${deployConfig.l1StartingBlockTag}`
)
}
deployL2StartingTimestamp = l1StartingBlock.timestamp
}
const oracleProxy = await get('L2OutputOracleProxy')
const portalProxy = await get('OptimismPortalProxy')
const messengerProxy = await get('L1CrossDomainMessengerProxy')
const bridgeProxy = await get('L1StandardBridgeProxy')
let nonce = await l1.getTransactionCount(deployer)
const implTxs = [
deploy('L2OutputOracle', {
from: deployer,
args: [
deployConfig.l2OutputOracleSubmissionInterval,
deployConfig.l2OutputOracleGenesisL2Output,
deployConfig.l2OutputOracleHistoricalTotalBlocks,
deployConfig.l2OutputOracleStartingBlockNumber,
deployL2StartingTimestamp,
deployConfig.l2BlockTime,
deployConfig.l2OutputOracleProposer,
deployConfig.l2OutputOracleOwner,
],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
nonce,
}),
deploy('OptimismPortal', {
from: deployer,
args: [oracleProxy.address, 2],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
nonce: ++nonce,
}),
deploy('L1CrossDomainMessenger', {
from: deployer,
args: [portalProxy.address],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
nonce: ++nonce,
}),
deploy('L1StandardBridge', {
from: deployer,
args: [messengerProxy.address],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
nonce: ++nonce,
}),
deploy('OptimismMintableERC20Factory', {
from: deployer,
args: [bridgeProxy.address],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
nonce: ++nonce,
}),
deploy('AddressManager', {
from: deployer,
args: [],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
nonce: ++nonce,
}),
deploy('ProxyAdmin', {
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
nonce: ++nonce,
}),
]
await Promise.all(implTxs)
const upgradeTxs = []
for (const [proxy, upgrader] of Object.entries(upgradeABIs)) {
const upgraderOut = await upgrader(deployConfig, hre)
const implName = proxy.replace('Proxy', '')
const implDeployment = await get(implName)
const implContract = await hre.ethers.getContractAt(
implName,
implDeployment.address
)
const proxyDeployment = await get(proxy)
const proxyContract = await hre.ethers.getContractAt(
'Proxy',
proxyDeployment.address
)
upgradeTxs.push(
proxyContract.upgradeToAndCall(
implContract.address,
implContract.interface.encodeFunctionData(
upgraderOut[0] as string,
upgraderOut[1] as any[]
),
{
nonce: ++nonce,
}
)
)
}
const factory = await get('OptimismMintableERC20Factory')
const factoryProxy = await get('OptimismMintableERC20FactoryProxy')
const factoryProxyContract = await hre.ethers.getContractAt(
'Proxy',
factoryProxy.address
)
upgradeTxs.push(factoryProxyContract.upgradeTo(factory.address))
const rawTxs = await Promise.all(upgradeTxs)
await Promise.all(rawTxs.map((tx) => tx.wait()))
await validateOracle(hre, deployConfig, deployL2StartingTimestamp)
await validatePortal(hre)
await validateMessenger(hre)
await validateBridge(hre)
await validateTokenFactory(hre)
}
const validateOracle = async (hre, deployConfig, deployL2StartingTimestamp) => {
const proxy = await hre.deployments.get('L2OutputOracleProxy')
const L2OutputOracle = await hre.ethers.getContractAt(
'L2OutputOracle',
proxy.address
)
const submissionInterval = await L2OutputOracle.SUBMISSION_INTERVAL()
if (
!submissionInterval.eq(
BigNumber.from(deployConfig.l2OutputOracleSubmissionInterval)
)
) {
throw new Error('submission internal misconfigured')
}
const historicalBlocks = await L2OutputOracle.HISTORICAL_TOTAL_BLOCKS()
if (
!historicalBlocks.eq(
BigNumber.from(deployConfig.l2OutputOracleHistoricalTotalBlocks)
)
) {
throw new Error('historical total blocks misconfigured')
}
const startingBlockNumber = await L2OutputOracle.STARTING_BLOCK_NUMBER()
if (
!startingBlockNumber.eq(
BigNumber.from(deployConfig.l2OutputOracleStartingBlockNumber)
)
) {
throw new Error('starting block number misconfigured')
}
const startingTimestamp = await L2OutputOracle.STARTING_TIMESTAMP()
if (!startingTimestamp.eq(BigNumber.from(deployL2StartingTimestamp))) {
throw new Error('starting timestamp misconfigured')
}
const l2BlockTime = await L2OutputOracle.L2_BLOCK_TIME()
if (!l2BlockTime.eq(BigNumber.from(deployConfig.l2BlockTime))) {
throw new Error('L2 block time misconfigured')
}
}
const validatePortal = async (hre) => {
const oracle = await hre.deployments.get('L2OutputOracleProxy')
const proxy = await hre.deployments.get('OptimismPortalProxy')
const OptimismPortal = await hre.ethers.getContractAt(
'OptimismPortal',
proxy.address
)
const l2Oracle = await OptimismPortal.L2_ORACLE()
if (l2Oracle !== oracle.address) {
throw new Error('L2 Oracle mismatch')
}
}
const validateMessenger = async (hre) => {
const portal = await hre.deployments.get('OptimismPortalProxy')
const proxy = await hre.deployments.get('L1CrossDomainMessengerProxy')
const L1CrossDomainMessenger = await hre.ethers.getContractAt(
'L1CrossDomainMessenger',
proxy.address
)
const portalAddress = await L1CrossDomainMessenger.portal()
if (portalAddress !== portal.address) {
throw new Error('portal misconfigured')
}
}
const validateBridge = async (hre) => {
const messenger = await hre.deployments.get('L1CrossDomainMessengerProxy')
const proxy = await hre.deployments.get('L1StandardBridgeProxy')
const L1StandardBridge = await hre.ethers.getContractAt(
'L1StandardBridge',
proxy.address
)
if (messenger.address !== (await L1StandardBridge.messenger())) {
throw new Error('misconfigured messenger')
}
}
const validateTokenFactory = async (hre) => {
const bridge = await hre.deployments.get('L1StandardBridgeProxy')
const proxy = await hre.deployments.get('OptimismMintableERC20FactoryProxy')
const OptimismMintableERC20Factory = await hre.ethers.getContractAt(
'OptimismMintableERC20Factory',
proxy.address
)
if (bridge.address !== (await OptimismMintableERC20Factory.bridge())) {
throw new Error('bridge misconfigured')
}
}
deployFn.tags = ['InitImplementations']
export default deployFn
/* Imports: Internal */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import 'hardhat-deploy'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
const deployFn: DeployFunction = async (hre) => {
const { deploy, get } = hre.deployments
const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
await deploy('OptimismPortalProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
const oracle = await get('L2OutputOracleProxy')
await deploy('OptimismPortal', {
from: deployer,
args: [oracle.address, 2],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
const proxy = await hre.deployments.get('OptimismPortalProxy')
const Proxy = await hre.ethers.getContractAt('Proxy', proxy.address)
const OptimismPortal = await hre.ethers.getContractAt(
'OptimismPortal',
proxy.address
)
const portal = await hre.deployments.get('OptimismPortal')
const tx = await Proxy.upgradeToAndCall(
portal.address,
OptimismPortal.interface.encodeFunctionData('initialize()')
)
await tx.wait()
const l2Oracle = await OptimismPortal.L2_ORACLE()
if (l2Oracle !== oracle.address) {
throw new Error('L2 Oracle mismatch')
}
}
deployFn.tags = ['OptimismPortal']
export default deployFn
...@@ -4,17 +4,6 @@ import '@nomiclabs/hardhat-ethers' ...@@ -4,17 +4,6 @@ import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config' import '@eth-optimism/hardhat-deploy-config'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments
const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
await deploy('ProxyAdmin', {
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
const admin = await hre.deployments.get('ProxyAdmin') const admin = await hre.deployments.get('ProxyAdmin')
const ProxyAdmin = await hre.ethers.getContractAt('ProxyAdmin', admin.address) const ProxyAdmin = await hre.ethers.getContractAt('ProxyAdmin', admin.address)
...@@ -50,6 +39,6 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -50,6 +39,6 @@ const deployFn: DeployFunction = async (hre) => {
await Promise.all(postConfig.map((tx) => tx.wait())) await Promise.all(postConfig.map((tx) => tx.wait()))
} }
deployFn.tags = ['ProxyAdmin'] deployFn.tags = ['ConfigureProxyAdmin']
export default deployFn export default deployFn
/* Imports: Internal */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import 'hardhat-deploy'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments
const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
await deploy('L1CrossDomainMessengerProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
const portal = await hre.deployments.get('OptimismPortalProxy')
await deploy('L1CrossDomainMessenger', {
from: deployer,
args: [portal.address],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
const proxy = await hre.deployments.get('L1CrossDomainMessengerProxy')
const Proxy = await hre.ethers.getContractAt('Proxy', proxy.address)
const messenger = await hre.deployments.get('L1CrossDomainMessenger')
const L1CrossDomainMessenger = await hre.ethers.getContractAt(
'L1CrossDomainMessenger',
proxy.address
)
const upgradeTx = await Proxy.upgradeToAndCall(
messenger.address,
L1CrossDomainMessenger.interface.encodeFunctionData('initialize')
)
await upgradeTx.wait()
const portalAddress = await L1CrossDomainMessenger.portal()
if (portalAddress !== portal.address) {
throw new Error('portal misconfigured')
}
}
deployFn.tags = ['L1CrossDomainMessenger']
export default deployFn
/* Imports: Internal */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import 'hardhat-deploy'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments
const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
await deploy('L1StandardBridgeProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
const messenger = await hre.deployments.get('L1CrossDomainMessengerProxy')
await deploy('L1StandardBridge', {
from: deployer,
args: [messenger.address],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
const proxy = await hre.deployments.get('L1StandardBridgeProxy')
const Proxy = await hre.ethers.getContractAt('Proxy', proxy.address)
const bridge = await hre.deployments.get('L1StandardBridge')
const L1StandardBridge = await hre.ethers.getContractAt(
'L1StandardBridge',
proxy.address
)
const upgradeTx = await Proxy.upgradeToAndCall(
bridge.address,
L1StandardBridge.interface.encodeFunctionData('initialize(address)', [
messenger.address,
])
)
await upgradeTx.wait()
if (messenger.address !== (await L1StandardBridge.messenger())) {
throw new Error('misconfigured messenger')
}
}
deployFn.tags = ['L1StandardBridge']
export default deployFn
/* Imports: Internal */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import 'hardhat-deploy'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments
const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
await deploy('OptimismMintableERC20FactoryProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
const bridge = await hre.deployments.get('L1StandardBridgeProxy')
await deploy('OptimismMintableERC20Factory', {
from: deployer,
args: [bridge.address],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
const factory = await hre.deployments.get('OptimismMintableERC20Factory')
const proxy = await hre.deployments.get('OptimismMintableERC20FactoryProxy')
const Proxy = await hre.ethers.getContractAt('Proxy', proxy.address)
const OptimismMintableERC20Factory = await hre.ethers.getContractAt(
'OptimismMintableERC20Factory',
proxy.address
)
const upgradeTx = await Proxy.upgradeTo(factory.address)
await upgradeTx.wait()
if (bridge.address !== (await OptimismMintableERC20Factory.bridge())) {
throw new Error('bridge misconfigured')
}
}
deployFn.tags = ['OptimismMintableERC20Factory']
export default deployFn
...@@ -130,16 +130,16 @@ export const CONTRACT_ADDRESSES: { ...@@ -130,16 +130,16 @@ export const CONTRACT_ADDRESSES: {
}, },
[L2ChainID.OPTIMISM_BEDROCK_LOCAL_DEVNET]: { [L2ChainID.OPTIMISM_BEDROCK_LOCAL_DEVNET]: {
l1: { l1: {
AddressManager: '0x5FbDB2315678afecb367f032d93F642f64180aa3' as const, AddressManager: '0x610178dA211FEF7D417bC0e6FeD39F05609AD788' as const,
L1CrossDomainMessenger: L1CrossDomainMessenger:
'0x0165878A594ca255338adfa4d48449f69242Eb8F' as const, '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512' as const,
L1StandardBridge: '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318' as const, L1StandardBridge: '0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0' as const,
StateCommitmentChain: StateCommitmentChain:
'0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9' as const, '0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9' as const,
CanonicalTransactionChain: CanonicalTransactionChain:
'0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9' as const, '0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9' as const,
BondManager: '0x5FC8d32690cc91D4c39d9d3abcBD16989F875707' as const, BondManager: '0x5FC8d32690cc91D4c39d9d3abcBD16989F875707' as const,
OptimismPortal: '0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9' as const, OptimismPortal: '0x0165878A594ca255338adfa4d48449f69242Eb8F' as const,
L2OutputOracle: '0x5FbDB2315678afecb367f032d93F642f64180aa3' as const, L2OutputOracle: '0x5FbDB2315678afecb367f032d93F642f64180aa3' as const,
}, },
l2: DEFAULT_L2_CONTRACT_ADDRESSES, l2: DEFAULT_L2_CONTRACT_ADDRESSES,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment