Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

contracts-bedrock: Add OPSM file I/O for superchain deployments #11750

Merged
merged 5 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
mds1 marked this conversation as resolved.
Show resolved Hide resolved
Empty file.
3 changes: 2 additions & 1 deletion packages/contracts-bedrock/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ fs_permissions = [
{ access='read', path = './forge-artifacts/' },
{ access='write', path='./semver-lock.json' },
{ access='read-write', path='./.testdata/' },
{ access='read', path='./kout-deployment' }
{ access='read', path='./kout-deployment' },
{ access='read', path='./test/fixtures' },
]
libs = ["node_modules", "lib"]

Expand Down
39 changes: 22 additions & 17 deletions packages/contracts-bedrock/scripts/DeploySuperchain.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity 0.8.15;

import { Script } from "forge-std/Script.sol";
import { CommonBase } from "forge-std/Base.sol";

import { SuperchainConfig } from "src/L1/SuperchainConfig.sol";
import { ProtocolVersions, ProtocolVersion } from "src/L1/ProtocolVersions.sol";
Expand Down Expand Up @@ -57,19 +58,20 @@ import { Solarray } from "scripts/libraries/Solarray.sol";
* scripts from the existing ones that "Config" and "Artifacts" terminology.
*/

contract DeploySuperchainInput {
contract DeploySuperchainInput is CommonBase {
// The input struct contains all the input data required for the deployment.
// The fields must be in alphabetical order for vm.parseToml to work.
struct Input {
Roles roles;
bool paused;
ProtocolVersion requiredProtocolVersion;
ProtocolVersion recommendedProtocolVersion;
ProtocolVersion requiredProtocolVersion;
Roles roles;
}

struct Roles {
address proxyAdminOwner;
address protocolVersionsOwner;
address guardian;
address protocolVersionsOwner;
address proxyAdminOwner;
}

// This flag tells us if all inputs have been set. An `input()` getter method that returns all
Expand All @@ -84,10 +86,10 @@ contract DeploySuperchainInput {

// Load the input from a TOML file.
function loadInputFile(string memory _infile) public {
_infile;
Input memory parsedInput;
string memory toml = vm.readFile(_infile);
bytes memory data = vm.parseToml(toml);
Input memory parsedInput = abi.decode(data, (Input));
mslipper marked this conversation as resolved.
Show resolved Hide resolved
loadInput(parsedInput);
require(false, "DeploySuperchainInput: not implemented");
}

// Load the input from a struct.
Expand Down Expand Up @@ -153,7 +155,7 @@ contract DeploySuperchainInput {
}
}

contract DeploySuperchainOutput {
contract DeploySuperchainOutput is CommonBase {
// The output struct contains all the output data from the deployment.
struct Output {
ProxyAdmin superchainProxyAdmin;
Expand Down Expand Up @@ -182,9 +184,14 @@ contract DeploySuperchainOutput {
}

// Save the output to a TOML file.
function writeOutputFile(string memory _outfile) public pure {
_outfile;
require(false, "DeploySuperchainOutput: not implemented");
function writeOutputFile(string memory _outfile) public {
string memory key = "dso-outfile";
vm.serializeAddress(key, "proxyAdmin", address(outputs.superchainProxyAdmin));
mslipper marked this conversation as resolved.
Show resolved Hide resolved
vm.serializeAddress(key, "superchainConfigImpl", address(outputs.superchainConfigImpl));
vm.serializeAddress(key, "superchainConfigProxy", address(outputs.superchainConfigProxy));
vm.serializeAddress(key, "protocolVersionsImpl", address(outputs.protocolVersionsImpl));
string memory out = vm.serializeAddress(key, "protocolVersionsProxy", address(outputs.protocolVersionsProxy));
vm.writeToml(out, _outfile);
}

function output() public view returns (Output memory) {
Expand Down Expand Up @@ -238,7 +245,7 @@ contract DeploySuperchain is Script {
// This entrypoint is for end-users to deploy from an input file and write to an output file.
// In this usage, we don't need the input and output contract functionality, so we deploy them
// here and abstract that architectural detail away from the end user.
function run(string memory _infile) public {
function run(string memory _infile, string memory _outfile) public {
mds1 marked this conversation as resolved.
Show resolved Hide resolved
// End-user without file IO, so etch the IO helper contracts.
(DeploySuperchainInput dsi, DeploySuperchainOutput dso) = etchIOContracts();

Expand All @@ -248,10 +255,8 @@ contract DeploySuperchain is Script {
// Run the deployment script and write outputs to the DeploySuperchainOutput contract.
run(dsi, dso);

// Write the output data to a file. The file
string memory outfile = ""; // This will be derived from input file name, e.g. `foo.in.toml` -> `foo.out.toml`
dso.writeOutputFile(outfile);
require(false, "DeploySuperchain: run is not implemented");
// Write the output data to a file.
dso.writeOutputFile(_outfile);
}

// This entrypoint is for use with Solidity tests, where the input and outputs are structs.
Expand Down
96 changes: 76 additions & 20 deletions packages/contracts-bedrock/test/DeploySuperchain.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,15 @@ contract DeploySuperchainInput_Test is Test {
// parameters to e.g. avoid the zero address. Therefore we hardcode a concrete test case
// which is simpler and still sufficient.
dsi.loadInput(input);
_assertLoadInput();
}

assertTrue(dsi.inputSet(), "100");

// Compare the test input struct to the getter methods.
assertEq(input.roles.proxyAdminOwner, dsi.proxyAdminOwner(), "200");
assertEq(input.roles.protocolVersionsOwner, dsi.protocolVersionsOwner(), "300");
assertEq(input.roles.guardian, dsi.guardian(), "400");
assertEq(input.paused, dsi.paused(), "500");
assertEq(
ProtocolVersion.unwrap(input.requiredProtocolVersion),
ProtocolVersion.unwrap(dsi.requiredProtocolVersion()),
"600"
);
assertEq(
ProtocolVersion.unwrap(input.recommendedProtocolVersion),
ProtocolVersion.unwrap(dsi.recommendedProtocolVersion()),
"700"
);
function test_loadInputFile_succeeds() public {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/test/fixtures/test-deploy-superchain.toml");

// Compare the test input struct to the `input` getter method.
assertEq(keccak256(abi.encode(input)), keccak256(abi.encode(dsi.input())), "800");
dsi.loadInputFile(path);
_assertLoadInput();
mslipper marked this conversation as resolved.
Show resolved Hide resolved
}

function test_getters_whenNotSet_revert() public {
Expand All @@ -76,6 +64,29 @@ contract DeploySuperchainInput_Test is Test {
vm.expectRevert(expectedErr);
dsi.recommendedProtocolVersion();
}

function _assertLoadInput() internal {
mslipper marked this conversation as resolved.
Show resolved Hide resolved
assertTrue(dsi.inputSet(), "100");

// Compare the test input struct to the getter methods.
assertEq(input.roles.proxyAdminOwner, dsi.proxyAdminOwner(), "200");
assertEq(input.roles.protocolVersionsOwner, dsi.protocolVersionsOwner(), "300");
assertEq(input.roles.guardian, dsi.guardian(), "400");
assertEq(input.paused, dsi.paused(), "500");
assertEq(
ProtocolVersion.unwrap(input.requiredProtocolVersion),
ProtocolVersion.unwrap(dsi.requiredProtocolVersion()),
"600"
);
assertEq(
ProtocolVersion.unwrap(input.recommendedProtocolVersion),
ProtocolVersion.unwrap(dsi.recommendedProtocolVersion()),
"700"
);

// Compare the test input struct to the `input` getter method.
assertEq(keccak256(abi.encode(input)), keccak256(abi.encode(dsi.input())), "800");
}
}

contract DeploySuperchainOutput_Test is Test {
Expand Down Expand Up @@ -165,6 +176,35 @@ contract DeploySuperchainOutput_Test is Test {
vm.expectRevert(expectedErr);
dso.protocolVersionsProxy();
}

function test_writeOutputFile_succeeds() public {
DeploySuperchainOutput.Output memory output = DeploySuperchainOutput.Output({
superchainProxyAdmin: ProxyAdmin(makeAddr("superchainProxyAdmin")),
superchainConfigImpl: SuperchainConfig(makeAddr("superchainConfigImpl")),
superchainConfigProxy: SuperchainConfig(makeAddr("superchainConfigProxy")),
protocolVersionsImpl: ProtocolVersions(makeAddr("protocolVersionsImpl")),
protocolVersionsProxy: ProtocolVersions(makeAddr("protocolVersionsProxy"))
});

dso.set(dso.superchainProxyAdmin.selector, address(output.superchainProxyAdmin));
dso.set(dso.superchainConfigImpl.selector, address(output.superchainConfigImpl));
dso.set(dso.superchainConfigProxy.selector, address(output.superchainConfigProxy));
dso.set(dso.protocolVersionsImpl.selector, address(output.protocolVersionsImpl));
dso.set(dso.protocolVersionsProxy.selector, address(output.protocolVersionsProxy));

string memory root = vm.projectRoot();
string memory path = string.concat(root, "/.testdata/test-deploy-superchain-output.toml");
dso.writeOutputFile(path);
string memory data = vm.readFile(path);

// Clean up before asserting so that we don't leave any files behind.
vm.removeFile(path);

assertEq(
keccak256(abi.encode(data)),
bytes32(0x496d8cafe47414684c9ccf13231a39c825f3740e0ed19854c54e1df691591fbd)
mslipper marked this conversation as resolved.
Show resolved Hide resolved
);
}
}

contract DeploySuperchain_Test is Test {
Expand Down Expand Up @@ -193,7 +233,7 @@ contract DeploySuperchain_Test is Test {
return ProtocolVersion.unwrap(_pv);
}

function test_run_succeeds(DeploySuperchainInput.Input memory _input) public {
function test_run_memory_succeeds(DeploySuperchainInput.Input memory _input) public {
vm.assume(_input.roles.proxyAdminOwner != address(0));
vm.assume(_input.roles.protocolVersionsOwner != address(0));
vm.assume(_input.roles.guardian != address(0));
Expand Down Expand Up @@ -244,6 +284,22 @@ contract DeploySuperchain_Test is Test {
dso.checkOutput();
}

function test_run_io_succeeds() public {
string memory root = vm.projectRoot();
string memory inpath = string.concat(root, "/test/fixtures/test-deploy-superchain.toml");
string memory outpath = string.concat(root, "/.testdata/test-deploy-superchain-out.toml");

deploySuperchain.run(inpath, outpath);

string memory outdata = vm.readFile(outpath);
// Clean up before asserting so that we don't leave any files behind.
vm.removeFile(outpath);
assertEq(
keccak256(abi.encode(outdata)),
bytes32(0x08aee2fe779ae629438776065e99398edaec136e7b57da9fd8574581aa7a0b3d)
mslipper marked this conversation as resolved.
Show resolved Hide resolved
);
}

function test_run_ZeroAddressRoleInput_reverts() public {
// Snapshot the state so we can revert to the default `input` struct between assertions.
uint256 snapshotId = vm.snapshot();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
paused = false
requiredProtocolVersion = 1
recommendedProtocolVersion = 2

[roles]
proxyAdminOwner = "0x51f0348a9fA2aAbaB45E82825Fbd13d406e04497"
protocolVersionsOwner = "0xeEB4cc05dC0dE43c465f97cfc703D165418CA93A"
guardian = "0xE5DbA98c65F4B9EB0aeEBb3674fE64f88509a1eC"