Commit 6b7ff0bf authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

feat: bedrock predeploys (#2580)

* contracts: update forge-std

This adds 2 new cheatcodes to the `vm` interface,
a `expectCall` that asserts on the call with a `msg.value`
set to a specific amount as well as a `mockCall` that can
send a specific amount of value as part of the mocked call.

* contracts: deploy OVM_ETH as part of setup

* contracts: deployer whitelist

* contracts: OVM_ETH

* contracts: sequencer fee vault

* contracts: weth9

* contracts: ignore linting for weth9

* contracts: gas oracle

* contracts: l1 standard bridge

* contracts: new snapshot
Co-authored-by: default avatarmergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
parent 8c7baa13
CrossDomainHashing_Test:test_l2TransactionHash() (gas: 78639)
GasPriceOracle_Test:test_baseFee() (gas: 11216)
GasPriceOracle_Test:test_gasPrice() (gas: 11205)
DeployerWhitelist_Test:test_owner() (gas: 7647)
DeployerWhitelist_Test:test_storageSlots() (gas: 33483)
GasPriceOracle_Test:test_baseFee() (gas: 8395)
GasPriceOracle_Test:test_gasPrice() (gas: 8384)
GasPriceOracle_Test:test_l1BaseFee() (gas: 10626)
GasPriceOracle_Test:test_onlyOwnerSetDecimals() (gas: 10575)
GasPriceOracle_Test:test_onlyOwnerSetOverhead() (gas: 10599)
......@@ -77,6 +79,15 @@ L2StandardBridge_Test:test_withdrawTo() (gas: 353495)
L2ToL1MessagePasserTest:test_burn() (gas: 112023)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromContract() (gas: 67890)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromEOA() (gas: 74851)
OVM_ETH_Test:test_approve() (gas: 10695)
OVM_ETH_Test:test_burn() (gas: 10609)
OVM_ETH_Test:test_crossDomain() (gas: 10599)
OVM_ETH_Test:test_decreaseAllowance() (gas: 10731)
OVM_ETH_Test:test_increaseAllowance() (gas: 10763)
OVM_ETH_Test:test_metadata() (gas: 15608)
OVM_ETH_Test:test_mint() (gas: 10621)
OVM_ETH_Test:test_transfer() (gas: 10726)
OVM_ETH_Test:test_transferFrom() (gas: 13008)
OptimismMintableTokenFactory_Test:test_bridge() (gas: 9850)
OptimismMintableTokenFactory_Test:test_burn() (gas: 52791)
OptimismMintableTokenFactory_Test:test_burnRevertsFromNotBridge() (gas: 13211)
......@@ -103,3 +114,8 @@ OptimismPortal_Test:test_depositTransaction_withEthValueAndEOAContractCreation()
OptimismPortal_Test:test_depositTransaction_withEthValueFromContract() (gas: 31210)
OptimismPortal_Test:test_depositTransaction_withEthValueFromEOA() (gas: 31781)
OptimismPortal_Test:test_invalidWithdrawalProof() (gas: 26565)
SequencerFeeVault_Test:test_constructor() (gas: 7611)
SequencerFeeVault_Test:test_minWithdrawalAmount() (gas: 5429)
SequencerFeeVault_Test:test_receive() (gas: 17280)
SequencerFeeVault_Test:test_revertWithdraw() (gas: 9245)
SequencerFeeVault_Test:test_withdraw() (gas: 147274)
......@@ -10,6 +10,8 @@ cache
typechain
coverage*
contracts/L2/WETH9.sol
# Other autogenerated files
gasReporterOutput.json
slither.db.json
......@@ -2,3 +2,4 @@
node_modules
lib
contracts/test/*.t.sol
contracts/L2/WETH9.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title OVM_DeployerWhitelist
* @dev The Deployer Whitelist is a temporary predeploy used to provide additional safety during the
* initial phases of our mainnet roll out. It is owned by the Optimism team, and defines accounts
* which are allowed to deploy contracts on Layer2. The Execution Manager will only allow an
* ovmCREATE or ovmCREATE2 operation to proceed if the deployer's address whitelisted.
*/
contract DeployerWhitelist {
/**********
* Events *
**********/
event OwnerChanged(address oldOwner, address newOwner);
event WhitelistStatusChanged(address deployer, bool whitelisted);
event WhitelistDisabled(address oldOwner);
/**********************
* Contract Constants *
**********************/
// WARNING: When owner is set to address(0), the whitelist is disabled.
address public owner;
mapping(address => bool) public whitelist;
/**********************
* Function Modifiers *
**********************/
/**
* Blocks functions to anyone except the contract owner.
*/
modifier onlyOwner() {
require(msg.sender == owner, "Function can only be called by the owner of this contract.");
_;
}
/********************
* Public Functions *
********************/
/**
* Adds or removes an address from the deployment whitelist.
* @param _deployer Address to update permissions for.
* @param _isWhitelisted Whether or not the address is whitelisted.
*/
function setWhitelistedDeployer(address _deployer, bool _isWhitelisted) external onlyOwner {
whitelist[_deployer] = _isWhitelisted;
emit WhitelistStatusChanged(_deployer, _isWhitelisted);
}
/**
* Updates the owner of this contract.
* @param _owner Address of the new owner.
*/
// slither-disable-next-line external-function
function setOwner(address _owner) public onlyOwner {
// Prevent users from setting the whitelist owner to address(0) except via
// enableArbitraryContractDeployment. If you want to burn the whitelist owner, send it to
// any other address that doesn't have a corresponding knowable private key.
require(
_owner != address(0),
"OVM_DeployerWhitelist: can only be disabled via enableArbitraryContractDeployment"
);
emit OwnerChanged(owner, _owner);
owner = _owner;
}
/**
* Permanently enables arbitrary contract deployment and deletes the owner.
*/
function enableArbitraryContractDeployment() external onlyOwner {
emit WhitelistDisabled(owner);
owner = address(0);
}
/**
* Checks whether an address is allowed to deploy contracts.
* @param _deployer Address to check.
* @return _allowed Whether or not the address can deploy contracts.
*/
function isDeployerAllowed(address _deployer) external view returns (bool) {
return (owner == address(0) || whitelist[_deployer]);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* Library Imports */
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
/* Contract Imports */
import { OptimismMintableERC20 } from "../universal/OptimismMintableERC20.sol";
/**
* @title OVM_ETH
* @dev Deprecated contract that used to hold user ETH balances
*/
contract OVM_ETH is OptimismMintableERC20 {
/***************
* Constructor *
***************/
constructor()
OptimismMintableERC20(Lib_PredeployAddresses.L2_STANDARD_BRIDGE, address(0), "Ether", "ETH")
{}
function mint(address _to, uint256 _amount) public virtual override {
revert("OVM_ETH: mint is disabled");
}
function burn(address _from, uint256 _amount) public virtual override {
revert("OVM_ETH: burn is disabled");
}
function transfer(address _recipient, uint256 _amount) public virtual override returns (bool) {
revert("OVM_ETH: transfer is disabled");
}
function approve(address _spender, uint256 _amount) public virtual override returns (bool) {
revert("OVM_ETH: approve is disabled");
}
function transferFrom(
address _sender,
address _recipient,
uint256 _amount
) public virtual override returns (bool) {
revert("OVM_ETH: transferFrom is disabled");
}
function increaseAllowance(address _spender, uint256 _addedValue)
public
virtual
override
returns (bool)
{
revert("OVM_ETH: increaseAllowance is disabled");
}
function decreaseAllowance(address _spender, uint256 _subtractedValue)
public
virtual
override
returns (bool)
{
revert("OVM_ETH: decreaseAllowance is disabled");
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* Library Imports */
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
/* Contract Imports */
import { L2StandardBridge } from "./L2StandardBridge.sol";
/**
* @title SequencerFeeVault
* @dev Simple holding contract for fees paid to the Sequencer
*/
contract SequencerFeeVault {
/*************
* Constants *
*************/
// Minimum ETH balance that can be withdrawn in a single withdrawal.
uint256 public constant MIN_WITHDRAWAL_AMOUNT = 15 ether;
/*************
* Variables *
*************/
// Address on L1 that will hold the fees once withdrawn. Dynamically
// initialized in the genesis state
address public l1FeeWallet;
/************
* Fallback *
************/
// slither-disable-next-line locked-ether
receive() external payable {}
/********************
* Public Functions *
********************/
// slither-disable-next-line external-function
function withdraw() public {
require(
address(this).balance >= MIN_WITHDRAWAL_AMOUNT,
// solhint-disable-next-line max-line-length
"OVM_SequencerFeeVault: withdrawal amount must be greater than minimum withdrawal amount"
);
uint256 balance = address(this).balance;
L2StandardBridge(payable(Lib_PredeployAddresses.L2_STANDARD_BRIDGE)).withdrawTo{
value: balance
}(Lib_PredeployAddresses.OVM_ETH, l1FeeWallet, balance, 0, bytes(""));
}
}
This diff is collapsed.
......@@ -14,13 +14,13 @@ import { L2ToL1MessagePasser } from "../L2/L2ToL1MessagePasser.sol";
import { L1CrossDomainMessenger } from "../L1/L1CrossDomainMessenger.sol";
import { L2CrossDomainMessenger } from "../L2/L2CrossDomainMessenger.sol";
import { AddressAliasHelper } from "@eth-optimism/contracts/standards/AddressAliasHelper.sol";
import { OVM_ETH } from "../L2/OVM_ETH.sol";
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { console } from "forge-std/console.sol";
contract CommonTest is Test {
address alice = address(128);
......@@ -81,8 +81,8 @@ contract L2OutputOracle_Initializer is CommonTest {
contract Messenger_Initializer is L2OutputOracle_Initializer {
OptimismPortal op;
L1CrossDomainMessenger L1Messenger;
L2CrossDomainMessenger L2Messenger;
L2ToL1MessagePasser messagePasser;
L2CrossDomainMessenger L2Messenger = L2CrossDomainMessenger(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER);
L2ToL1MessagePasser messagePasser = L2ToL1MessagePasser(payable(Lib_PredeployAddresses.L2_TO_L1_MESSAGE_PASSER));
event SentMessage(
address indexed target,
......@@ -125,16 +125,23 @@ contract Messenger_Initializer is L2OutputOracle_Initializer {
L1Messenger = new L1CrossDomainMessenger();
L1Messenger.initialize(op);
L2CrossDomainMessenger l2m = new L2CrossDomainMessenger();
vm.etch(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER, address(l2m).code);
L2Messenger = L2CrossDomainMessenger(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER);
vm.etch(
Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER,
address(new L2CrossDomainMessenger()).code
);
L2Messenger.initialize(address(L1Messenger));
// Set the L2ToL1MessagePasser at the correct address
L2ToL1MessagePasser mp = new L2ToL1MessagePasser();
vm.etch(Lib_PredeployAddresses.L2_TO_L1_MESSAGE_PASSER, address(mp).code);
messagePasser = L2ToL1MessagePasser(payable(Lib_PredeployAddresses.L2_TO_L1_MESSAGE_PASSER));
vm.etch(
Lib_PredeployAddresses.L2_TO_L1_MESSAGE_PASSER,
address(new L2ToL1MessagePasser()).code
);
vm.label(
Lib_PredeployAddresses.OVM_ETH,
"OVM_ETH"
);
vm.label(
Lib_PredeployAddresses.L2_TO_L1_MESSAGE_PASSER,
......@@ -285,6 +292,11 @@ contract Bridge_Initializer is Messenger_Initializer {
L2TokenFactory = OptimismMintableTokenFactory(Lib_PredeployAddresses.L2_STANDARD_TOKEN_FACTORY);
L2TokenFactory.initialize(Lib_PredeployAddresses.L2_STANDARD_BRIDGE);
vm.etch(
Lib_PredeployAddresses.OVM_ETH,
address(new OVM_ETH()).code
);
L1Token = new ERC20("Native L1 Token", "L1T");
// Deploy the L2 ERC20 now
......
//SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import { CommonTest } from "./CommonTest.t.sol";
import { DeployerWhitelist } from "../L2/DeployerWhitelist.sol";
contract DeployerWhitelist_Test is CommonTest {
DeployerWhitelist list;
function setUp() external {
list = new DeployerWhitelist();
}
// The owner should be address(0)
function test_owner() external {
assertEq(list.owner(), address(0));
}
// The storage slot for the owner must be the same
function test_storageSlots() external {
vm.prank(list.owner());
list.setOwner(address(1));
assertEq(
bytes32(uint256(1)),
vm.load(address(list), bytes32(uint256(0)))
);
}
}
......@@ -6,8 +6,6 @@ import { GasPriceOracle } from "../L2/GasPriceOracle.sol";
import { L1Block } from "../L2/L1Block.sol";
import { Lib_BedrockPredeployAddresses } from "../libraries/Lib_BedrockPredeployAddresses.sol";
import { console } from "forge-std/console.sol";
contract GasPriceOracle_Test is CommonTest {
event OverheadUpdated(uint256);
......@@ -89,14 +87,12 @@ contract GasPriceOracle_Test is CommonTest {
function test_gasPrice() external {
vm.fee(100);
uint256 gasPrice = gasOracle.gasPrice();
console.log(gasPrice);
assertEq(gasPrice, 100);
}
function test_baseFee() external {
vm.fee(64);
uint256 gasPrice = gasOracle.baseFee();
console.log(gasPrice);
assertEq(gasPrice, 64);
}
......
......@@ -12,8 +12,6 @@ import { AddressAliasHelper } from "@eth-optimism/contracts/standards/AddressAli
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { stdStorage, StdStorage } from "forge-std/Test.sol";
import { console } from "forge-std/console.sol";
contract L1StandardBridge_Test is Bridge_Initializer {
using stdStorage for StdStorage;
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import { CommonTest } from "./CommonTest.t.sol";
import { OVM_ETH } from "../L2/OVM_ETH.sol";
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
contract OVM_ETH_Test is CommonTest {
OVM_ETH eth;
function setUp() external {
eth = new OVM_ETH();
}
function test_metadata() external {
assertEq(eth.name(), "Ether");
assertEq(eth.symbol(), "ETH");
assertEq(eth.decimals(), 18);
}
function test_crossDomain() external {
assertEq(eth.l2Bridge(), Lib_PredeployAddresses.L2_STANDARD_BRIDGE);
assertEq(eth.l1Token(), address(0));
}
function test_transfer() external {
vm.expectRevert("OVM_ETH: transfer is disabled");
eth.transfer(alice, 100);
}
function test_approve() external {
vm.expectRevert("OVM_ETH: approve is disabled");
eth.approve(alice, 100);
}
function test_transferFrom() external {
vm.expectRevert("OVM_ETH: transferFrom is disabled");
eth.transferFrom(bob, alice, 100);
}
function test_increaseAllowance() external {
vm.expectRevert("OVM_ETH: increaseAllowance is disabled");
eth.increaseAllowance(alice, 100);
}
function test_decreaseAllowance() external {
vm.expectRevert("OVM_ETH: decreaseAllowance is disabled");
eth.decreaseAllowance(alice, 100);
}
function test_mint() external {
vm.expectRevert("OVM_ETH: mint is disabled");
eth.mint(alice, 100);
}
function test_burn() external {
vm.expectRevert("OVM_ETH: burn is disabled");
eth.burn(alice, 100);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { Bridge_Initializer } from "./CommonTest.t.sol";
import { SequencerFeeVault } from "../L2/SequencerFeeVault.sol";
import { L2StandardBridge } from "../L2/L2StandardBridge.sol";
contract SequencerFeeVault_Test is Bridge_Initializer {
SequencerFeeVault vault =
SequencerFeeVault(payable(Lib_PredeployAddresses.SEQUENCER_FEE_WALLET));
address constant recipient = address(256);
function setUp() public override {
super.setUp();
vm.etch(
Lib_PredeployAddresses.SEQUENCER_FEE_WALLET,
address(new SequencerFeeVault()).code
);
vm.store(
Lib_PredeployAddresses.SEQUENCER_FEE_WALLET,
bytes32(uint256(0)),
bytes32(uint256(uint160(recipient)))
);
}
function test_minWithdrawalAmount() external {
assertEq(
vault.MIN_WITHDRAWAL_AMOUNT(),
15 ether
);
}
function test_constructor() external {
assertEq(
vault.l1FeeWallet(),
recipient
);
}
function test_receive() external {
assertEq(
address(vault).balance,
0
);
vm.prank(alice);
address(vault).call{ value: 100 }(hex"");
assertEq(
address(vault).balance,
100
);
}
function test_revertWithdraw() external {
assert(address(vault).balance < vault.MIN_WITHDRAWAL_AMOUNT());
vm.expectRevert(
"OVM_SequencerFeeVault: withdrawal amount must be greater than minimum withdrawal amount"
);
vault.withdraw();
}
function test_withdraw() external {
vm.deal(address(vault), vault.MIN_WITHDRAWAL_AMOUNT() + 1);
vm.expectCall(
Lib_PredeployAddresses.L2_STANDARD_BRIDGE,
abi.encodeWithSelector(
L2StandardBridge.withdrawTo.selector,
Lib_PredeployAddresses.OVM_ETH,
vault.l1FeeWallet(),
address(vault).balance,
0,
bytes("")
)
);
vault.withdraw();
}
}
Subproject commit 4d36e3f7e2168c8155c641eb0f80e85cd584bd1c
Subproject commit 1680d7fb3e00b7b197a7336e7c88e838c7e6a3ec
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