Commit 3b8933d3 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

contracts-bedrock: modularize config (#9475)

* contracts-bedrock: modularize config

All env var based config for the deploy scripts is centralized
into a single library called `Config`. Any `vm.env` or `vm.envOr`
calls should be added here so that it is easy to track the full
set of configuration options. Having this library makes configuration
much more self documenting for the deploy scripts.

This modularization is meant to make the migration away the old
hardhat deploy style architecture much easier. Now that we have
a canonical set of config values, we can be sure that anything
behind the abstraction is applied properly across the codebase
when it is changed.

There is a bunch of deprecated config, that will be able to
be deleted after https://github.com/ethereum-optimism/optimism/pull/9315
is merged along with some changes around where the default output
location for deploy artifacts is. Right now it is in the deployment
context directory, which the entire concept of deployment context
comes from hardhat deploy, which doesn't necessarily make sense
anymore. Right now it ends up in `deployments/<deploy-context>/.deploy`.
In the future, it will likely end up in the root of the contracts
directory by default and then an override can be provided where
the override is expected to be the absolute path to the desired
output location. This will greatly improve the devex and maintainability
of the deploy script.

* lint: fix
parent 71b9ba6d
......@@ -7,6 +7,7 @@ import { Vm } from "forge-std/Vm.sol";
import { Executables } from "scripts/Executables.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";
import { Chains } from "scripts/Chains.sol";
import { Config } from "scripts/Config.sol";
/// @notice Represents a deployment. Is serialized to JSON as a key/value
/// pair. Can be accessed from within scripts.
......@@ -49,7 +50,7 @@ abstract contract Artifacts {
vm.createDir(deploymentsDir, true);
}
deployArtifactPath = vm.envOr("DEPLOYMENT_OUTFILE", string.concat(deploymentsDir, "/.deploy"));
deployArtifactPath = Config.deployArtifactPath(deploymentsDir);
try vm.readFile(deployArtifactPath) returns (string memory) { }
catch {
vm.writeJson("{}", deployArtifactPath);
......@@ -58,12 +59,12 @@ abstract contract Artifacts {
try vm.createDir(deploymentsDir, true) { } catch (bytes memory) { }
uint256 chainId = vm.envOr("CHAIN_ID", block.chainid);
uint256 chainId = Config.chainID();
console.log("Connected to network with chainid %s", chainId);
// Load addresses from a JSON file if the CONTRACT_ADDRESSES_PATH environment variable
// is set. Great for loading addresses from `superchain-registry`.
string memory addresses = vm.envOr("CONTRACT_ADDRESSES_PATH", string(""));
string memory addresses = Config.contractAddressesPath();
if (bytes(addresses).length > 0) {
console.log("Loading addresses from %s", addresses);
_loadAddresses(addresses);
......@@ -269,12 +270,12 @@ abstract contract Artifacts {
/// An unknown context will use the chainid as the context name.
/// This is legacy code and should be removed in the future.
function _getDeploymentContext() private view returns (string memory) {
string memory context = vm.envOr("DEPLOYMENT_CONTEXT", string(""));
string memory context = Config.deploymentContext();
if (bytes(context).length > 0) {
return context;
}
uint256 chainid = vm.envOr("CHAIN_ID", block.chainid);
uint256 chainid = Config.chainID();
if (chainid == Chains.Mainnet) {
return "mainnet";
} else if (chainid == Chains.Goerli) {
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Vm } from "forge-std/Vm.sol";
/// @title Config
/// @notice Contains all env var based config. Add any new env var parsing to this file
/// to ensure that all config is in a single place.
library Config {
/// @notice Foundry cheatcode VM.
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
/// @notice Returns the path on the local filesystem where the deployment artifact is
/// written to disk after doing a deployment.
function deployArtifactPath(string memory _deploymentsDir) internal view returns (string memory _env) {
_env = vm.envOr("DEPLOYMENT_OUTFILE", string.concat(_deploymentsDir, "/.deploy"));
}
/// @notice Returns the chainid from the EVM context or the value of the CHAIN_ID env var as
/// an override.
function chainID() internal view returns (uint256 _env) {
_env = vm.envOr("CHAIN_ID", block.chainid);
}
/// @notice Returns the value of the env var CONTRACT_ADDRESSES_PATH which is a JSON key/value
/// pair of contract names and their addresses. Each key/value pair is passed to `save`
/// which then backs the `getAddress` function.
function contractAddressesPath() internal view returns (string memory _env) {
_env = vm.envOr("CONTRACT_ADDRESSES_PATH", string(""));
}
/// @notice Returns the deployment context which was only useful in the hardhat deploy style
/// of deployments. It is now DEPRECATED and will be removed in the future.
function deploymentContext() internal view returns (string memory _env) {
_env = vm.envOr("DEPLOYMENT_CONTEXT", string(""));
}
/// @notice The CREATE2 salt to be used when deploying the implementations.
function implSalt() internal view returns (string memory _env) {
_env = vm.envOr("IMPL_SALT", string("ethers phoenix"));
}
/// @notice Returns the path that the state dump file should be written to or read from
/// on the local filesystem.
function stateDumpPath(string memory _name) internal view returns (string memory _env) {
_env = vm.envOr(
"STATE_DUMP_PATH", string.concat(vm.projectRoot(), "/", _name, "-", vm.toString(block.chainid), ".json")
);
}
/// @notice Returns the name of the script used for deployment. This was useful for parsing the
/// foundry deploy artifacts to turn them into hardhat deploy style artifacts. It is now
/// DEPRECATED and will be removed in the future.
function deployScript(string memory _name) internal view returns (string memory _env) {
_env = vm.envOr("DEPLOY_SCRIPT", _name);
}
/// @notice Returns the sig of the entrypoint to the deploy script. By default, it is `run`.
/// This was useful for creating hardhat deploy style artifacts and will be removed in a future release.
function sig() internal view returns (string memory _env) {
_env = vm.envOr("SIG", string("run"));
}
/// @notice Returns the name of the file that the forge deployment artifact is written to on the local
/// filesystem. By default, it is the name of the deploy script with the suffix `-latest.json`.
/// This was useful for creating hardhat deploy style artifacts and will be removed in a future release.
function deployFile(string memory _sig) internal view returns (string memory _env) {
_env = vm.envOr("DEPLOY_FILE", string.concat(_sig, "-latest.json"));
}
/// @notice Returns the private key that is used to configure drippie.
function drippieOwnerPrivateKey() internal view returns (uint256 _env) {
_env = vm.envUint("DRIPPIE_OWNER_PRIVATE_KEY");
}
}
......@@ -40,6 +40,7 @@ import { ProtocolVersions, ProtocolVersion } from "src/L1/ProtocolVersions.sol";
import { StorageSetter } from "src/universal/StorageSetter.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";
import { Chains } from "scripts/Chains.sol";
import { Config } from "scripts/Config.sol";
import { IBigStepper } from "src/dispute/interfaces/IBigStepper.sol";
import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol";
......@@ -121,7 +122,7 @@ contract Deploy is Deployer {
/// Using this helps to reduce config across networks as the implementation
/// addresses will be the same across networks when deployed with create2.
function _implSalt() internal view returns (bytes32) {
return keccak256(bytes(vm.envOr("IMPL_SALT", string("ethers phoenix"))));
return keccak256(bytes(Config.implSalt()));
}
/// @notice Returns the proxy addresses. If a proxy is not found, it will have address(0).
......@@ -266,10 +267,7 @@ contract Deploy is Deployer {
function runWithStateDump() public {
_run();
string memory path = vm.envOr(
"STATE_DUMP_PATH", string.concat(vm.projectRoot(), "/", name(), "-", vm.toString(block.chainid), ".json")
);
vm.dumpState(path);
vm.dumpState(Config.stateDumpPath(name()));
}
/// @notice Deploy all L1 contracts and write the state diff to a file.
......
......@@ -16,6 +16,7 @@ import { CheckBalanceLow } from "src/periphery/drippie/dripchecks/CheckBalanceLo
import { CheckTrue } from "src/periphery/drippie/dripchecks/CheckTrue.sol";
import { AdminFaucetAuthModule } from "src/periphery/faucet/authmodules/AdminFaucetAuthModule.sol";
import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
import { Config } from "scripts/Config.sol";
/// @title DeployPeriphery
/// @notice Script used to deploy periphery contracts.
......@@ -250,7 +251,7 @@ contract DeployPeriphery is Deployer {
/// @notice installs drip configs that deposit funds to all OP Chain faucets. This function
/// should only be called on an L1 testnet.
function installOpChainFaucetsDrippieConfigs() public {
uint256 drippieOwnerPrivateKey = vm.envUint("DRIPPIE_OWNER_PRIVATE_KEY");
uint256 drippieOwnerPrivateKey = Config.drippieOwnerPrivateKey();
vm.startBroadcast(drippieOwnerPrivateKey);
Drippie drippie = Drippie(mustGetAddress("FaucetDrippie"));
......@@ -267,7 +268,7 @@ contract DeployPeriphery is Deployer {
/// @notice archives the previous OP Chain drip configs.
function archivePreviousOpChainFaucetsDrippieConfigs() public {
uint256 drippieOwnerPrivateKey = vm.envUint("DRIPPIE_OWNER_PRIVATE_KEY");
uint256 drippieOwnerPrivateKey = Config.drippieOwnerPrivateKey();
vm.startBroadcast(drippieOwnerPrivateKey);
Drippie drippie = Drippie(mustGetAddress("FaucetDrippie"));
......
......@@ -9,6 +9,7 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
import { IAddressManager } from "scripts/interfaces/IAddressManager.sol";
import { LibString } from "solady/utils/LibString.sol";
import { Artifacts, Deployment } from "scripts/Artifacts.s.sol";
import { Config } from "scripts/Config.sol";
/// @notice Contains information about a storage slot. Mirrors the layout of the storage
/// slot object in Forge artifacts so that we can deserialize JSON into this struct.
......@@ -44,11 +45,11 @@ abstract contract Deployer is Script, Artifacts {
function setUp() public virtual override {
Artifacts.setUp();
deployScript = vm.envOr("DEPLOY_SCRIPT", name());
deployScript = Config.deployScript(name());
string memory sig = vm.envOr("SIG", string("run"));
string memory deployFile = vm.envOr("DEPLOY_FILE", string.concat(sig, "-latest.json"));
uint256 chainId = vm.envOr("CHAIN_ID", block.chainid);
string memory sig = Config.sig();
string memory deployFile = Config.deployFile(sig);
uint256 chainId = Config.chainID();
deployPath = string.concat(
vm.projectRoot(), "/broadcast/", deployScript, ".s.sol/", vm.toString(chainId), "/", deployFile
);
......
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