Skip to content

Commit

Permalink
feat(opsm): scaffold OP Stack Manager and tests (#11274)
Browse files Browse the repository at this point in the history
* init scaffolding of OPSM contract and tests

* add chainIdToBatchInboxAddress

* chore: address semgrep findings

* test: add auth spec

* update functions sig, semver lock, snapshots

* semver lock update after installing correct foundry version

* udpates based on style guide

* snapshots
  • Loading branch information
mds1 authored Jul 30, 2024
1 parent 02e0463 commit 59fbf91
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/contracts-bedrock/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
"initCodeHash": "0x14c3a582ca46ef2a6abad5590323f4de26ff4de54415c927c62e131ccbf8d9ba",
"sourceCodeHash": "0xf5fcf570721e25459fadbb37e02f9efe349e1c8afcbf1e3b5fdb09c9f612cdc0"
},
"src/L1/OPStackManager.sol": {
"initCodeHash": "0x1630942414d9711137028c48f37b6fcd7fbbedc147102e31ebcdcc03a9645c6a",
"sourceCodeHash": "0x8e9a47583c4c3d711c2b7cc5e0f86495e29d4e79c38415dd3d342e1d1aae4fb7"
},
"src/L1/OptimismPortal.sol": {
"initCodeHash": "0xfdc8cf0b0b26961f6ac493ee564761716447d263291bea4d366a7b94afe33392",
"sourceCodeHash": "0x9fe0a9001edecd2a04daada4ca9e17d66141b1c982f73653493b4703d2c675c4"
Expand Down
121 changes: 121 additions & 0 deletions packages/contracts-bedrock/snapshots/abi/OPStackManager.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
[
{
"inputs": [
{
"internalType": "uint256",
"name": "_l2ChainId",
"type": "uint256"
},
{
"internalType": "uint32",
"name": "_basefeeScalar",
"type": "uint32"
},
{
"internalType": "uint32",
"name": "_blobBasefeeScalar",
"type": "uint32"
},
{
"components": [
{
"internalType": "address",
"name": "proxyAdminOwner",
"type": "address"
},
{
"internalType": "address",
"name": "systemConfigOwner",
"type": "address"
},
{
"internalType": "address",
"name": "batcher",
"type": "address"
},
{
"internalType": "address",
"name": "unsafeBlockSigner",
"type": "address"
},
{
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"internalType": "address",
"name": "challenger",
"type": "address"
}
],
"internalType": "struct OPStackManager.Roles",
"name": "_roles",
"type": "tuple"
}
],
"name": "deploy",
"outputs": [
{
"internalType": "contract SystemConfig",
"name": "systemConfig_",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "version",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "l2ChainId",
"type": "uint256"
},
{
"indexed": true,
"internalType": "contract SystemConfig",
"name": "systemConfig",
"type": "address"
}
],
"name": "Deployed",
"type": "event"
},
{
"inputs": [
{
"internalType": "string",
"name": "reason",
"type": "string"
}
],
"name": "DeploymentFailed",
"type": "error"
},
{
"inputs": [],
"name": "InvalidChainId",
"type": "error"
},
{
"inputs": [],
"name": "NotImplemented",
"type": "error"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
67 changes: 67 additions & 0 deletions packages/contracts-bedrock/src/L1/OPStackManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { ISemver } from "src/universal/ISemver.sol";
import { SystemConfig } from "src/L1/SystemConfig.sol";

/// @custom:proxied
contract OPStackManager is ISemver {
/// @custom:semver 1.0.0-beta.1
string public constant version = "1.0.0-beta.1";

/// @notice Represents the roles that can be set when deploying a standard OP Stack chain.
struct Roles {
address proxyAdminOwner;
address systemConfigOwner;
address batcher;
address unsafeBlockSigner;
address proposer;
address challenger;
}

/// @notice Emitted when a new OP Stack chain is deployed.
/// @param l2ChainId The chain ID of the new chain.
/// @param systemConfig The address of the new chain's SystemConfig contract.
event Deployed(uint256 indexed l2ChainId, SystemConfig indexed systemConfig);

/// @notice Thrown when an invalid `l2ChainId` is provided to `deploy`.
error InvalidChainId();

/// @notice Thrown when a deployment fails.
error DeploymentFailed(string reason);

/// @notice Temporary error since the deploy method is not yet implemented.
error NotImplemented();

function deploy(
uint256 _l2ChainId,
uint32 _basefeeScalar,
uint32 _blobBasefeeScalar,
Roles calldata _roles
)
external
view // This is only here to silence the compiler warning until the function is fully implemented.
returns (SystemConfig systemConfig_)
{
if (_l2ChainId == 0 || _l2ChainId == block.chainid) revert InvalidChainId();

// Silence compiler warnings.
_roles;
_basefeeScalar;
_blobBasefeeScalar;
systemConfig_;

revert NotImplemented();
}

/// @notice Maps an L2 chain ID to an L1 batch inbox address as defined by the standard
/// configuration's convention. This convention is `versionByte || keccak256(bytes32(chainId))[:19]`,
/// where || denotes concatenation`, versionByte is 0x00, and chainId is a uint256.
/// https://specs.optimism.io/protocol/configurability.html#consensus-parameters
function chainIdToBatchInboxAddress(uint256 _l2ChainId) internal pure returns (address) {
bytes1 versionByte = 0x00;
bytes32 hashedChainId = keccak256(bytes.concat(bytes32(_l2ChainId)));
bytes19 first19Bytes = bytes19(hashedChainId);
return address(uint160(bytes20(bytes.concat(versionByte, first19Bytes))));
}
}
65 changes: 65 additions & 0 deletions packages/contracts-bedrock/test/L1/OPStackManager.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

// Testing utilities
import { Test } from "forge-std/Test.sol";

// Target contract
import { OPStackManager } from "src/L1/OPStackManager.sol";

// Exposes internal functions for testing.
contract OPStackManager_Harness is OPStackManager {
function chainIdToBatchInboxAddress_exposed(uint256 l2ChainId) public pure returns (address) {
return super.chainIdToBatchInboxAddress(l2ChainId);
}
}

// Unlike other test suites, we intentionally do not inherit from CommonTest or Setup. This is
// because OPStackManager acts as a deploy script, so we start from a clean slate here and
// work OPStackManager's deployment into the existing test setup, instead of using the existing
// test setup to deploy OPStackManager.
contract OPStackManager_Init is Test {
OPStackManager opsm;

// Default dummy parameters for the deploy function.
OPStackManager.Roles roles;
uint256 l2ChainId = 1234;
uint32 basefeeScalar = 1;
uint32 blobBasefeeScalar = 1;

function setUp() public {
opsm = new OPStackManager();
}
}

contract OPStackManager_Deploy_Test is OPStackManager_Init {
function test_deploy_l2ChainIdEqualsZero_reverts() public {
vm.expectRevert(OPStackManager.InvalidChainId.selector);
opsm.deploy(0, basefeeScalar, blobBasefeeScalar, roles);
}

function test_deploy_l2ChainIdEqualsCurrentChainId_reverts() public {
vm.expectRevert(OPStackManager.InvalidChainId.selector);
opsm.deploy(block.chainid, basefeeScalar, blobBasefeeScalar, roles);
}
}

// These tests use the harness which exposes internal functions for testing.
contract OPStackManager_InternalMethods_Test is Test {
function test_calculatesBatchInboxAddress_succeeds() public {
OPStackManager_Harness opsmHarness = new OPStackManager_Harness();

// These test vectors were calculated manually:
// 1. Compute the bytes32 encoding of the chainId: bytes32(uint256(chainId));
// 2. Hash it and manually take the first 19 bytes, and prefixed it with 0x00.
uint256 chainId = 1234;
address expected = 0x0017FA14b0d73Aa6A26D6b8720c1c84b50984f5C;
address actual = opsmHarness.chainIdToBatchInboxAddress_exposed(chainId);
vm.assertEq(expected, actual);

chainId = type(uint256).max;
expected = 0x00a9C584056064687E149968cBaB758a3376D22A;
actual = opsmHarness.chainIdToBatchInboxAddress_exposed(chainId);
vm.assertEq(expected, actual);
}
}
5 changes: 5 additions & 0 deletions packages/contracts-bedrock/test/Specs.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { OptimismPortalInterop } from "src/L1/OptimismPortalInterop.sol";
import { OptimismPortal2 } from "src/L1/OptimismPortal2.sol";
import { SystemConfig } from "src/L1/SystemConfig.sol";
import { DataAvailabilityChallenge } from "src/L1/DataAvailabilityChallenge.sol";
import { OPStackManager } from "src/L1/OPStackManager.sol";
import { ForgeArtifacts, Abi, AbiEntry } from "scripts/ForgeArtifacts.sol";

/// @title Specification_Test
Expand Down Expand Up @@ -781,6 +782,10 @@ contract Specification_Test is CommonTest {
_addSpec({ _name: "WETH98", _sel: _getSel("transferFrom(address,address,uint256)") });
_addSpec({ _name: "WETH98", _sel: _getSel("withdraw(uint256)") });

// OPStackManager
_addSpec({ _name: "OPStackManager", _sel: _getSel("version()") });
_addSpec({ _name: "OPStackManager", _sel: OPStackManager.deploy.selector });

// DeputyGuardianModule
_addSpec({
_name: "DeputyGuardianModule",
Expand Down

0 comments on commit 59fbf91

Please sign in to comment.