Commit 7c6e9a56 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge pull request #4039 from ethereum-optimism/sc/ctb-unified-deploy-2

feat(ctb): unify fresh and migration deployments
parents 088d168d 1362c808
......@@ -61,7 +61,7 @@ def main():
addresses = read_json(addresses_json_path)
else:
log.info('Deploying contracts.')
run_command(['yarn', 'hardhat', '--network', 'devnetL1', 'deploy', '--tags', 'fresh'], env={
run_command(['yarn', 'hardhat', '--network', 'devnetL1', 'deploy'], env={
'CHAIN_ID': '900',
'L1_RPC': 'http://localhost:8545',
'PRIVATE_KEY_DEPLOYER': 'ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { L2OutputOracle } from "../L1/L2OutputOracle.sol";
import { OptimismPortal } from "../L1/OptimismPortal.sol";
import { SystemConfig } from "../L1/SystemConfig.sol";
import { L1CrossDomainMessenger } from "../L1/L1CrossDomainMessenger.sol";
import { BaseSystemDictator } from "./BaseSystemDictator.sol";
/**
* @title FreshSystemDictator
* @notice The FreshSystemDictator is responsible for coordinating initialization of a fresh
* deployment of the Optimism system. We expect that all proxies and implementations
* already be deployed before this contract is used.
*/
contract FreshSystemDictator is BaseSystemDictator {
/**
* @param _config System configuration.
*/
constructor(DeployConfig memory _config) BaseSystemDictator(_config) {}
/**
* @notice Upgrades and initializes proxy contracts.
*/
function step1() external onlyOwner step(1) {
// Upgrade and initialize the L2OutputOracle.
config.globalConfig.proxyAdmin.upgradeAndCall(
payable(config.proxyAddressConfig.l2OutputOracleProxy),
address(config.implementationAddressConfig.l2OutputOracleImpl),
abi.encodeCall(
L2OutputOracle.initialize,
(
config.l2OutputOracleConfig.l2OutputOracleGenesisL2Output,
config.l2OutputOracleConfig.l2OutputOracleProposer,
config.l2OutputOracleConfig.l2OutputOracleOwner
)
)
);
// Upgrade and initialize the OptimismPortal.
config.globalConfig.proxyAdmin.upgradeAndCall(
payable(config.proxyAddressConfig.optimismPortalProxy),
address(config.implementationAddressConfig.optimismPortalImpl),
abi.encodeCall(OptimismPortal.initialize, ())
);
// Upgrade and initialize the L1CrossDomainMessenger.
config.globalConfig.proxyAdmin.upgradeAndCall(
payable(config.proxyAddressConfig.l1CrossDomainMessengerProxy),
address(config.implementationAddressConfig.l1CrossDomainMessengerImpl),
abi.encodeCall(L1CrossDomainMessenger.initialize, (config.globalConfig.finalOwner))
);
// Upgrade the L1StandardBridge (no initializer).
config.globalConfig.proxyAdmin.upgrade(
payable(config.proxyAddressConfig.l1StandardBridgeProxy),
address(config.implementationAddressConfig.l1StandardBridgeImpl)
);
// Upgrade the OptimismMintableERC20Factory (no initializer).
config.globalConfig.proxyAdmin.upgrade(
payable(config.proxyAddressConfig.optimismMintableERC20FactoryProxy),
address(config.implementationAddressConfig.optimismMintableERC20FactoryImpl)
);
// Upgrade the L1ERC721Bridge (no initializer).
config.globalConfig.proxyAdmin.upgrade(
payable(config.proxyAddressConfig.l1ERC721BridgeProxy),
address(config.implementationAddressConfig.l1ERC721BridgeImpl)
);
// Upgrade and initialize the SystemConfig.
config.globalConfig.proxyAdmin.upgradeAndCall(
payable(config.proxyAddressConfig.systemConfigProxy),
address(config.implementationAddressConfig.systemConfigImpl),
abi.encodeCall(
SystemConfig.initialize,
(
config.systemConfigConfig.owner,
config.systemConfigConfig.overhead,
config.systemConfigConfig.scalar,
config.systemConfigConfig.batcherHash,
config.systemConfigConfig.gasLimit
)
)
);
}
/**
* @notice Transfers ownership to final owner.
*/
function step2() external onlyOwner step(2) {
// Transfer ownership of the ProxyAdmin to the final owner.
config.globalConfig.proxyAdmin.transferOwnership(config.globalConfig.finalOwner);
}
}
......@@ -143,10 +143,6 @@ contract MigrationSystemDictator is BaseSystemDictator {
* @notice Upgrades and initializes proxy contracts.
*/
function step5() external onlyOwner step(5) {
// Pause the L1CrossDomainMessenger. Now we use the real pause() function because by the
// time we're done here we'll have access to the unpause() function.
L1CrossDomainMessenger(config.proxyAddressConfig.l1CrossDomainMessengerProxy).pause();
// Upgrade and initialize the L2OutputOracle.
config.globalConfig.proxyAdmin.upgradeAndCall(
payable(config.proxyAddressConfig.l2OutputOracleProxy),
......@@ -168,13 +164,34 @@ contract MigrationSystemDictator is BaseSystemDictator {
abi.encodeCall(OptimismPortal.initialize, ())
);
// Upgrade the L1CrossDomainMessenger. No initializer because this is
// already initialized.
// Upgrade the L1CrossDomainMessenger.
config.globalConfig.proxyAdmin.upgrade(
payable(config.proxyAddressConfig.l1CrossDomainMessengerProxy),
address(config.implementationAddressConfig.l1CrossDomainMessengerImpl)
);
// Try to initialize the L1CrossDomainMessenger, only fail if it's already been initialized.
try
L1CrossDomainMessenger(config.proxyAddressConfig.l1CrossDomainMessengerProxy)
.initialize(address(this))
{
// L1CrossDomainMessenger is the one annoying edge case difference between existing
// networks and fresh networks because in existing networks it'll already be
// initialized but in fresh networks it won't be. Try/catch is the easiest and most
// consistent way to handle this because initialized() is not exposed publicly.
} catch Error(string memory reason) {
require(
keccak256(abi.encodePacked(reason)) ==
keccak256("Initializable: contract is already initialized"),
string.concat(
"MigrationSystemDictator: unexpected error initializing L1XDM: ",
reason
)
);
} catch {
revert("MigrationSystemDictator: unexpected error initializing L1XDM (no reason)");
}
// Transfer ETH from the L1StandardBridge to the OptimismPortal.
config.globalConfig.proxyAdmin.upgradeAndCall(
payable(config.proxyAddressConfig.l1StandardBridgeProxy),
......@@ -215,6 +232,9 @@ contract MigrationSystemDictator is BaseSystemDictator {
)
)
);
// Pause the L1CrossDomainMessenger, chance to check that everything is OK.
L1CrossDomainMessenger(config.proxyAddressConfig.l1CrossDomainMessengerProxy).pause();
}
/**
......
......@@ -19,6 +19,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['ProxyAdmin', 'fresh', 'migration']
deployFn.tags = ['ProxyAdmin']
export default deployFn
......@@ -3,22 +3,22 @@ import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
assertContractVariable,
deployAndVerifyAndThen,
getDeploymentAddress,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const proxyAdmin = await getDeploymentAddress(hre, 'ProxyAdmin')
const { deployer } = await hre.getNamedAccounts()
await deployAndVerifyAndThen({
hre,
name: 'L1StandardBridgeProxy',
contract: 'Proxy',
args: [proxyAdmin],
name: 'Lib_AddressManager',
contract: 'AddressManager',
args: [],
postDeployAction: async (contract) => {
await assertContractVariable(contract, 'admin', proxyAdmin)
// Owner is temporarily set to the deployer.
await assertContractVariable(contract, 'owner', deployer)
},
})
}
deployFn.tags = ['L1StandardBridgeProxy', 'fresh']
deployFn.tags = ['AddressManager']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
assertContractVariable,
deployAndVerifyAndThen,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
await deployAndVerifyAndThen({
hre,
name: 'Proxy__OVM_L1StandardBridge',
contract: 'L1ChugSplashProxy',
args: [deployer],
postDeployAction: async (contract) => {
await assertContractVariable(contract, 'getOwner', deployer)
},
})
}
deployFn.tags = ['L1StandardBridgeProxy']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
assertContractVariable,
deployAndVerifyAndThen,
getDeploymentAddress,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const proxyAdmin = await getDeploymentAddress(hre, 'ProxyAdmin')
await deployAndVerifyAndThen({
hre,
name: 'L1CrossDomainMessengerProxy',
contract: 'Proxy',
args: [proxyAdmin],
postDeployAction: async (contract) => {
await assertContractVariable(contract, 'admin', proxyAdmin)
},
})
}
deployFn.tags = ['L1CrossDomainMessengerProxy', 'fresh']
export default deployFn
......@@ -19,6 +19,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['L2OutputOracleProxy', 'fresh', 'migration']
deployFn.tags = ['L2OutputOracleProxy']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
deployAndVerifyAndThen,
getDeploymentAddress,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const addressManager = await getDeploymentAddress(hre, 'Lib_AddressManager')
await deployAndVerifyAndThen({
hre,
name: 'Proxy__OVM_L1CrossDomainMessenger',
contract: 'ResolvedDelegateProxy',
args: [addressManager, 'OVM_L1CrossDomainMessenger'],
})
}
deployFn.tags = ['L1CrossDomainMessengerProxy']
export default deployFn
......@@ -19,6 +19,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['OptimismPortalProxy', 'fresh', 'migration']
deployFn.tags = ['OptimismPortalProxy']
export default deployFn
......@@ -19,6 +19,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['OptimismMintableERC20FactoryProxy', 'fresh', 'migration']
deployFn.tags = ['OptimismMintableERC20FactoryProxy']
export default deployFn
......@@ -19,6 +19,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['L1ERC721BridgeProxy', 'fresh', 'migration']
deployFn.tags = ['L1ERC721BridgeProxy']
export default deployFn
......@@ -19,6 +19,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['SystemConfigProxy', 'fresh', 'migration']
deployFn.tags = ['SystemConfigProxy']
export default deployFn
......@@ -12,6 +12,7 @@ const deployFn: DeployFunction = async (hre) => {
hre,
'OptimismPortalProxy'
)
await deployAndVerifyAndThen({
hre,
name: 'L1CrossDomainMessenger',
......@@ -31,6 +32,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['L1CrossDomainMessengerImpl', 'fresh', 'migration']
deployFn.tags = ['L1CrossDomainMessengerImpl']
export default deployFn
import { ethers } from 'ethers'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { predeploys } from '../src'
......@@ -9,18 +8,10 @@ import {
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
let L1CrossDomainMessengerProxy: ethers.Contract
try {
L1CrossDomainMessengerProxy = await getContractFromArtifact(
hre,
'Proxy__OVM_L1CrossDomainMessenger'
)
} catch {
L1CrossDomainMessengerProxy = await getContractFromArtifact(
hre,
'L1CrossDomainMessengerProxy'
)
}
const L1CrossDomainMessengerProxy = await getContractFromArtifact(
hre,
'Proxy__OVM_L1CrossDomainMessenger'
)
await deployAndVerifyAndThen({
hre,
......@@ -41,6 +32,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['L1StandardBridgeImpl', 'fresh', 'migration']
deployFn.tags = ['L1StandardBridgeImpl']
export default deployFn
......@@ -91,6 +91,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['L2OutputOracleImpl', 'fresh', 'migration']
deployFn.tags = ['L2OutputOracleImpl']
export default deployFn
......@@ -12,6 +12,7 @@ const deployFn: DeployFunction = async (hre) => {
hre,
'L2OutputOracleProxy'
)
await deployAndVerifyAndThen({
hre,
name: 'OptimismPortal',
......@@ -34,6 +35,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['OptimismPortalImpl', 'fresh', 'migration']
deployFn.tags = ['OptimismPortalImpl']
export default deployFn
import { ethers } from 'ethers'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
......@@ -8,18 +7,10 @@ import {
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
let L1StandardBridgeProxy: ethers.Contract
try {
L1StandardBridgeProxy = await getContractFromArtifact(
hre,
'Proxy__OVM_L1StandardBridge'
)
} catch (e) {
L1StandardBridgeProxy = await getContractFromArtifact(
hre,
'L1StandardBridgeProxy'
)
}
const L1StandardBridgeProxy = await getContractFromArtifact(
hre,
'Proxy__OVM_L1StandardBridge'
)
await deployAndVerifyAndThen({
hre,
......@@ -35,6 +26,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['OptimismMintableERC20FactoryImpl', 'fresh', 'migration']
deployFn.tags = ['OptimismMintableERC20FactoryImpl']
export default deployFn
import { ethers } from 'ethers'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { predeploys } from '../src'
......@@ -9,18 +8,10 @@ import {
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
let L1CrossDomainMessengerProxy: ethers.Contract
try {
L1CrossDomainMessengerProxy = await getContractFromArtifact(
hre,
'Proxy__OVM_L1CrossDomainMessenger'
)
} catch {
L1CrossDomainMessengerProxy = await getContractFromArtifact(
hre,
'L1CrossDomainMessengerProxy'
)
}
const L1CrossDomainMessengerProxy = await getContractFromArtifact(
hre,
'Proxy__OVM_L1CrossDomainMessenger'
)
await deployAndVerifyAndThen({
hre,
......@@ -36,6 +27,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['L1ERC721BridgeImpl', 'fresh', 'migration']
deployFn.tags = ['L1ERC721BridgeImpl']
export default deployFn
......@@ -11,6 +11,7 @@ const deployFn: DeployFunction = async (hre) => {
hre,
'OptimismPortalProxy'
)
await deployAndVerifyAndThen({
hre,
name: 'PortalSender',
......@@ -25,6 +26,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['PortalSenderImpl', 'fresh', 'migration']
deployFn.tags = ['PortalSenderImpl']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import {
deployAndVerifyAndThen,
assertDictatorConfig,
makeDictatorConfig,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const config = await makeDictatorConfig(
hre,
deployer,
hre.deployConfig.finalSystemOwner,
true
)
await deployAndVerifyAndThen({
hre,
name: 'FreshSystemDictator',
args: [config],
postDeployAction: async (contract) => {
await assertDictatorConfig(contract, config)
},
})
}
deployFn.tags = ['FreshSystemDictator', 'fresh']
export default deployFn
......@@ -11,6 +11,7 @@ const deployFn: DeployFunction = async (hre) => {
hre.deployConfig.batchSenderAddress,
32
)
await deployAndVerifyAndThen({
hre,
name: 'SystemConfig',
......@@ -46,6 +47,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['SystemConfigImpl', 'fresh', 'migration']
deployFn.tags = ['SystemConfigImpl']
export default deployFn
import assert from 'assert'
import { ethers } from 'ethers'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import {
assertContractVariable,
getContractFromArtifact,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const ProxyAdmin = await getContractFromArtifact(hre, 'ProxyAdmin', {
signerOrProvider: deployer,
})
const FreshSystemDictator = await getContractFromArtifact(
hre,
'FreshSystemDictator',
{
signerOrProvider: deployer,
}
)
if ((await ProxyAdmin.owner()) !== FreshSystemDictator.address) {
console.log(`Transferring proxy admin ownership to the FreshSystemDictator`)
await ProxyAdmin.transferOwnership(FreshSystemDictator.address)
} else {
console.log(`Proxy admin already owned by the FreshSystemDictator`)
}
if ((await FreshSystemDictator.currentStep()) === 1) {
console.log(`Executing step 1`)
await FreshSystemDictator.step1()
// Check L2OutputOracle was initialized properly.
const L2OutputOracle = await getContractFromArtifact(
hre,
'L2OutputOracleProxy',
{
iface: 'L2OutputOracle',
}
)
await assertContractVariable(
L2OutputOracle,
'latestBlockNumber',
hre.deployConfig.l2OutputOracleStartingBlockNumber
)
await assertContractVariable(
L2OutputOracle,
'proposer',
hre.deployConfig.l2OutputOracleProposer
)
await assertContractVariable(
L2OutputOracle,
'owner',
hre.deployConfig.l2OutputOracleOwner
)
if (
hre.deployConfig.l2OutputOracleGenesisL2Output !==
ethers.constants.HashZero
) {
const genesisOutput = await L2OutputOracle.getL2Output(
hre.deployConfig.l2OutputOracleStartingBlockNumber
)
assert(
genesisOutput.outputRoot ===
hre.deployConfig.l2OutputOracleGenesisL2Output,
`L2OutputOracle was not initialized with the correct genesis output root`
)
}
// Check OptimismPortal was initialized properly.
const OptimismPortal = await getContractFromArtifact(
hre,
'OptimismPortalProxy',
{
iface: 'OptimismPortal',
}
)
await assertContractVariable(
OptimismPortal,
'l2Sender',
'0x000000000000000000000000000000000000dEaD'
)
const resourceParams = await OptimismPortal.params()
assert(
resourceParams.prevBaseFee.eq(await OptimismPortal.INITIAL_BASE_FEE()),
`OptimismPortal was not initialized with the correct initial base fee`
)
assert(
resourceParams.prevBoughtGas.eq(0),
`OptimismPortal was not initialized with the correct initial bought gas`
)
assert(
!resourceParams.prevBlockNum.eq(0),
`OptimismPortal was not initialized with the correct initial block number`
)
// Check L1CrossDomainMessenger was initialized properly.
const L1CrossDomainMessenger = await getContractFromArtifact(
hre,
'L1CrossDomainMessengerProxy',
{
iface: 'L1CrossDomainMessenger',
}
)
try {
await L1CrossDomainMessenger.xDomainMessageSender()
assert(false, `L1CrossDomainMessenger was not initialized properly`)
} catch (err) {
assert(
err.message.includes('xDomainMessageSender is not set'),
`L1CrossDomainMessenger was not initialized properly`
)
}
await assertContractVariable(
L1CrossDomainMessenger,
'owner',
hre.deployConfig.finalSystemOwner
)
// Check L1StandardBridge was initialized properly.
const L1StandardBridge = await getContractFromArtifact(
hre,
'L1StandardBridgeProxy',
{
iface: 'L1StandardBridge',
}
)
await assertContractVariable(
L1StandardBridge,
'messenger',
L1CrossDomainMessenger.address
)
// Check OptimismMintableERC20Factory was initialized properly.
const OptimismMintableERC20Factory = await getContractFromArtifact(
hre,
'OptimismMintableERC20FactoryProxy',
{
iface: 'OptimismMintableERC20Factory',
}
)
await assertContractVariable(
OptimismMintableERC20Factory,
'bridge',
L1StandardBridge.address
)
// Check L1ERC721Bridge was initialized properly.
const L1ERC721Bridge = await getContractFromArtifact(
hre,
'L1ERC721BridgeProxy',
{
iface: 'L1ERC721Bridge',
}
)
await assertContractVariable(
L1ERC721Bridge,
'messenger',
L1CrossDomainMessenger.address
)
} else {
console.log(`Step 1 executed`)
}
if ((await FreshSystemDictator.currentStep()) === 2) {
console.log(`Executing step 2`)
await FreshSystemDictator.step2()
// Check the ProxyAdmin owner was changed properly.
await assertContractVariable(
ProxyAdmin,
'owner',
hre.deployConfig.finalSystemOwner
)
} else {
console.log(`Step 2 executed`)
}
}
deployFn.tags = ['FreshSystemDictatorSteps', 'fresh']
export default deployFn
......@@ -73,6 +73,6 @@ const deployFn: DeployFunction = async (hre) => {
})
}
deployFn.tags = ['MigrationSystemDictator', 'migration']
deployFn.tags = ['MigrationSystemDictator']
export default deployFn
......@@ -17,9 +17,24 @@ const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
let isLiveDeployer = false
if (hre.deployConfig.controller === deployer) {
console.log('using a live deployer')
isLiveDeployer = true
let controller = hre.deployConfig.controller
if (controller === ethers.constants.AddressZero) {
if (hre.network.config.live === false) {
console.log(`WARNING!!!`)
console.log(`WARNING!!!`)
console.log(`WARNING!!!`)
console.log(`WARNING!!! A controller address was not provided.`)
console.log(
`WARNING!!! Make sure you are ONLY doing this on a test network.`
)
console.log('using a live deployer')
isLiveDeployer = true
controller = deployer
} else {
throw new Error(
`controller address MUST NOT be the deployer on live networks`
)
}
}
// Set up required contract references.
......@@ -116,6 +131,8 @@ const deployFn: DeployFunction = async (hre) => {
// Transfer ownership of the L1CrossDomainMessenger to MigrationSystemDictator.
if (
(await AddressManager.getAddress('OVM_L1CrossDomainMessenger')) !==
ethers.constants.AddressZero &&
(await L1CrossDomainMessenger.owner()) !== MigrationSystemDictator.address
) {
if (isLiveDeployer) {
......@@ -279,7 +296,7 @@ const deployFn: DeployFunction = async (hre) => {
`OptimismPortal was not initialized with the correct initial block number`
)
assert(
(await hre.ethers.provider.getBalance(OptimismPortal.address)).gt(0)
(await hre.ethers.provider.getBalance(L1StandardBridge.address)).eq(0)
)
// Check L1CrossDomainMessenger was initialized properly.
......@@ -375,6 +392,6 @@ const deployFn: DeployFunction = async (hre) => {
}
}
deployFn.tags = ['MigrationSystemDictatorSteps', 'migration']
deployFn.tags = ['MigrationSystemDictatorSteps']
export default deployFn
......@@ -12,6 +12,9 @@ import './tasks'
const config: HardhatUserConfig = {
networks: {
hardhat: {
live: false,
},
devnetL1: {
live: false,
url: 'http://localhost:8545',
......@@ -341,8 +344,14 @@ const config: HardhatUserConfig = {
],
deployments: {
goerli: ['../contracts/deployments/goerli'],
mainnet: ['../contracts/deployments/mainnet'],
'mainnet-forked': ['../contracts/deployments/mainnet'],
mainnet: [
'../contracts/deployments/mainnet',
'../contracts-periphery/deployments/mainnet',
],
'mainnet-forked': [
'../contracts/deployments/mainnet',
'../contracts-periphery/deployments/mainnet',
],
},
},
solidity: {
......
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