Commit af357f17 authored by Blaine Malone's avatar Blaine Malone Committed by GitHub

refactor: Remove file I/O from deployment scripts (#12015)

* fix: Removing all file I/O features

* fix: comments in code.

* fix: pr comment
parent fbf69c9b
...@@ -35,13 +35,6 @@ contract DeployAuthSystemInput is CommonBase { ...@@ -35,13 +35,6 @@ contract DeployAuthSystemInput is CommonBase {
} }
} }
function loadInputFile(string memory _infile) public {
string memory toml = vm.readFile(_infile);
set(this.threshold.selector, toml.readUint(".safe.threshold"));
set(this.owners.selector, toml.readAddressArray(".safe.owners"));
}
function threshold() public view returns (uint256) { function threshold() public view returns (uint256) {
require(_threshold != 0, "DeployAuthSystemInput: threshold not set"); require(_threshold != 0, "DeployAuthSystemInput: threshold not set");
return _threshold; return _threshold;
...@@ -61,11 +54,6 @@ contract DeployAuthSystemOutput is CommonBase { ...@@ -61,11 +54,6 @@ contract DeployAuthSystemOutput is CommonBase {
else revert("DeployAuthSystemOutput: unknown selector"); else revert("DeployAuthSystemOutput: unknown selector");
} }
function writeOutputFile(string memory _outfile) public {
string memory out = vm.serializeAddress("outfile", "safe", address(this.safe()));
vm.writeToml(out, _outfile);
}
function checkOutput() public view { function checkOutput() public view {
address[] memory addrs = Solarray.addresses(address(this.safe())); address[] memory addrs = Solarray.addresses(address(this.safe()));
DeployUtils.assertValidContractAddresses(addrs); DeployUtils.assertValidContractAddresses(addrs);
...@@ -78,16 +66,6 @@ contract DeployAuthSystemOutput is CommonBase { ...@@ -78,16 +66,6 @@ contract DeployAuthSystemOutput is CommonBase {
} }
contract DeployAuthSystem is Script { 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 { function run(DeployAuthSystemInput _dasi, DeployAuthSystemOutput _daso) public {
deploySafe(_dasi, _daso); deploySafe(_dasi, _daso);
} }
......
...@@ -97,11 +97,6 @@ contract DeployImplementationsInput is BaseDeployIO { ...@@ -97,11 +97,6 @@ contract DeployImplementationsInput is BaseDeployIO {
else revert("DeployImplementationsInput: unknown selector"); else revert("DeployImplementationsInput: unknown selector");
} }
function loadInputFile(string memory _infile) public pure {
_infile;
require(false, "DeployImplementationsInput: not implemented");
}
function salt() public view returns (bytes32) { function salt() public view returns (bytes32) {
// TODO check if implementations are deployed based on code+salt and skip deploy if so. // TODO check if implementations are deployed based on code+salt and skip deploy if so.
return _salt; return _salt;
...@@ -192,11 +187,6 @@ contract DeployImplementationsOutput is BaseDeployIO { ...@@ -192,11 +187,6 @@ contract DeployImplementationsOutput is BaseDeployIO {
// forgefmt: disable-end // forgefmt: disable-end
} }
function writeOutputFile(string memory _outfile) public pure {
_outfile;
require(false, "DeployImplementationsOutput: not implemented");
}
function checkOutput(DeployImplementationsInput _dii) public { function checkOutput(DeployImplementationsInput _dii) public {
address[] memory addrs = Solarray.addresses( address[] memory addrs = Solarray.addresses(
address(this.opsmProxy()), address(this.opsmProxy()),
...@@ -441,15 +431,6 @@ contract DeployImplementationsOutput is BaseDeployIO { ...@@ -441,15 +431,6 @@ contract DeployImplementationsOutput is BaseDeployIO {
contract DeployImplementations is Script { contract DeployImplementations is Script {
// -------- Core Deployment Methods -------- // -------- Core Deployment Methods --------
function run(string memory _infile) public {
(DeployImplementationsInput dii, DeployImplementationsOutput dio) = etchIOContracts();
dii.loadInputFile(_infile);
run(dii, dio);
string memory outfile = ""; // This will be derived from input file name, e.g. `foo.in.toml` -> `foo.out.toml`
dio.writeOutputFile(outfile);
require(false, "DeployImplementations: run is not implemented");
}
function run(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public { function run(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public {
// Deploy the implementations. // Deploy the implementations.
deploySystemConfigImpl(_dii, _dio); deploySystemConfigImpl(_dii, _dio);
......
...@@ -70,11 +70,6 @@ contract DeployOPChainInput is BaseDeployIO { ...@@ -70,11 +70,6 @@ contract DeployOPChainInput is BaseDeployIO {
} }
} }
function loadInputFile(string memory _infile) public pure {
_infile;
require(false, "DeployOPChainInput: not implemented");
}
function opChainProxyAdminOwner() public view returns (address) { function opChainProxyAdminOwner() public view returns (address) {
require(_opChainProxyAdminOwner != address(0), "DeployOPChainInput: not set"); require(_opChainProxyAdminOwner != address(0), "DeployOPChainInput: not set");
return _opChainProxyAdminOwner; return _opChainProxyAdminOwner;
...@@ -167,11 +162,6 @@ contract DeployOPChainOutput is BaseDeployIO { ...@@ -167,11 +162,6 @@ contract DeployOPChainOutput is BaseDeployIO {
// forgefmt: disable-end // forgefmt: disable-end
} }
function writeOutputFile(string memory _outfile) public pure {
_outfile;
require(false, "DeployOPChainOutput: not implemented");
}
function checkOutput(DeployOPChainInput _doi) public view { function checkOutput(DeployOPChainInput _doi) public view {
// With 16 addresses, we'd get a stack too deep error if we tried to do this inline as a // With 16 addresses, we'd get a stack too deep error if we tried to do this inline as a
// single call to `Solarray.addresses`. So we split it into two calls. // single call to `Solarray.addresses`. So we split it into two calls.
...@@ -406,14 +396,6 @@ contract DeployOPChainOutput is BaseDeployIO { ...@@ -406,14 +396,6 @@ contract DeployOPChainOutput is BaseDeployIO {
contract DeployOPChain is Script { contract DeployOPChain is Script {
// -------- Core Deployment Methods -------- // -------- Core Deployment Methods --------
function run(string memory _infile) public {
(DeployOPChainInput doi, DeployOPChainOutput doo) = etchIOContracts();
doi.loadInputFile(_infile);
run(doi, doo);
string memory outfile = ""; // This will be derived from input file name, e.g. `foo.in.toml` -> `foo.out.toml`
doo.writeOutputFile(outfile);
require(false, "DeployOPChain: run is not implemented");
}
function run(DeployOPChainInput _doi, DeployOPChainOutput _doo) public { function run(DeployOPChainInput _doi, DeployOPChainOutput _doo) public {
OPStackManager opsmProxy = _doi.opsmProxy(); OPStackManager opsmProxy = _doi.opsmProxy();
......
...@@ -19,14 +19,14 @@ import { BaseDeployIO } from "scripts/utils/BaseDeployIO.sol"; ...@@ -19,14 +19,14 @@ import { BaseDeployIO } from "scripts/utils/BaseDeployIO.sol";
// deployment script. // deployment script.
// //
// There are three categories of users that are expected to interact with the scripts: // There are three categories of users that are expected to interact with the scripts:
// 1. End users that want to run live contract deployments. // 1. End users that want to run live contract deployments. These users are expected to run these scripts via
// 'op-deployer' which uses a go interface to interact with the scripts.
// 2. Solidity developers that want to use or test these scripts in a standard forge test environment. // 2. Solidity developers that want to use or test these scripts in a standard forge test environment.
// 3. Go developers that want to run the deploy scripts as part of e2e testing with other aspects of the OP Stack. // 3. Go developers that want to run the deploy scripts as part of e2e testing with other aspects of the OP Stack.
// //
// We want each user to interact with the scripts in the way that's simplest for their use case: // We want each user to interact with the scripts in the way that's simplest for their use case:
// 1. End users: TOML input files that define config, and TOML output files with all output data. // 1. Solidity developers: Direct calls to the script, with the input and output contracts configured.
// 2. Solidity developers: Direct calls to the script, with the input and output contracts configured. // 2. Go developers: The forge scripts can be executed directly in Go.
// 3. Go developers: The forge scripts can be executed directly in Go.
// //
// The following architecture is used to meet the requirements of each user. We use this file's // The following architecture is used to meet the requirements of each user. We use this file's
// `DeploySuperchain` script as an example, but it applies to other scripts as well. // `DeploySuperchain` script as an example, but it applies to other scripts as well.
...@@ -39,7 +39,7 @@ import { BaseDeployIO } from "scripts/utils/BaseDeployIO.sol"; ...@@ -39,7 +39,7 @@ import { BaseDeployIO } from "scripts/utils/BaseDeployIO.sol";
// //
// Because the core script performs calls to the input and output contracts, Go developers can // Because the core script performs calls to the input and output contracts, Go developers can
// intercept calls to these addresses (analogous to how forge intercepts calls to the `Vm` address // intercept calls to these addresses (analogous to how forge intercepts calls to the `Vm` address
// to execute cheatcodes), to avoid the need for file I/O or hardcoding the input/output values. // to execute cheatcodes), to avoid the need for hardcoding the input/output values.
// //
// Public getter methods on the input and output contracts allow individual fields to be accessed // Public getter methods on the input and output contracts allow individual fields to be accessed
// in a strong, type-safe manner (as opposed to a single struct getter where the caller may // in a strong, type-safe manner (as opposed to a single struct getter where the caller may
...@@ -110,27 +110,6 @@ contract DeploySuperchainInput is BaseDeployIO { ...@@ -110,27 +110,6 @@ contract DeploySuperchainInput is BaseDeployIO {
else revert("DeploySuperchainInput: unknown selector"); else revert("DeploySuperchainInput: unknown selector");
} }
// Load the input from a TOML file.
// When setting inputs from a TOML file, we use the setter methods instead of writing directly
// to storage. This allows us to validate each input as it is set.
function loadInputFile(string memory _infile) public {
string memory toml = vm.readFile(_infile);
// Parse and set role inputs.
set(this.guardian.selector, toml.readAddress(".roles.guardian"));
set(this.protocolVersionsOwner.selector, toml.readAddress(".roles.protocolVersionsOwner"));
set(this.proxyAdminOwner.selector, toml.readAddress(".roles.proxyAdminOwner"));
// Parse and set other inputs.
set(this.paused.selector, toml.readBool(".paused"));
uint256 recVersion = toml.readUint(".recommendedProtocolVersion");
set(this.recommendedProtocolVersion.selector, ProtocolVersion.wrap(recVersion));
uint256 reqVersion = toml.readUint(".requiredProtocolVersion");
set(this.requiredProtocolVersion.selector, ProtocolVersion.wrap(reqVersion));
}
// Each input field is exposed via it's own getter method. Using public storage variables here // Each input field is exposed via it's own getter method. Using public storage variables here
// would be less verbose, but would also be more error-prone, as it would require the caller to // would be less verbose, but would also be more error-prone, as it would require the caller to
// validate that each input is set before accessing it. With getter methods, we can automatically // validate that each input is set before accessing it. With getter methods, we can automatically
...@@ -195,21 +174,8 @@ contract DeploySuperchainOutput is BaseDeployIO { ...@@ -195,21 +174,8 @@ contract DeploySuperchainOutput is BaseDeployIO {
else revert("DeploySuperchainOutput: unknown selector"); else revert("DeploySuperchainOutput: unknown selector");
} }
// Save the output to a TOML file. // This function can be called to ensure all outputs are correct.
// We fetch the output values using external calls to the getters to verify that all outputs are // It fetches the output values using external calls to the getter methods for safety.
// set correctly before writing them to the file.
function writeOutputFile(string memory _outfile) public {
string memory key = "dso-outfile";
vm.serializeAddress(key, "superchainProxyAdmin", address(this.superchainProxyAdmin()));
vm.serializeAddress(key, "superchainConfigImpl", address(this.superchainConfigImpl()));
vm.serializeAddress(key, "superchainConfigProxy", address(this.superchainConfigProxy()));
vm.serializeAddress(key, "protocolVersionsImpl", address(this.protocolVersionsImpl()));
string memory out = vm.serializeAddress(key, "protocolVersionsProxy", address(this.protocolVersionsProxy()));
vm.writeToml(out, _outfile);
}
// This function can be called to ensure all outputs are correct. Similar to `writeOutputFile`,
// it fetches the output values using external calls to the getter methods for safety.
function checkOutput(DeploySuperchainInput _dsi) public { function checkOutput(DeploySuperchainInput _dsi) public {
address[] memory addrs = Solarray.addresses( address[] memory addrs = Solarray.addresses(
address(this.superchainProxyAdmin()), address(this.superchainProxyAdmin()),
...@@ -322,24 +288,6 @@ contract DeploySuperchainOutput is BaseDeployIO { ...@@ -322,24 +288,6 @@ contract DeploySuperchainOutput is BaseDeployIO {
contract DeploySuperchain is Script { contract DeploySuperchain is Script {
// -------- Core Deployment Methods -------- // -------- Core Deployment Methods --------
// 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, string memory _outfile) public {
// End-user without file IO, so etch the IO helper contracts.
(DeploySuperchainInput dsi, DeploySuperchainOutput dso) = etchIOContracts();
// Load the input file into the input contract.
dsi.loadInputFile(_infile);
// Run the deployment script and write outputs to the DeploySuperchainOutput contract.
run(dsi, dso);
// Write the output data to a file.
dso.writeOutputFile(_outfile);
}
// This entrypoint is useful for testing purposes, as it doesn't use any file I/O.
function run(DeploySuperchainInput _dsi, DeploySuperchainOutput _dso) public { function run(DeploySuperchainInput _dsi, DeploySuperchainOutput _dso) public {
// Notice that we do not do any explicit verification here that inputs are set. This is because // Notice that we do not do any explicit verification here that inputs are set. This is because
// the verification happens elsewhere: // the verification happens elsewhere:
...@@ -449,10 +397,8 @@ contract DeploySuperchain is Script { ...@@ -449,10 +397,8 @@ contract DeploySuperchain is Script {
// -------- Utilities -------- // -------- Utilities --------
// This etches the IO contracts into memory so that we can use them in tests. When using file IO // This etches the IO contracts into memory so that we can use them in tests.
// we don't need to call this directly, as the `DeploySuperchain.run(file, file)` entrypoint // When interacting with the script programmatically (e.g. in a Solidity test), this must be called.
// handles it. But when interacting with the script programmatically (e.g. in a Solidity test),
// this must be called.
function etchIOContracts() public returns (DeploySuperchainInput dsi_, DeploySuperchainOutput dso_) { function etchIOContracts() public returns (DeploySuperchainInput dsi_, DeploySuperchainOutput dso_) {
(dsi_, dso_) = getIOContracts(); (dsi_, dso_) = getIOContracts();
vm.etch(address(dsi_), type(DeploySuperchainInput).runtimeCode); vm.etch(address(dsi_), type(DeploySuperchainInput).runtimeCode);
......
...@@ -30,16 +30,6 @@ contract DeployAuthSystemInput_Test is Test { ...@@ -30,16 +30,6 @@ contract DeployAuthSystemInput_Test is Test {
} }
} }
function test_loadInputFile_succeeds() public {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/test/fixtures/test-deploy-auth-system-in.toml");
dasi.loadInputFile(path);
assertEq(threshold, dasi.threshold(), "100");
assertEq(owners.length, dasi.owners().length, "200");
}
function test_getters_whenNotSet_revert() public { function test_getters_whenNotSet_revert() public {
vm.expectRevert("DeployAuthSystemInput: threshold not set"); vm.expectRevert("DeployAuthSystemInput: threshold not set");
dasi.threshold(); dasi.threshold();
...@@ -88,27 +78,6 @@ contract DeployAuthSystemOutput_Test is Test { ...@@ -88,27 +78,6 @@ contract DeployAuthSystemOutput_Test is Test {
vm.expectRevert(expectedErr); vm.expectRevert(expectedErr);
daso.safe(); daso.safe();
} }
function test_writeOutputFile_succeeds() public {
string memory root = vm.projectRoot();
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");
vm.etch(expSafe, hex"01");
daso.set(daso.safe.selector, expSafe);
string memory actOutPath = string.concat(root, "/.testdata/test-deploy-auth-system-output.toml");
daso.writeOutputFile(actOutPath);
string memory actOutToml = vm.readFile(actOutPath);
vm.removeFile(actOutPath);
assertEq(expOutToml, actOutToml);
}
} }
contract DeployAuthSystem_Test is Test { contract DeployAuthSystem_Test is Test {
...@@ -166,20 +135,6 @@ contract DeployAuthSystem_Test is Test { ...@@ -166,20 +135,6 @@ contract DeployAuthSystem_Test is Test {
daso.checkOutput(); 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 { function test_run_NullInput_reverts() public {
dasi.set(dasi.owners.selector, defaultOwners); dasi.set(dasi.owners.selector, defaultOwners);
dasi.set(dasi.threshold.selector, defaultThreshold); dasi.set(dasi.threshold.selector, defaultThreshold);
......
...@@ -43,19 +43,6 @@ contract DeployImplementationsInput_Test is Test { ...@@ -43,19 +43,6 @@ contract DeployImplementationsInput_Test is Test {
dii = new DeployImplementationsInput(); dii = new DeployImplementationsInput();
} }
function test_loadInputFile_succeeds() public {
// See `test_loadInputFile_succeeds` in `DeploySuperchain.t.sol` for a reference implementation.
// This test is currently skipped because loadInputFile is not implemented.
vm.skip(true);
// Compare the test inputs to the getter methods.
// assertEq(withdrawalDelaySeconds, dii.withdrawalDelaySeconds(), "100");
// assertEq(minProposalSizeBytes, dii.minProposalSizeBytes(), "200");
// assertEq(challengePeriodSeconds, dii.challengePeriodSeconds(), "300");
// assertEq(proofMaturityDelaySeconds, dii.proofMaturityDelaySeconds(), "400");
// assertEq(disputeGameFinalityDelaySeconds, dii.disputeGameFinalityDelaySeconds(), "500");
}
function test_getters_whenNotSet_revert() public { function test_getters_whenNotSet_revert() public {
vm.expectRevert("DeployImplementationsInput: not set"); vm.expectRevert("DeployImplementationsInput: not set");
dii.withdrawalDelaySeconds(); dii.withdrawalDelaySeconds();
......
...@@ -24,28 +24,6 @@ contract DeploySuperchainInput_Test is Test { ...@@ -24,28 +24,6 @@ contract DeploySuperchainInput_Test is Test {
dsi = new DeploySuperchainInput(); dsi = new DeploySuperchainInput();
} }
function test_loadInputFile_succeeds() public {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/test/fixtures/test-deploy-superchain-in.toml");
dsi.loadInputFile(path);
assertEq(proxyAdminOwner, dsi.proxyAdminOwner(), "100");
assertEq(protocolVersionsOwner, dsi.protocolVersionsOwner(), "200");
assertEq(guardian, dsi.guardian(), "300");
assertEq(paused, dsi.paused(), "400");
assertEq(
ProtocolVersion.unwrap(requiredProtocolVersion),
ProtocolVersion.unwrap(dsi.requiredProtocolVersion()),
"500"
);
assertEq(
ProtocolVersion.unwrap(recommendedProtocolVersion),
ProtocolVersion.unwrap(dsi.recommendedProtocolVersion()),
"600"
);
}
function test_getters_whenNotSet_revert() public { function test_getters_whenNotSet_revert() public {
vm.expectRevert("DeploySuperchainInput: proxyAdminOwner not set"); vm.expectRevert("DeploySuperchainInput: proxyAdminOwner not set");
dsi.proxyAdminOwner(); dsi.proxyAdminOwner();
...@@ -139,43 +117,6 @@ contract DeploySuperchainOutput_Test is Test { ...@@ -139,43 +117,6 @@ contract DeploySuperchainOutput_Test is Test {
vm.expectRevert(expectedErr); vm.expectRevert(expectedErr);
dso.protocolVersionsProxy(); dso.protocolVersionsProxy();
} }
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-superchain-out.toml");
string memory expOutToml = vm.readFile(expOutPath);
// Parse each field of expOutToml individually.
ProxyAdmin expSuperchainProxyAdmin = ProxyAdmin(expOutToml.readAddress(".superchainProxyAdmin"));
SuperchainConfig expSuperchainConfigImpl = SuperchainConfig(expOutToml.readAddress(".superchainConfigImpl"));
SuperchainConfig expSuperchainConfigProxy = SuperchainConfig(expOutToml.readAddress(".superchainConfigProxy"));
ProtocolVersions expProtocolVersionsImpl = ProtocolVersions(expOutToml.readAddress(".protocolVersionsImpl"));
ProtocolVersions expProtocolVersionsProxy = ProtocolVersions(expOutToml.readAddress(".protocolVersionsProxy"));
// Etch code at each address so the code checks pass when settings values.
vm.etch(address(expSuperchainConfigImpl), hex"01");
vm.etch(address(expSuperchainConfigProxy), hex"01");
vm.etch(address(expProtocolVersionsImpl), hex"01");
vm.etch(address(expProtocolVersionsProxy), hex"01");
dso.set(dso.superchainProxyAdmin.selector, address(expSuperchainProxyAdmin));
dso.set(dso.superchainProxyAdmin.selector, address(expSuperchainProxyAdmin));
dso.set(dso.superchainConfigImpl.selector, address(expSuperchainConfigImpl));
dso.set(dso.superchainConfigProxy.selector, address(expSuperchainConfigProxy));
dso.set(dso.protocolVersionsImpl.selector, address(expProtocolVersionsImpl));
dso.set(dso.protocolVersionsProxy.selector, address(expProtocolVersionsProxy));
string memory actOutPath = string.concat(root, "/.testdata/test-deploy-superchain-output.toml");
dso.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 DeploySuperchain_Test is Test { contract DeploySuperchain_Test is Test {
...@@ -253,21 +194,6 @@ contract DeploySuperchain_Test is Test { ...@@ -253,21 +194,6 @@ contract DeploySuperchain_Test is Test {
dso.checkOutput(dsi); dso.checkOutput(dsi);
} }
function test_run_io_succeeds() public {
string memory root = vm.projectRoot();
string memory inpath = string.concat(root, "/test/fixtures/test-deploy-superchain-in.toml");
string memory outpath = string.concat(root, "/.testdata/test-deploy-superchain-out.toml");
deploySuperchain.run(inpath, outpath);
string memory actOutToml = vm.readFile(outpath);
string memory expOutToml = vm.readFile(string.concat(root, "/test/fixtures/test-deploy-superchain-out.toml"));
// Clean up before asserting so that we don't leave any files behind.
vm.removeFile(outpath);
assertEq(expOutToml, actOutToml);
}
function test_run_NullInput_reverts() public { function test_run_NullInput_reverts() public {
// Set default values for all inputs. // Set default values for all inputs.
dsi.set(dsi.proxyAdminOwner.selector, defaultProxyAdminOwner); dsi.set(dsi.proxyAdminOwner.selector, defaultProxyAdminOwner);
......
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