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

feat: Scaffolding for DeployAuthSystem Script #11908

Merged
merged 3 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
43 changes: 43 additions & 0 deletions packages/contracts-bedrock/scripts/DeployAuthSystem.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,46 @@ contract DeployAuthSystemOutput is CommonBase {
return _safe;
}
}

contract DeployAuthSystem is Script {
function run(string memory _infile, string memory _outfile) public {
(DeployAuthSystemInput dasi, DeployAuthSystemOutput daso) = etchIOContracts();

dasi.loadInputFile(_infile);

run(dasi, daso);

daso.writeOutputFile(_outfile);
}

function run(DeployAuthSystemInput _dasi, DeployAuthSystemOutput _daso) public {
deploySafe(_dasi, _daso);
}

function deploySafe(DeployAuthSystemInput _dasi, DeployAuthSystemOutput _daso) public {
address[] memory owners = _dasi.owners();
uint256 threshold = _dasi.threshold();

// TODO: replace with a real deployment. The safe deployment logic is fairly complex, so for the purposes of
// this scaffolding PR we'll just etch the code.
address safe = makeAddr("safe");
vm.etch(safe, type(Safe).runtimeCode);
vm.store(safe, bytes32(uint256(3)), bytes32(uint256(owners.length)));
vm.store(safe, bytes32(uint256(4)), bytes32(uint256(threshold)));

_daso.set(_daso.safe.selector, safe);
}

function etchIOContracts() public returns (DeployAuthSystemInput dasi_, DeployAuthSystemOutput daso_) {
(dasi_, daso_) = getIOContracts();
vm.etch(address(dasi_), type(DeployAuthSystemInput).runtimeCode);
vm.etch(address(daso_), type(DeployAuthSystemOutput).runtimeCode);
vm.allowCheatcodes(address(dasi_));
vm.allowCheatcodes(address(daso_));
}

function getIOContracts() public view returns (DeployAuthSystemInput dasi_, DeployAuthSystemOutput daso_) {
dasi_ = DeployAuthSystemInput(DeployUtils.toIOAddress(msg.sender, "optimism.DeployAuthSystemInput"));
daso_ = DeployAuthSystemOutput(DeployUtils.toIOAddress(msg.sender, "optimism.DeployAuthSystemOutput"));
}
}
102 changes: 94 additions & 8 deletions packages/contracts-bedrock/test/DeployAuthSystem.t.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { Test } from "forge-std/Test.sol";
import { Test, stdStorage, StdStorage } from "forge-std/Test.sol";
import { stdToml } from "forge-std/StdToml.sol";
import { Solarray } from "scripts/libraries/Solarray.sol";

import { DeployAuthSystemInput, DeployAuthSystemOutput } from "scripts/DeployAuthSystem.s.sol";
import { DeployAuthSystemInput, DeployAuthSystem, DeployAuthSystemOutput } from "scripts/DeployAuthSystem.s.sol";

