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: setting up contracts for the RIP-7560 #2

Merged
merged 1 commit into from
Oct 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
3 changes: 3 additions & 0 deletions op-chain-ops/genesis/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Gene
EIP1559Elasticity: eip1559Elasticity,
EIP1559DenominatorCanyon: &eip1559DenomCanyon,
},
EntryPointAddress: common.HexToAddress("0x0000000000000000000000000000000000007560"),
NonceManagerAddress: common.HexToAddress("0x4200000000000000000000000000000000000024"),
DeployerCallerAddress: common.HexToAddress("0x00000000000000000000000000000000ffff7560"),
}

gasLimit := config.L2GenesisBlockGasLimit
Expand Down
3 changes: 3 additions & 0 deletions op-service/predeploys/addresses.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
L2toL2CrossDomainMessenger = "0x4200000000000000000000000000000000000023"
SuperchainWETH = "0x4200000000000000000000000000000000000024"
ETHLiquidity = "0x4200000000000000000000000000000000000025"
NonceManager = "0x4200000000000000000000000000000000000024"
Create2Deployer = "0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2"
MultiCall3 = "0xcA11bde05977b3631167028862bE2a173976CA11"
Safe_v130 = "0x69f4D1788e39c87893C980c06EdF4b7f686e2938"
Expand Down Expand Up @@ -68,6 +69,7 @@ var (
L2toL2CrossDomainMessengerAddr = common.HexToAddress(L2toL2CrossDomainMessenger)
SuperchainWETHAddr = common.HexToAddress(SuperchainWETH)
ETHLiquidityAddr = common.HexToAddress(ETHLiquidity)
NonceManagerAddr = common.HexToAddress(NonceManager)
Create2DeployerAddr = common.HexToAddress(Create2Deployer)
MultiCall3Addr = common.HexToAddress(MultiCall3)
Safe_v130Addr = common.HexToAddress(Safe_v130)
Expand Down Expand Up @@ -116,6 +118,7 @@ func init() {
Predeploys["L1FeeVault"] = &Predeploy{Address: L1FeeVaultAddr}
Predeploys["SchemaRegistry"] = &Predeploy{Address: SchemaRegistryAddr}
Predeploys["EAS"] = &Predeploy{Address: EASAddr}
Predeploys["NonceManager"] = &Predeploy{Address: NonceManagerAddr}
Predeploys["Create2Deployer"] = &Predeploy{
Address: Create2DeployerAddr,
ProxyDisabled: true,
Expand Down
2 changes: 2 additions & 0 deletions packages/contracts-bedrock/scripts/Artifacts.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ abstract contract Artifacts {
return payable(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY);
} else if (digest == keccak256(bytes("OptimismSuperchainERC20Beacon"))) {
return payable(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON);
} else if (digest == keccak256(bytes("NonceManager"))) {
return payable(Predeploys.NONCE_MANAGER);
}
return payable(address(0));
}
Expand Down
13 changes: 11 additions & 2 deletions packages/contracts-bedrock/scripts/L2Genesis.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { OptimismSuperchainERC20Beacon } from "src/L2/OptimismSuperchainERC20Bea
import { OptimismMintableERC721Factory } from "src/universal/OptimismMintableERC721Factory.sol";
import { FeeVault } from "src/universal/FeeVault.sol";
import { GovernanceToken } from "src/governance/GovernanceToken.sol";
import { NonceManager } from "src/L2/NonceManager.sol";

// Libraries
import { Predeploys } from "src/libraries/Predeploys.sol";
Expand Down Expand Up @@ -65,7 +66,7 @@ contract L2Genesis is Deployer {
/// @notice Default Anvil dev accounts. Only funded if `cfg.fundDevAccounts == true`.
/// Also known as "test test test test test test test test test test test junk" mnemonic accounts,
/// on path "m/44'/60'/0'/0/i" (where i is the account index).
address[30] internal devAccounts = [
address[32] internal devAccounts = [
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, // 0
0x70997970C51812dc3A010C7d01b50e0d17dc79C8, // 1
0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC, // 2
Expand Down Expand Up @@ -95,7 +96,9 @@ contract L2Genesis is Deployer {
0x553BC17A05702530097c3677091C5BB47a3a7931, // 26
0x87BdCE72c06C21cd96219BD8521bDF1F42C78b5e, // 27
0x40Fc963A729c542424cD800349a7E4Ecc4896624, // 28
0x9DCCe783B6464611f38631e6C851bf441907c710 // 29
0x9DCCe783B6464611f38631e6C851bf441907c710, // 29
0x7560000000000000000000000000000000000000, // RIP-7560 BasicPaymaster
0x7560000000000000000000000000000000000001 // RIP-7560 BasicAccount
];

/// @notice The address of the deployer account.
Expand Down Expand Up @@ -273,6 +276,7 @@ contract L2Genesis is Deployer {
// 1B,1C,1D,1E,1F: not used.
setSchemaRegistry(); // 20
setEAS(); // 21
setNonceManager(); //24
setGovernanceToken(); // 42: OP (not behind a proxy)
if (cfg.useInterop()) {
setCrossL2Inbox(); // 22
Expand Down Expand Up @@ -554,6 +558,11 @@ contract L2Genesis is Deployer {
vm.etch(address(beacon), "");
vm.resetNonce(address(beacon));
}
/// @notice This predeploy is following the safety invariant #1.
function setNonceManager() public {
console.log("Setting %s implementation at: %s", "NonceManager", Predeploys.NONCE_MANAGER);
vm.etch(Predeploys.NONCE_MANAGER, vm.getDeployedCode("NonceManager.sol:NonceManager"));
}

/// @notice Sets all the preinstalls.
function setPreinstalls() public {
Expand Down
3 changes: 3 additions & 0 deletions packages/contracts-bedrock/scripts/SetPreinstalls.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ contract SetPreinstalls is Script {
_setPreinstallCode(Preinstalls.EntryPoint_v070); // ERC 4337 v0.7.0
_setPreinstallCode(Preinstalls.BeaconBlockRoots);
_setPreinstallCode(Preinstalls.CreateX);
_setPreinstallCode(Preinstalls.BasicPaymaster); // RIP 7560
_setPreinstallCode(Preinstalls.BasicAccount); // RIP 7560
_setPreinstallCode(Preinstalls.BasicAccountFactory); // RIP 7560
// 4788 sender nonce must be incremented, since it's part of later upgrade-transactions.
// For the upgrade-tx to not create a contract that conflicts with an already-existing copy,
// the nonce must be bumped.
Expand Down
75 changes: 75 additions & 0 deletions packages/contracts-bedrock/src/L2/NonceManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

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

/// @custom:predeploy 0x4200000000000000000000000000000000000024
/// @title NonceManager
/// @notice The NonceManager manages nonce of smart accounts using RIP-7560.
contract NonceManager is ISemver {
/// @notice Semantic version.
/// @custom:semver 0.1.0
string public constant version = "0.1.0";

/// @notice The EntryPoint address defined at RIP-7560.
address internal constant AA_ENTRY_POINT = 0x0000000000000000000000000000000000007560;

fallback(bytes calldata data) external returns (bytes memory) {
if (msg.sender == AA_ENTRY_POINT) {
_validateIncrement(data);
return new bytes(0);
} else {
return abi.encodePacked(_get(data));
}
}

/// @notice Return the next nonce for this sender. Within a given key, the nonce values are sequenced
/// (starting with zero, and incremented by one on each transaction).
/// But transactions with different keys can come with arbitrary order.
/// @return nonce a full nonce to pass for next transaction with given sender and key.
function _get(bytes calldata /* data */) internal view returns (uint256 nonce) {
assembly {
// Check if calldata is 44 bytes long
if iszero(eq(calldatasize(), 44)) {
mstore(0x00, 0x947d5a84) // 'InvalidLength()'
revert(0x1c, 0x04)
}

let ptr := mload(0x40)
calldatacopy(ptr, 0, 44)

// Extract key and sender from calldata
let key := shr(64, mload(add(ptr, 20)))
mstore(0x00, key)
mstore(0x14, shr(96, mload(ptr)))

// Load nonce from storage
nonce := or(shl(64, key), sload(keccak256(0x04, 0x30)))
}
}

/// @notice validate nonce uniqueness for this account. Called by AA_ENTRY_POINT.
function _validateIncrement(bytes calldata /* data */) internal {
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize())

// Store key and sender in memory
mstore(0x00, shr(64, mload(add(ptr, 20))))
mstore(0x14, shr(96, mload(ptr)))

// Calculate storage slot and load current nonce
let nonceSlot := keccak256(0x04, 0x30)
let currentNonce := sload(nonceSlot)

// Revert if nonce mismatch
if iszero(eq(shr(192, mload(add(ptr, 44))), currentNonce)) {
mstore(0, 0)
revert(0, 0) // Revert if nonce mismatch
}

// Increment nonce
sstore(nonceSlot, add(currentNonce, 1))
}
}
}
9 changes: 7 additions & 2 deletions packages/contracts-bedrock/src/libraries/Predeploys.sol
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ library Predeploys {
/// @notice Arbitrary address of the OptimismSuperchainERC20 implementation contract.
address internal constant OPTIMISM_SUPERCHAIN_ERC20 = 0xB9415c6cA93bdC545D4c5177512FCC22EFa38F28;

/// @notice Address of the NonceManager predeploy.
address internal constant NONCE_MANAGER = 0x4200000000000000000000000000000000000024;

/// @notice Returns the name of the predeploy at the given address.
function getName(address _addr) internal pure returns (string memory out_) {
require(isPredeployNamespace(_addr), "Predeploys: address must be a predeploy");
Expand Down Expand Up @@ -135,12 +138,13 @@ library Predeploys {
if (_addr == ETH_LIQUIDITY) return "ETHLiquidity";
if (_addr == OPTIMISM_SUPERCHAIN_ERC20_FACTORY) return "OptimismSuperchainERC20Factory";
if (_addr == OPTIMISM_SUPERCHAIN_ERC20_BEACON) return "OptimismSuperchainERC20Beacon";
if (_addr == NONCE_MANAGER) return "NonceManager";
revert("Predeploys: unnamed predeploy");
}

/// @notice Returns true if the predeploy is not proxied.
function notProxied(address _addr) internal pure returns (bool) {
return _addr == GOVERNANCE_TOKEN || _addr == WETH;
return _addr == GOVERNANCE_TOKEN || _addr == WETH || _addr == NONCE_MANAGER;
}

/// @notice Returns true if the address is a defined predeploy that is embedded into new OP-Stack chains.
Expand All @@ -154,7 +158,8 @@ library Predeploys {
|| (_useInterop && _addr == CROSS_L2_INBOX) || (_useInterop && _addr == L2_TO_L2_CROSS_DOMAIN_MESSENGER)
|| (_useInterop && _addr == SUPERCHAIN_WETH) || (_useInterop && _addr == ETH_LIQUIDITY)
|| (_useInterop && _addr == OPTIMISM_SUPERCHAIN_ERC20_FACTORY)
|| (_useInterop && _addr == OPTIMISM_SUPERCHAIN_ERC20_BEACON);
|| (_useInterop && _addr == OPTIMISM_SUPERCHAIN_ERC20_BEACON)
|| _addr == NONCE_MANAGER;
}

function isPredeployNamespace(address _addr) internal pure returns (bool) {
Expand Down
Loading