contract DeployAuthSystemInput_Test is Test {
DeployAuthSystemInput dasi;
Expand Down Expand Up @@ -68,13 +68,10 @@ contract DeployAuthSystemOutput_Test is Test {
function test_set_succeeds() public {
address safeAddr = makeAddr("safe");

// Ensure the address has code, since it's expected to be a contract
vm.etch(safeAddr, hex"01");

// Set the output data
daso.set(daso.safe.selector, safeAddr);

// Compare the test data to the getter method
assertEq(safeAddr, address(daso.safe()), "100");
}

Expand All @@ -95,13 +92,11 @@ contract DeployAuthSystemOutput_Test is Test {
function test_writeOutputFile_succeeds() public {
string memory root = vm.projectRoot();

// Use the expected data from the test fixture.
string memory expOutPath = string.concat(root, "/test/fixtures/test-deploy-auth-system-out.toml");
string memory expOutToml = vm.readFile(expOutPath);

address expSafe = expOutToml.readAddress(".safe");

// Etch code at each address so the code checks pass when settings values.
vm.etch(expSafe, hex"01");

daso.set(daso.safe.selector, expSafe);
Expand All @@ -110,9 +105,100 @@ contract DeployAuthSystemOutput_Test is Test {
daso.writeOutputFile(actOutPath);
string memory actOutToml = vm.readFile(actOutPath);

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

assertEq(expOutToml, actOutToml);
}
}

contract DeployAuthSystem_Test is Test {
using stdStorage for StdStorage;

DeployAuthSystem deployAuthSystem;
DeployAuthSystemInput dasi;
DeployAuthSystemOutput daso;

// Define default input variables for testing.
uint256 defaultThreshold = 5;
uint256 defaultOwnersLength = 7;
address[] defaultOwners;

function setUp() public {
deployAuthSystem = new DeployAuthSystem();
(dasi, daso) = deployAuthSystem.etchIOContracts();
for (uint256 i = 0; i < defaultOwnersLength; i++) {
defaultOwners.push(makeAddr(string.concat("owner", vm.toString(i))));
}
}

function hash(bytes32 _seed, uint256 _i) internal pure returns (bytes32) {
return keccak256(abi.encode(_seed, _i));
}

function testFuzz_run_memory_succeeds(bytes32 _seed) public {
address[] memory _owners = Solarray.addresses(
address(uint160(uint256(hash(_seed, 0)))),
address(uint160(uint256(hash(_seed, 1)))),
address(uint160(uint256(hash(_seed, 2)))),
address(uint160(uint256(hash(_seed, 3)))),
address(uint160(uint256(hash(_seed, 4)))),
address(uint160(uint256(hash(_seed, 5)))),
address(uint160(uint256(hash(_seed, 6))))
);

uint256 threshold = bound(uint256(_seed), 1, _owners.length - 1);

dasi.set(dasi.owners.selector, _owners);
dasi.set(dasi.threshold.selector, threshold);

deployAuthSystem.run(dasi, daso);

assertNotEq(address(daso.safe()), address(0), "100");
assertEq(daso.safe().getThreshold(), threshold, "200");
// TODO: the getOwners() method requires iterating over the owners linked list.
// Since we're not yet performing a proper deployment of the Safe, this call will revert.
// assertEq(daso.safe().getOwners().length, _owners.length, "300");

// Architecture assertions.
// TODO: these will become relevant as we add more contracts to the auth system, and need to test their
// relationships.

daso.checkOutput();
}

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

deployAuthSystem.run(inpath, outpath);

string memory actOutToml = vm.readFile(outpath);
string memory expOutToml = vm.readFile(string.concat(root, "/test/fixtures/test-deploy-auth-system-out.toml"));

vm.removeFile(outpath);
assertEq(expOutToml, actOutToml);
}

function test_run_NullInput_reverts() public {
dasi.set(dasi.owners.selector, defaultOwners);
dasi.set(dasi.threshold.selector, defaultThreshold);

// Zero out the owners length slot
uint256 slot = 9;
vm.store(address(dasi), bytes32(uint256(9)), bytes32(0));
vm.expectRevert("DeployAuthSystemInput: owners not set");
deployAuthSystem.run(dasi, daso);
vm.store(address(dasi), bytes32(uint256(9)), bytes32(defaultOwnersLength));

slot = zeroOutSlotForSelector(dasi.threshold.selector);
vm.expectRevert("DeployAuthSystemInput: threshold not set");
deployAuthSystem.run(dasi, daso);
vm.store(address(dasi), bytes32(slot), bytes32(defaultThreshold));
}

function zeroOutSlotForSelector(bytes4 _selector) internal returns (uint256 slot_) {
slot_ = stdstore.enable_packed_slots().target(address(dasi)).sig(_selector).find();
vm.store(address(dasi), bytes32(slot_), bytes32(0));
}
}
Loading