Commit 5d38cf25 authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #6096 from ethereum-optimism/refcell/first/stylestack

fix(ctb): Triple Slash Natspec Port
parents 07b0dc29 92b5bae6
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -6,42 +6,32 @@ import { OptimismPortal } from "./OptimismPortal.sol"; ...@@ -6,42 +6,32 @@ import { OptimismPortal } from "./OptimismPortal.sol";
import { CrossDomainMessenger } from "../universal/CrossDomainMessenger.sol"; import { CrossDomainMessenger } from "../universal/CrossDomainMessenger.sol";
import { Semver } from "../universal/Semver.sol"; import { Semver } from "../universal/Semver.sol";
/** /// @custom:proxied
* @custom:proxied /// @title L1CrossDomainMessenger
* @title L1CrossDomainMessenger /// @notice The L1CrossDomainMessenger is a message passing interface between L1 and L2 responsible
* @notice The L1CrossDomainMessenger is a message passing interface between L1 and L2 responsible /// for sending and receiving data on the L1 side. Users are encouraged to use this
* for sending and receiving data on the L1 side. Users are encouraged to use this /// interface instead of interacting with lower-level contracts directly.
* interface instead of interacting with lower-level contracts directly.
*/
contract L1CrossDomainMessenger is CrossDomainMessenger, Semver { contract L1CrossDomainMessenger is CrossDomainMessenger, Semver {
/** /// @notice Address of the OptimismPortal.
* @notice Address of the OptimismPortal.
*/
OptimismPortal public immutable PORTAL; OptimismPortal public immutable PORTAL;
/** /// @custom:semver 1.4.1
* @custom:semver 1.4.0 /// @notice Constructs the L1CrossDomainMessenger contract.
* /// @param _portal Address of the OptimismPortal contract on this network.
* @param _portal Address of the OptimismPortal contract on this network.
*/
constructor(OptimismPortal _portal) constructor(OptimismPortal _portal)
Semver(1, 4, 0) Semver(1, 4, 1)
CrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER) CrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER)
{ {
PORTAL = _portal; PORTAL = _portal;
initialize(); initialize();
} }
/** /// @notice Initializes the contract.
* @notice Initializer.
*/
function initialize() public initializer { function initialize() public initializer {
__CrossDomainMessenger_init(); __CrossDomainMessenger_init();
} }
/** /// @inheritdoc CrossDomainMessenger
* @inheritdoc CrossDomainMessenger
*/
function _sendMessage( function _sendMessage(
address _to, address _to,
uint64 _gasLimit, uint64 _gasLimit,
...@@ -51,16 +41,12 @@ contract L1CrossDomainMessenger is CrossDomainMessenger, Semver { ...@@ -51,16 +41,12 @@ contract L1CrossDomainMessenger is CrossDomainMessenger, Semver {
PORTAL.depositTransaction{ value: _value }(_to, _value, _gasLimit, false, _data); PORTAL.depositTransaction{ value: _value }(_to, _value, _gasLimit, false, _data);
} }
/** /// @inheritdoc CrossDomainMessenger
* @inheritdoc CrossDomainMessenger
*/
function _isOtherMessenger() internal view override returns (bool) { function _isOtherMessenger() internal view override returns (bool) {
return msg.sender == address(PORTAL) && PORTAL.l2Sender() == OTHER_MESSENGER; return msg.sender == address(PORTAL) && PORTAL.l2Sender() == OTHER_MESSENGER;
} }
/** /// @inheritdoc CrossDomainMessenger
* @inheritdoc CrossDomainMessenger
*/
function _isUnsafeTarget(address _target) internal view override returns (bool) { function _isUnsafeTarget(address _target) internal view override returns (bool) {
return _target == address(this) || _target == address(PORTAL); return _target == address(this) || _target == address(PORTAL);
} }
......
...@@ -6,43 +6,34 @@ import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; ...@@ -6,43 +6,34 @@ import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { L2ERC721Bridge } from "../L2/L2ERC721Bridge.sol"; import { L2ERC721Bridge } from "../L2/L2ERC721Bridge.sol";
import { Semver } from "../universal/Semver.sol"; import { Semver } from "../universal/Semver.sol";
/** /// @title L1ERC721Bridge
* @title L1ERC721Bridge /// @notice The L1 ERC721 bridge is a contract which works together with the L2 ERC721 bridge to
* @notice The L1 ERC721 bridge is a contract which works together with the L2 ERC721 bridge to /// make it possible to transfer ERC721 tokens from Ethereum to Optimism. This contract
* make it possible to transfer ERC721 tokens from Ethereum to Optimism. This contract /// acts as an escrow for ERC721 tokens deposited into L2.
* acts as an escrow for ERC721 tokens deposited into L2.
*/
contract L1ERC721Bridge is ERC721Bridge, Semver { contract L1ERC721Bridge is ERC721Bridge, Semver {
/** /// @notice Mapping of L1 token to L2 token to ID to boolean, indicating if the given L1 token
* @notice Mapping of L1 token to L2 token to ID to boolean, indicating if the given L1 token /// by ID was deposited for a given L2 token.
* by ID was deposited for a given L2 token.
*/
mapping(address => mapping(address => mapping(uint256 => bool))) public deposits; mapping(address => mapping(address => mapping(uint256 => bool))) public deposits;
/** /// @custom:semver 1.1.2
* @custom:semver 1.1.1 /// @notice Constructs the L1ERC721Bridge contract.
* /// @param _messenger Address of the CrossDomainMessenger on this network.
* @param _messenger Address of the CrossDomainMessenger on this network. /// @param _otherBridge Address of the ERC721 bridge on the other network.
* @param _otherBridge Address of the ERC721 bridge on the other network.
*/
constructor(address _messenger, address _otherBridge) constructor(address _messenger, address _otherBridge)
Semver(1, 1, 1) Semver(1, 1, 2)
ERC721Bridge(_messenger, _otherBridge) ERC721Bridge(_messenger, _otherBridge)
{} {}
/** /// @notice Completes an ERC721 bridge from the other domain and sends the ERC721 token to the
* @notice Completes an ERC721 bridge from the other domain and sends the ERC721 token to the /// recipient on this domain.
* recipient on this domain. /// @param _localToken Address of the ERC721 token on this domain.
* /// @param _remoteToken Address of the ERC721 token on the other domain.
* @param _localToken Address of the ERC721 token on this domain. /// @param _from Address that triggered the bridge on the other domain.
* @param _remoteToken Address of the ERC721 token on the other domain. /// @param _to Address to receive the token on this domain.
* @param _from Address that triggered the bridge on the other domain. /// @param _tokenId ID of the token being deposited.
* @param _to Address to receive the token on this domain. /// @param _extraData Optional data to forward to L2.
* @param _tokenId ID of the token being deposited. /// Data supplied here will not be used to execute any code on L2 and is
* @param _extraData Optional data to forward to L2. Data supplied here will not be used to /// only emitted as extra data for the convenience of off-chain tooling.
* execute any code on L2 and is only emitted as extra data for the
* convenience of off-chain tooling.
*/
function finalizeBridgeERC721( function finalizeBridgeERC721(
address _localToken, address _localToken,
address _remoteToken, address _remoteToken,
...@@ -71,9 +62,7 @@ contract L1ERC721Bridge is ERC721Bridge, Semver { ...@@ -71,9 +62,7 @@ contract L1ERC721Bridge is ERC721Bridge, Semver {
emit ERC721BridgeFinalized(_localToken, _remoteToken, _from, _to, _tokenId, _extraData); emit ERC721BridgeFinalized(_localToken, _remoteToken, _from, _to, _tokenId, _extraData);
} }
/** /// @inheritdoc ERC721Bridge
* @inheritdoc ERC721Bridge
*/
function _initiateBridgeERC721( function _initiateBridgeERC721(
address _localToken, address _localToken,
address _remoteToken, address _remoteToken,
......
...@@ -6,48 +6,40 @@ import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; ...@@ -6,48 +6,40 @@ import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { Burn } from "../libraries/Burn.sol"; import { Burn } from "../libraries/Burn.sol";
import { Arithmetic } from "../libraries/Arithmetic.sol"; import { Arithmetic } from "../libraries/Arithmetic.sol";
/** /// @custom:upgradeable
* @custom:upgradeable /// @title ResourceMetering
* @title ResourceMetering /// @notice ResourceMetering implements an EIP-1559 style resource metering system where pricing
* @notice ResourceMetering implements an EIP-1559 style resource metering system where pricing /// updates automatically based on current demand.
* updates automatically based on current demand.
*/
abstract contract ResourceMetering is Initializable { abstract contract ResourceMetering is Initializable {
/** /// @notice Represents the various parameters that control the way in which resources are
* @notice Represents the various parameters that control the way in which resources are /// metered. Corresponds to the EIP-1559 resource metering system.
* metered. Corresponds to the EIP-1559 resource metering system. /// @custom:field prevBaseFee Base fee from the previous block(s).
* /// @custom:field prevBoughtGas Amount of gas bought so far in the current block.
* @custom:field prevBaseFee Base fee from the previous block(s). /// @custom:field prevBlockNum Last block number that the base fee was updated.
* @custom:field prevBoughtGas Amount of gas bought so far in the current block.
* @custom:field prevBlockNum Last block number that the base fee was updated.
*/
struct ResourceParams { struct ResourceParams {
uint128 prevBaseFee; uint128 prevBaseFee;
uint64 prevBoughtGas; uint64 prevBoughtGas;
uint64 prevBlockNum; uint64 prevBlockNum;
} }
/** /// @notice Represents the configuration for the EIP-1559 based curve for the deposit gas
* @notice Represents the configuration for the EIP-1559 based curve for the deposit gas /// market. These values should be set with care as it is possible to set them in
* market. These values should be set with care as it is possible to set them in /// a way that breaks the deposit gas market. The target resource limit is defined as
* a way that breaks the deposit gas market. The target resource limit is defined as /// maxResourceLimit / elasticityMultiplier. This struct was designed to fit within a
* maxResourceLimit / elasticityMultiplier. This struct was designed to fit within a /// single word. There is additional space for additions in the future.
* single word. There is additional space for additions in the future. /// @custom:field maxResourceLimit Represents the maximum amount of deposit gas that
* /// can be purchased per block.
* @custom:field maxResourceLimit Represents the maximum amount of deposit gas that /// @custom:field elasticityMultiplier Determines the target resource limit along with
* can be purchased per block. /// the resource limit.
* @custom:field elasticityMultiplier Determines the target resource limit along with /// @custom:field baseFeeMaxChangeDenominator Determines max change on fee per block.
* the resource limit. /// @custom:field minimumBaseFee The min deposit base fee, it is clamped to this
* @custom:field baseFeeMaxChangeDenominator Determines max change on fee per block. /// value.
* @custom:field minimumBaseFee The min deposit base fee, it is clamped to this /// @custom:field systemTxMaxGas The amount of gas supplied to the system
* value. /// transaction. This should be set to the same
* @custom:field systemTxMaxGas The amount of gas supplied to the system /// number that the op-node sets as the gas limit
* transaction. This should be set to the same number /// for the system transaction.
* that the op-node sets as the gas limit for the /// @custom:field maximumBaseFee The max deposit base fee, it is clamped to this
* system transaction. /// value.
* @custom:field maximumBaseFee The max deposit base fee, it is clamped to this
* value.
*/
struct ResourceConfig { struct ResourceConfig {
uint32 maxResourceLimit; uint32 maxResourceLimit;
uint8 elasticityMultiplier; uint8 elasticityMultiplier;
...@@ -57,21 +49,14 @@ abstract contract ResourceMetering is Initializable { ...@@ -57,21 +49,14 @@ abstract contract ResourceMetering is Initializable {
uint128 maximumBaseFee; uint128 maximumBaseFee;
} }
/** /// @notice EIP-1559 style gas parameters.
* @notice EIP-1559 style gas parameters.
*/
ResourceParams public params; ResourceParams public params;
/** /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades.
* @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades.
*/
uint256[48] private __gap; uint256[48] private __gap;
/** /// @notice Meters access to a function based an amount of a requested resource.
* @notice Meters access to a function based an amount of a requested resource. /// @param _amount Amount of the resource requested.
*
* @param _amount Amount of the resource requested.
*/
modifier metered(uint64 _amount) { modifier metered(uint64 _amount) {
// Record initial gas amount so we can refund for it later. // Record initial gas amount so we can refund for it later.
uint256 initialGas = gasleft(); uint256 initialGas = gasleft();
...@@ -83,12 +68,9 @@ abstract contract ResourceMetering is Initializable { ...@@ -83,12 +68,9 @@ abstract contract ResourceMetering is Initializable {
_metered(_amount, initialGas); _metered(_amount, initialGas);
} }
/** /// @notice An internal function that holds all of the logic for metering a resource.
* @notice An internal function that holds all of the logic for metering a resource. /// @param _amount Amount of the resource requested.
* /// @param _initialGas The amount of gas before any modifier execution.
* @param _amount Amount of the resource requested.
* @param _initialGas The amount of gas before any modifier execution.
*/
function _metered(uint64 _amount, uint256 _initialGas) internal { function _metered(uint64 _amount, uint256 _initialGas) internal {
// Update block number and base fee if necessary. // Update block number and base fee if necessary.
uint256 blockDiff = block.number - params.prevBlockNum; uint256 blockDiff = block.number - params.prevBlockNum;
...@@ -163,18 +145,14 @@ abstract contract ResourceMetering is Initializable { ...@@ -163,18 +145,14 @@ abstract contract ResourceMetering is Initializable {
} }
} }
/** /// @notice Virtual function that returns the resource config.
* @notice Virtual function that returns the resource config. Contracts that inherit this /// Contracts that inherit this contract must implement this function.
* contract must implement this function. /// @return ResourceConfig
*
* @return ResourceConfig
*/
function _resourceConfig() internal virtual returns (ResourceConfig memory); function _resourceConfig() internal virtual returns (ResourceConfig memory);
/** /// @notice Sets initial resource parameter values.
* @notice Sets initial resource parameter values. This function must either be called by the /// This function must either be called by the initializer function of an upgradeable
* initializer function of an upgradeable child contract. /// child contract.
*/
// solhint-disable-next-line func-name-mixedcase // solhint-disable-next-line func-name-mixedcase
function __ResourceMetering_init() internal onlyInitializing { function __ResourceMetering_init() internal onlyInitializing {
params = ResourceParams({ params = ResourceParams({
......
...@@ -124,6 +124,26 @@ contract L2OutputOracle_Initializer is CommonTest { ...@@ -124,6 +124,26 @@ contract L2OutputOracle_Initializer is CommonTest {
vm.warp(oracle.computeL2Timestamp(_nextBlockNumber) + 1); vm.warp(oracle.computeL2Timestamp(_nextBlockNumber) + 1);
} }
/// @dev Helper function to propose an output.
function proposeAnotherOutput() public {
bytes32 proposedOutput2 = keccak256(abi.encode());
uint256 nextBlockNumber = oracle.nextBlockNumber();
uint256 nextOutputIndex = oracle.nextOutputIndex();
warpToProposeTime(nextBlockNumber);
uint256 proposedNumber = oracle.latestBlockNumber();
// Ensure the submissionInterval is enforced
assertEq(nextBlockNumber, proposedNumber + submissionInterval);
vm.roll(nextBlockNumber + 1);
vm.expectEmit(true, true, true, true);
emit OutputProposed(proposedOutput2, nextOutputIndex, nextBlockNumber, block.timestamp);
vm.prank(proposer);
oracle.proposeL2Output(proposedOutput2, nextBlockNumber, 0, 0);
}
function setUp() public virtual override { function setUp() public virtual override {
super.setUp(); super.setUp();
guardian = makeAddr("guardian"); guardian = makeAddr("guardian");
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
/* Testing utilities */ // Testing utilities
import { Messenger_Initializer, Reverter, ConfigurableCaller } from "./CommonTest.t.sol"; import { Messenger_Initializer, Reverter, ConfigurableCaller } from "./CommonTest.t.sol";
import { L2OutputOracle_Initializer } from "./L2OutputOracle.t.sol"; import { L2OutputOracle_Initializer } from "./L2OutputOracle.t.sol";
/* Libraries */ // Libraries
import { AddressAliasHelper } from "../vendor/AddressAliasHelper.sol"; import { AddressAliasHelper } from "../vendor/AddressAliasHelper.sol";
import { Predeploys } from "../libraries/Predeploys.sol"; import { Predeploys } from "../libraries/Predeploys.sol";
import { Hashing } from "../libraries/Hashing.sol"; import { Hashing } from "../libraries/Hashing.sol";
import { Encoding } from "../libraries/Encoding.sol"; import { Encoding } from "../libraries/Encoding.sol";
/* Target contract dependencies */ // Target contract dependencies
import { L2OutputOracle } from "../L1/L2OutputOracle.sol"; import { L2OutputOracle } from "../L1/L2OutputOracle.sol";
import { OptimismPortal } from "../L1/OptimismPortal.sol"; import { OptimismPortal } from "../L1/OptimismPortal.sol";
/* Target contract */ // Target contract
import { L1CrossDomainMessenger } from "../L1/L1CrossDomainMessenger.sol"; import { L1CrossDomainMessenger } from "../L1/L1CrossDomainMessenger.sol";
contract L1CrossDomainMessenger_Test is Messenger_Initializer { contract L1CrossDomainMessenger_Test is Messenger_Initializer {
// Receiver address for testing /// @dev The receiver address
address recipient = address(0xabbaacdc); address recipient = address(0xabbaacdc);
// Storage slot of the l2Sender /// @dev The storage slot of the l2Sender
uint256 constant senderSlotIndex = 50; uint256 constant senderSlotIndex = 50;
// the version is encoded in the nonce /// @dev Tests that the version can be decoded from the message nonce.
function test_messageVersion_succeeds() external { function test_messageVersion_succeeds() external {
(, uint16 version) = Encoding.decodeVersionedNonce(L1Messenger.messageNonce()); (, uint16 version) = Encoding.decodeVersionedNonce(L1Messenger.messageNonce());
assertEq(version, L1Messenger.MESSAGE_VERSION()); assertEq(version, L1Messenger.MESSAGE_VERSION());
} }
// sendMessage: should be able to send a single message /// @dev Tests that the sendMessage function is able to send a single message.
// TODO: this same test needs to be done with the legacy message type /// TODO: this same test needs to be done with the legacy message type
// by setting the message version to 0 /// by setting the message version to 0
function test_sendMessage_succeeds() external { function test_sendMessage_succeeds() external {
// deposit transaction on the optimism portal should be called // deposit transaction on the optimism portal should be called
vm.expectCall( vm.expectCall(
...@@ -86,7 +86,8 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { ...@@ -86,7 +86,8 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
L1Messenger.sendMessage(recipient, hex"ff", uint32(100)); L1Messenger.sendMessage(recipient, hex"ff", uint32(100));
} }
// sendMessage: should be able to send the same message twice /// @dev Tests that the sendMessage function is able to send
/// the same message twice.
function test_sendMessage_twice_succeeds() external { function test_sendMessage_twice_succeeds() external {
uint256 nonce = L1Messenger.messageNonce(); uint256 nonce = L1Messenger.messageNonce();
L1Messenger.sendMessage(recipient, hex"aa", uint32(500_000)); L1Messenger.sendMessage(recipient, hex"aa", uint32(500_000));
...@@ -95,11 +96,14 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { ...@@ -95,11 +96,14 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
assertEq(nonce + 2, L1Messenger.messageNonce()); assertEq(nonce + 2, L1Messenger.messageNonce());
} }
/// @dev Tests that the xDomainMessageSender reverts when not set.
function test_xDomainSender_notSet_reverts() external { function test_xDomainSender_notSet_reverts() external {
vm.expectRevert("CrossDomainMessenger: xDomainMessageSender is not set"); vm.expectRevert("CrossDomainMessenger: xDomainMessageSender is not set");
L1Messenger.xDomainMessageSender(); L1Messenger.xDomainMessageSender();
} }
/// @dev Tests that the relayMessage function reverts when
/// the message version is not 0 or 1.
function test_relayMessage_v2_reverts() external { function test_relayMessage_v2_reverts() external {
address target = address(0xabcd); address target = address(0xabcd);
address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER;
...@@ -124,7 +128,8 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { ...@@ -124,7 +128,8 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
); );
} }
// relayMessage: should send a successful call to the target contract /// @dev Tests that the relayMessage function is able to relay a message
/// successfully by calling the target contract.
function test_relayMessage_succeeds() external { function test_relayMessage_succeeds() external {
address target = address(0xabcd); address target = address(0xabcd);
address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER;
...@@ -163,7 +168,8 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { ...@@ -163,7 +168,8 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
assertEq(L1Messenger.failedMessages(hash), false); assertEq(L1Messenger.failedMessages(hash), false);
} }
// relayMessage: should revert if attempting to relay a message sent to an L1 system contract /// @dev Tests that relayMessage reverts if attempting to relay a message
/// sent to an L1 system contract.
function test_relayMessage_toSystemContract_reverts() external { function test_relayMessage_toSystemContract_reverts() external {
// set the target to be the OptimismPortal // set the target to be the OptimismPortal
address target = address(op); address target = address(op);
...@@ -193,7 +199,8 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { ...@@ -193,7 +199,8 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
); );
} }
// relayMessage: should revert if eth is sent from a contract other than the standard bridge /// @dev Tests that the relayMessage function reverts if eth is
/// sent from a contract other than the standard bridge.
function test_replayMessage_withValue_reverts() external { function test_replayMessage_withValue_reverts() external {
address target = address(0xabcd); address target = address(0xabcd);
address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER;
...@@ -212,7 +219,8 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { ...@@ -212,7 +219,8 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
); );
} }
// relayMessage: the xDomainMessageSender is reset to the original value /// @dev Tests that the xDomainMessageSender is reset to the original value
/// after a message is relayed.
function test_xDomainMessageSender_reset_succeeds() external { function test_xDomainMessageSender_reset_succeeds() external {
vm.expectRevert("CrossDomainMessenger: xDomainMessageSender is not set"); vm.expectRevert("CrossDomainMessenger: xDomainMessageSender is not set");
L1Messenger.xDomainMessageSender(); L1Messenger.xDomainMessageSender();
...@@ -234,8 +242,9 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { ...@@ -234,8 +242,9 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
L1Messenger.xDomainMessageSender(); L1Messenger.xDomainMessageSender();
} }
// relayMessage: should send a successful call to the target contract after the first message /// @dev Tests that relayMessage should successfully call the target contract after
// fails and ETH gets stuck, but the second message succeeds /// the first message fails and ETH is stuck, but the second message succeeds
/// with a version 1 message.
function test_relayMessage_retryAfterFailure_succeeds() external { function test_relayMessage_retryAfterFailure_succeeds() external {
address target = address(0xabcd); address target = address(0xabcd);
address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER;
...@@ -291,6 +300,9 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { ...@@ -291,6 +300,9 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
assertEq(L1Messenger.failedMessages(hash), true); assertEq(L1Messenger.failedMessages(hash), true);
} }
/// @dev Tests that relayMessage should successfully call the target contract after
/// the first message fails and ETH is stuck, but the second message succeeds
/// with a legacy message.
function test_relayMessage_legacy_succeeds() external { function test_relayMessage_legacy_succeeds() external {
address target = address(0xabcd); address target = address(0xabcd);
address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER;
...@@ -332,6 +344,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { ...@@ -332,6 +344,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
assertEq(L1Messenger.failedMessages(hash), false); assertEq(L1Messenger.failedMessages(hash), false);
} }
/// @dev Tests that relayMessage should revert if the message is already replayed.
function test_relayMessage_legacyOldReplay_reverts() external { function test_relayMessage_legacyOldReplay_reverts() external {
address target = address(0xabcd); address target = address(0xabcd);
address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER;
...@@ -375,6 +388,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { ...@@ -375,6 +388,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
assertEq(L1Messenger.failedMessages(hash), false); assertEq(L1Messenger.failedMessages(hash), false);
} }
/// @dev Tests that relayMessage can be retried after a failure with a legacy message.
function test_relayMessage_legacyRetryAfterFailure_succeeds() external { function test_relayMessage_legacyRetryAfterFailure_succeeds() external {
address target = address(0xabcd); address target = address(0xabcd);
address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER;
...@@ -450,6 +464,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { ...@@ -450,6 +464,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
assertEq(L1Messenger.failedMessages(hash), true); assertEq(L1Messenger.failedMessages(hash), true);
} }
/// @dev Tests that relayMessage cannot be retried after success with a legacy message.
function test_relayMessage_legacyRetryAfterSuccess_reverts() external { function test_relayMessage_legacyRetryAfterSuccess_reverts() external {
address target = address(0xabcd); address target = address(0xabcd);
address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER;
...@@ -509,6 +524,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { ...@@ -509,6 +524,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer {
); );
} }
/// @dev Tests that relayMessage cannot be called after a failure and a successful replay.
function test_relayMessage_legacyRetryAfterFailureThenSuccess_reverts() external { function test_relayMessage_legacyRetryAfterFailureThenSuccess_reverts() external {
address target = address(0xabcd); address target = address(0xabcd);
address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER;
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; // Testing utilities
import { Messenger_Initializer } from "./CommonTest.t.sol"; import { Messenger_Initializer } from "./CommonTest.t.sol";
import { L1ERC721Bridge } from "../L1/L1ERC721Bridge.sol"; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
// Target contract dependencies
import { L2ERC721Bridge } from "../L2/L2ERC721Bridge.sol"; import { L2ERC721Bridge } from "../L2/L2ERC721Bridge.sol";
// Target contract
import { L1ERC721Bridge } from "../L1/L1ERC721Bridge.sol";
/// @dev Test ERC721 contract.
contract TestERC721 is ERC721 { contract TestERC721 is ERC721 {
constructor() ERC721("Test", "TST") {} constructor() ERC721("Test", "TST") {}
...@@ -39,6 +45,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -39,6 +45,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
bytes extraData bytes extraData
); );
/// @dev Sets up the testing environment.
function setUp() public override { function setUp() public override {
super.setUp(); super.setUp();
...@@ -58,6 +65,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -58,6 +65,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
localToken.approve(address(bridge), tokenId); localToken.approve(address(bridge), tokenId);
} }
/// @dev Tests that the constructor sets the correct values.
function test_constructor_succeeds() public { function test_constructor_succeeds() public {
assertEq(address(bridge.MESSENGER()), address(L1Messenger)); assertEq(address(bridge.MESSENGER()), address(L1Messenger));
assertEq(address(bridge.OTHER_BRIDGE()), otherBridge); assertEq(address(bridge.OTHER_BRIDGE()), otherBridge);
...@@ -65,6 +73,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -65,6 +73,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
assertEq(address(bridge.otherBridge()), otherBridge); assertEq(address(bridge.otherBridge()), otherBridge);
} }
/// @dev Tests that the ERC721 can be bridged successfully.
function test_bridgeERC721_succeeds() public { function test_bridgeERC721_succeeds() public {
// Expect a call to the messenger. // Expect a call to the messenger.
vm.expectCall( vm.expectCall(
...@@ -109,6 +118,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -109,6 +118,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
assertEq(localToken.ownerOf(tokenId), address(bridge)); assertEq(localToken.ownerOf(tokenId), address(bridge));
} }
/// @dev Tests that the ERC721 bridge reverts for non externally owned accounts.
function test_bridgeERC721_fromContract_reverts() external { function test_bridgeERC721_fromContract_reverts() external {
// Bridge the token. // Bridge the token.
vm.etch(alice, hex"01"); vm.etch(alice, hex"01");
...@@ -121,6 +131,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -121,6 +131,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
assertEq(localToken.ownerOf(tokenId), alice); assertEq(localToken.ownerOf(tokenId), alice);
} }
/// @dev Tests that the ERC721 bridge reverts for a zero address local token.
function test_bridgeERC721_localTokenZeroAddress_reverts() external { function test_bridgeERC721_localTokenZeroAddress_reverts() external {
// Bridge the token. // Bridge the token.
vm.prank(alice); vm.prank(alice);
...@@ -132,6 +143,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -132,6 +143,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
assertEq(localToken.ownerOf(tokenId), alice); assertEq(localToken.ownerOf(tokenId), alice);
} }
/// @dev Tests that the ERC721 bridge reverts for a zero address remote token.
function test_bridgeERC721_remoteTokenZeroAddress_reverts() external { function test_bridgeERC721_remoteTokenZeroAddress_reverts() external {
// Bridge the token. // Bridge the token.
vm.prank(alice); vm.prank(alice);
...@@ -143,6 +155,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -143,6 +155,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
assertEq(localToken.ownerOf(tokenId), alice); assertEq(localToken.ownerOf(tokenId), alice);
} }
/// @dev Tests that the ERC721 bridge reverts for an incorrect owner.
function test_bridgeERC721_wrongOwner_reverts() external { function test_bridgeERC721_wrongOwner_reverts() external {
// Bridge the token. // Bridge the token.
vm.prank(bob); vm.prank(bob);
...@@ -154,6 +167,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -154,6 +167,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
assertEq(localToken.ownerOf(tokenId), alice); assertEq(localToken.ownerOf(tokenId), alice);
} }
/// @dev Tests that the ERC721 bridge successfully sends a token
/// to a different address than the owner.
function test_bridgeERC721To_succeeds() external { function test_bridgeERC721To_succeeds() external {
// Expect a call to the messenger. // Expect a call to the messenger.
vm.expectCall( vm.expectCall(
...@@ -198,6 +213,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -198,6 +213,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
assertEq(localToken.ownerOf(tokenId), address(bridge)); assertEq(localToken.ownerOf(tokenId), address(bridge));
} }
/// @dev Tests that the ERC721 bridge reverts for non externally owned accounts
/// when sending to a different address than the owner.
function test_bridgeERC721To_localTokenZeroAddress_reverts() external { function test_bridgeERC721To_localTokenZeroAddress_reverts() external {
// Bridge the token. // Bridge the token.
vm.prank(alice); vm.prank(alice);
...@@ -209,6 +226,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -209,6 +226,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
assertEq(localToken.ownerOf(tokenId), alice); assertEq(localToken.ownerOf(tokenId), alice);
} }
/// @dev Tests that the ERC721 bridge reverts for a zero address remote token
/// when sending to a different address than the owner.
function test_bridgeERC721To_remoteTokenZeroAddress_reverts() external { function test_bridgeERC721To_remoteTokenZeroAddress_reverts() external {
// Bridge the token. // Bridge the token.
vm.prank(alice); vm.prank(alice);
...@@ -220,6 +239,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -220,6 +239,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
assertEq(localToken.ownerOf(tokenId), alice); assertEq(localToken.ownerOf(tokenId), alice);
} }
/// @dev Tests that the ERC721 bridge reverts for an incorrect owner
//// when sending to a different address than the owner.
function test_bridgeERC721To_wrongOwner_reverts() external { function test_bridgeERC721To_wrongOwner_reverts() external {
// Bridge the token. // Bridge the token.
vm.prank(bob); vm.prank(bob);
...@@ -238,6 +259,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -238,6 +259,7 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
assertEq(localToken.ownerOf(tokenId), alice); assertEq(localToken.ownerOf(tokenId), alice);
} }
/// @dev Tests that the ERC721 bridge successfully finalizes a withdrawal.
function test_finalizeBridgeERC721_succeeds() external { function test_finalizeBridgeERC721_succeeds() external {
// Bridge the token. // Bridge the token.
vm.prank(alice); vm.prank(alice);
...@@ -275,6 +297,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -275,6 +297,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
assertEq(localToken.ownerOf(tokenId), alice); assertEq(localToken.ownerOf(tokenId), alice);
} }
/// @dev Tests that the ERC721 bridge finalize reverts when not called
/// by the remote bridge.
function test_finalizeBridgeERC721_notViaLocalMessenger_reverts() external { function test_finalizeBridgeERC721_notViaLocalMessenger_reverts() external {
// Finalize a withdrawal. // Finalize a withdrawal.
vm.prank(alice); vm.prank(alice);
...@@ -289,6 +313,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -289,6 +313,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
); );
} }
/// @dev Tests that the ERC721 bridge finalize reverts when not called
/// from the remote messenger.
function test_finalizeBridgeERC721_notFromRemoteMessenger_reverts() external { function test_finalizeBridgeERC721_notFromRemoteMessenger_reverts() external {
// Finalize a withdrawal. // Finalize a withdrawal.
vm.mockCall( vm.mockCall(
...@@ -308,6 +334,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -308,6 +334,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
); );
} }
/// @dev Tests that the ERC721 bridge finalize reverts when the local token
/// is set as the bridge itself.
function test_finalizeBridgeERC721_selfToken_reverts() external { function test_finalizeBridgeERC721_selfToken_reverts() external {
// Finalize a withdrawal. // Finalize a withdrawal.
vm.mockCall( vm.mockCall(
...@@ -327,6 +355,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer { ...@@ -327,6 +355,8 @@ contract L1ERC721Bridge_Test is Messenger_Initializer {
); );
} }
/// @dev Tests that the ERC721 bridge finalize reverts when the remote token
/// is not escrowed in the L1 bridge.
function test_finalizeBridgeERC721_notEscrowed_reverts() external { function test_finalizeBridgeERC721_notEscrowed_reverts() external {
// Finalize a withdrawal. // Finalize a withdrawal.
vm.mockCall( vm.mockCall(
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
// Testing utilities
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { ResourceMetering } from "../L1/ResourceMetering.sol";
import { Proxy } from "../universal/Proxy.sol"; // Libraries
import { Constants } from "../libraries/Constants.sol"; import { Constants } from "../libraries/Constants.sol";
// Target contract dependencies
import { Proxy } from "../universal/Proxy.sol";
// Target contract
import { ResourceMetering } from "../L1/ResourceMetering.sol";
contract MeterUser is ResourceMetering { contract MeterUser is ResourceMetering {
ResourceMetering.ResourceConfig public innerConfig; ResourceMetering.ResourceConfig public innerConfig;
...@@ -50,20 +57,20 @@ contract MeterUser is ResourceMetering { ...@@ -50,20 +57,20 @@ contract MeterUser is ResourceMetering {
} }
} }
/** /// @title ResourceMetering_Test
* @title ResourceConfig /// @dev Tests are based on the default config values.
* @notice The tests are based on the default config values. It is expected that /// It is expected that these config values are used in production.
* the config values used in these tests are ran in production.
*/
contract ResourceMetering_Test is Test { contract ResourceMetering_Test is Test {
MeterUser internal meter; MeterUser internal meter;
uint64 initialBlockNum; uint64 initialBlockNum;
/// @dev Sets up the test contract.
function setUp() public { function setUp() public {
meter = new MeterUser(); meter = new MeterUser();
initialBlockNum = uint64(block.number); initialBlockNum = uint64(block.number);
} }
/// @dev Tests that the initial resource params are set correctly.
function test_meter_initialResourceParams_succeeds() external { function test_meter_initialResourceParams_succeeds() external {
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params(); (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params();
ResourceMetering.ResourceConfig memory rcfg = meter.resourceConfig(); ResourceMetering.ResourceConfig memory rcfg = meter.resourceConfig();
...@@ -73,6 +80,7 @@ contract ResourceMetering_Test is Test { ...@@ -73,6 +80,7 @@ contract ResourceMetering_Test is Test {
assertEq(prevBlockNum, initialBlockNum); assertEq(prevBlockNum, initialBlockNum);
} }
/// @dev Tests that updating the resource params to the same values works correctly.
function test_meter_updateParamsNoChange_succeeds() external { function test_meter_updateParamsNoChange_succeeds() external {
meter.use(0); // equivalent to just updating the base fee and block number meter.use(0); // equivalent to just updating the base fee and block number
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params(); (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params();
...@@ -84,6 +92,7 @@ contract ResourceMetering_Test is Test { ...@@ -84,6 +92,7 @@ contract ResourceMetering_Test is Test {
assertEq(postBlockNum, prevBlockNum); assertEq(postBlockNum, prevBlockNum);
} }
/// @dev Tests that updating the initial block number sets the meter params correctly.
function test_meter_updateOneEmptyBlock_succeeds() external { function test_meter_updateOneEmptyBlock_succeeds() external {
vm.roll(initialBlockNum + 1); vm.roll(initialBlockNum + 1);
meter.use(0); meter.use(0);
...@@ -94,6 +103,7 @@ contract ResourceMetering_Test is Test { ...@@ -94,6 +103,7 @@ contract ResourceMetering_Test is Test {
assertEq(prevBlockNum, initialBlockNum + 1); assertEq(prevBlockNum, initialBlockNum + 1);
} }
/// @dev Tests that updating the initial block number sets the meter params correctly.
function test_meter_updateTwoEmptyBlocks_succeeds() external { function test_meter_updateTwoEmptyBlocks_succeeds() external {
vm.roll(initialBlockNum + 2); vm.roll(initialBlockNum + 2);
meter.use(0); meter.use(0);
...@@ -104,6 +114,7 @@ contract ResourceMetering_Test is Test { ...@@ -104,6 +114,7 @@ contract ResourceMetering_Test is Test {
assertEq(prevBlockNum, initialBlockNum + 2); assertEq(prevBlockNum, initialBlockNum + 2);
} }
/// @dev Tests that updating the initial block number sets the meter params correctly.
function test_meter_updateTenEmptyBlocks_succeeds() external { function test_meter_updateTenEmptyBlocks_succeeds() external {
vm.roll(initialBlockNum + 10); vm.roll(initialBlockNum + 10);
meter.use(0); meter.use(0);
...@@ -114,6 +125,7 @@ contract ResourceMetering_Test is Test { ...@@ -114,6 +125,7 @@ contract ResourceMetering_Test is Test {
assertEq(prevBlockNum, initialBlockNum + 10); assertEq(prevBlockNum, initialBlockNum + 10);
} }
/// @dev Tests that updating the gas delta sets the meter params correctly.
function test_meter_updateNoGasDelta_succeeds() external { function test_meter_updateNoGasDelta_succeeds() external {
ResourceMetering.ResourceConfig memory rcfg = meter.resourceConfig(); ResourceMetering.ResourceConfig memory rcfg = meter.resourceConfig();
uint256 target = uint256(rcfg.maxResourceLimit) / uint256(rcfg.elasticityMultiplier); uint256 target = uint256(rcfg.maxResourceLimit) / uint256(rcfg.elasticityMultiplier);
...@@ -125,6 +137,7 @@ contract ResourceMetering_Test is Test { ...@@ -125,6 +137,7 @@ contract ResourceMetering_Test is Test {
assertEq(prevBlockNum, initialBlockNum); assertEq(prevBlockNum, initialBlockNum);
} }
/// @dev Tests that the meter params are set correctly for the maximum gas delta.
function test_meter_useMax_succeeds() external { function test_meter_useMax_succeeds() external {
ResourceMetering.ResourceConfig memory rcfg = meter.resourceConfig(); ResourceMetering.ResourceConfig memory rcfg = meter.resourceConfig();
uint64 target = uint64(rcfg.maxResourceLimit) / uint64(rcfg.elasticityMultiplier); uint64 target = uint64(rcfg.maxResourceLimit) / uint64(rcfg.elasticityMultiplier);
...@@ -141,15 +154,9 @@ contract ResourceMetering_Test is Test { ...@@ -141,15 +154,9 @@ contract ResourceMetering_Test is Test {
assertEq(postBaseFee, 2125000000); assertEq(postBaseFee, 2125000000);
} }
/** /// @dev Tests that the metered modifier reverts if the baseFeeMaxChangeDenominator is set to 1.
* @notice This tests that the metered modifier reverts if /// Since the metered modifier internally calls solmate's powWad function, it will revert
* the ResourceConfig baseFeeMaxChangeDenominator /// with the error string "UNDEFINED" since the first parameter will be computed as 0.
* is set to 1.
* Since the metered modifier internally calls
* solmate's powWad function, it will revert
* with the error string "UNDEFINED" since the
* first parameter will be computed as 0.
*/
function test_meter_denominatorEq1_reverts() external { function test_meter_denominatorEq1_reverts() external {
ResourceMetering.ResourceConfig memory rcfg = meter.resourceConfig(); ResourceMetering.ResourceConfig memory rcfg = meter.resourceConfig();
uint64 target = uint64(rcfg.maxResourceLimit) / uint64(rcfg.elasticityMultiplier); uint64 target = uint64(rcfg.maxResourceLimit) / uint64(rcfg.elasticityMultiplier);
...@@ -167,6 +174,7 @@ contract ResourceMetering_Test is Test { ...@@ -167,6 +174,7 @@ contract ResourceMetering_Test is Test {
meter.use(0); meter.use(0);
} }
/// @dev Tests that the metered modifier reverts if the value is greater than allowed.
function test_meter_useMoreThanMax_reverts() external { function test_meter_useMoreThanMax_reverts() external {
ResourceMetering.ResourceConfig memory rcfg = meter.resourceConfig(); ResourceMetering.ResourceConfig memory rcfg = meter.resourceConfig();
uint64 target = uint64(rcfg.maxResourceLimit) / uint64(rcfg.elasticityMultiplier); uint64 target = uint64(rcfg.maxResourceLimit) / uint64(rcfg.elasticityMultiplier);
...@@ -176,8 +184,7 @@ contract ResourceMetering_Test is Test { ...@@ -176,8 +184,7 @@ contract ResourceMetering_Test is Test {
meter.use(target * elasticityMultiplier + 1); meter.use(target * elasticityMultiplier + 1);
} }
// Demonstrates that the resource metering arithmetic can tolerate very large gaps between /// @dev Tests that resource metering can handle large gaps between deposits.
// deposits.
function testFuzz_meter_largeBlockDiff_succeeds(uint64 _amount, uint256 _blockDiff) external { function testFuzz_meter_largeBlockDiff_succeeds(uint64 _amount, uint256 _blockDiff) external {
// This test fails if the following line is commented out. // This test fails if the following line is commented out.
// At 12 seconds per block, this number is effectively unreachable. // At 12 seconds per block, this number is effectively unreachable.
...@@ -193,11 +200,9 @@ contract ResourceMetering_Test is Test { ...@@ -193,11 +200,9 @@ contract ResourceMetering_Test is Test {
} }
} }
/** /// @title CustomMeterUser
* @title CustomMeterUser /// @notice A simple wrapper around `ResourceMetering` that allows the initial
* @notice A simple wrapper around `ResourceMetering` that allows the initial /// params to be set in the constructor.
* params to be set in the constructor.
*/
contract CustomMeterUser is ResourceMetering { contract CustomMeterUser is ResourceMetering {
uint256 public startGas; uint256 public startGas;
uint256 public endGas; uint256 public endGas;
...@@ -230,15 +235,13 @@ contract CustomMeterUser is ResourceMetering { ...@@ -230,15 +235,13 @@ contract CustomMeterUser is ResourceMetering {
} }
} }
/** /// @title ArtifactResourceMetering_Test
* @title ArtifactResourceMetering_Test /// @notice A table test that sets the state of the ResourceParams and then requests
* @notice A table test that sets the state of the ResourceParams and then requests /// various amounts of gas. This test ensures that a wide range of values
* various amounts of gas. This test ensures that a wide range of values /// can safely be used with the `ResourceMetering` contract.
* can safely be used with the `ResourceMetering` contract. /// It also writes a CSV file to disk that includes useful information
* It also writes a CSV file to disk that includes useful information /// about how much gas is used and how expensive it is in USD terms to
* about how much gas is used and how expensive it is in USD terms to /// purchase the deposit gas.
* purchase the deposit gas.
*/
contract ArtifactResourceMetering_Test is Test { contract ArtifactResourceMetering_Test is Test {
uint128 internal minimumBaseFee; uint128 internal minimumBaseFee;
uint128 internal maximumBaseFee; uint128 internal maximumBaseFee;
...@@ -257,10 +260,7 @@ contract ArtifactResourceMetering_Test is Test { ...@@ -257,10 +260,7 @@ contract ArtifactResourceMetering_Test is Test {
bytes32 internal emptyReturnData = bytes32 internal emptyReturnData =
0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
/** /// @dev Sets up the tests with constants from the ResourceMetering contract.
* @notice Sets up the tests by getting constants from the ResourceMetering
* contract.
*/
function setUp() public { function setUp() public {
vm.roll(1_000_000); vm.roll(1_000_000);
...@@ -275,11 +275,8 @@ contract ArtifactResourceMetering_Test is Test { ...@@ -275,11 +275,8 @@ contract ArtifactResourceMetering_Test is Test {
try vm.removeFile(outfile) {} catch {} try vm.removeFile(outfile) {} catch {}
} }
/** /// @dev Generates a CSV file. No more than the L1 block gas limit should
* @notice Generate a CSV file. The call to `meter` should be called with at /// be supplied to the `meter` function to avoid long execution time.
* most the L1 block gas limit. Without specifying the amount of
* gas, it can take very long to execute.
*/
function test_meter_generateArtifact_succeeds() external { function test_meter_generateArtifact_succeeds() external {
vm.writeLine( vm.writeLine(
outfile, outfile,
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
// Testing utilities
import { CommonTest } from "./CommonTest.t.sol"; import { CommonTest } from "./CommonTest.t.sol";
import { SystemConfig } from "../L1/SystemConfig.sol";
import { ResourceMetering } from "../L1/ResourceMetering.sol"; // Libraries
import { Constants } from "../libraries/Constants.sol"; import { Constants } from "../libraries/Constants.sol";
// Target contract dependencies
import { ResourceMetering } from "../L1/ResourceMetering.sol";
// Target contract
import { SystemConfig } from "../L1/SystemConfig.sol";
contract SystemConfig_Init is CommonTest { contract SystemConfig_Init is CommonTest {
SystemConfig sysConf; SystemConfig sysConf;
...@@ -34,6 +41,7 @@ contract SystemConfig_Init is CommonTest { ...@@ -34,6 +41,7 @@ contract SystemConfig_Init is CommonTest {
} }
contract SystemConfig_Initialize_TestFail is SystemConfig_Init { contract SystemConfig_Initialize_TestFail is SystemConfig_Init {
/// @dev Tests that initialization reverts if the gas limit is too low.
function test_initialize_lowGasLimit_reverts() external { function test_initialize_lowGasLimit_reverts() external {
uint64 minimumGasLimit = sysConf.minimumGasLimit(); uint64 minimumGasLimit = sysConf.minimumGasLimit();
...@@ -60,32 +68,39 @@ contract SystemConfig_Initialize_TestFail is SystemConfig_Init { ...@@ -60,32 +68,39 @@ contract SystemConfig_Initialize_TestFail is SystemConfig_Init {
} }
contract SystemConfig_Setters_TestFail is SystemConfig_Init { contract SystemConfig_Setters_TestFail is SystemConfig_Init {
/// @dev Tests that `setBatcherHash` reverts if the caller is not the owner.
function test_setBatcherHash_notOwner_reverts() external { function test_setBatcherHash_notOwner_reverts() external {
vm.expectRevert("Ownable: caller is not the owner"); vm.expectRevert("Ownable: caller is not the owner");
sysConf.setBatcherHash(bytes32(hex"")); sysConf.setBatcherHash(bytes32(hex""));
} }
/// @dev Tests that `setGasConfig` reverts if the caller is not the owner.
function test_setGasConfig_notOwner_reverts() external { function test_setGasConfig_notOwner_reverts() external {
vm.expectRevert("Ownable: caller is not the owner"); vm.expectRevert("Ownable: caller is not the owner");
sysConf.setGasConfig(0, 0); sysConf.setGasConfig(0, 0);
} }
/// @dev Tests that `setGasLimit` reverts if the caller is not the owner.
function test_setGasLimit_notOwner_reverts() external { function test_setGasLimit_notOwner_reverts() external {
vm.expectRevert("Ownable: caller is not the owner"); vm.expectRevert("Ownable: caller is not the owner");
sysConf.setGasLimit(0); sysConf.setGasLimit(0);
} }
/// @dev Tests that `setUnsafeBlockSigner` reverts if the caller is not the owner.
function test_setUnsafeBlockSigner_notOwner_reverts() external { function test_setUnsafeBlockSigner_notOwner_reverts() external {
vm.expectRevert("Ownable: caller is not the owner"); vm.expectRevert("Ownable: caller is not the owner");
sysConf.setUnsafeBlockSigner(address(0x20)); sysConf.setUnsafeBlockSigner(address(0x20));
} }
/// @dev Tests that `setResourceConfig` reverts if the caller is not the owner.
function test_setResourceConfig_notOwner_reverts() external { function test_setResourceConfig_notOwner_reverts() external {
ResourceMetering.ResourceConfig memory config = Constants.DEFAULT_RESOURCE_CONFIG(); ResourceMetering.ResourceConfig memory config = Constants.DEFAULT_RESOURCE_CONFIG();
vm.expectRevert("Ownable: caller is not the owner"); vm.expectRevert("Ownable: caller is not the owner");
sysConf.setResourceConfig(config); sysConf.setResourceConfig(config);
} }
/// @dev Tests that `setResourceConfig` reverts if the min base fee
/// is greater than the maximum allowed base fee.
function test_setResourceConfig_badMinMax_reverts() external { function test_setResourceConfig_badMinMax_reverts() external {
ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({ ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({
maxResourceLimit: 20_000_000, maxResourceLimit: 20_000_000,
...@@ -100,6 +115,8 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init { ...@@ -100,6 +115,8 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
sysConf.setResourceConfig(config); sysConf.setResourceConfig(config);
} }
/// @dev Tests that `setResourceConfig` reverts if the baseFeeMaxChangeDenominator
/// is zero.
function test_setResourceConfig_zeroDenominator_reverts() external { function test_setResourceConfig_zeroDenominator_reverts() external {
ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({ ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({
maxResourceLimit: 20_000_000, maxResourceLimit: 20_000_000,
...@@ -114,6 +131,7 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init { ...@@ -114,6 +131,7 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
sysConf.setResourceConfig(config); sysConf.setResourceConfig(config);
} }
/// @dev Tests that `setResourceConfig` reverts if the gas limit is too low.
function test_setResourceConfig_lowGasLimit_reverts() external { function test_setResourceConfig_lowGasLimit_reverts() external {
uint64 gasLimit = sysConf.gasLimit(); uint64 gasLimit = sysConf.gasLimit();
...@@ -130,6 +148,8 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init { ...@@ -130,6 +148,8 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
sysConf.setResourceConfig(config); sysConf.setResourceConfig(config);
} }
/// @dev Tests that `setResourceConfig` reverts if the elasticity multiplier
/// and max resource limit are configured such that there is a loss of precision.
function test_setResourceConfig_badPrecision_reverts() external { function test_setResourceConfig_badPrecision_reverts() external {
ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({ ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({
maxResourceLimit: 20_000_000, maxResourceLimit: 20_000_000,
...@@ -152,6 +172,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { ...@@ -152,6 +172,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
bytes data bytes data
); );
/// @dev Tests that `setBatcherHash` updates the batcher hash successfully.
function testFuzz_setBatcherHash_succeeds(bytes32 newBatcherHash) external { function testFuzz_setBatcherHash_succeeds(bytes32 newBatcherHash) external {
vm.expectEmit(true, true, true, true); vm.expectEmit(true, true, true, true);
emit ConfigUpdate(0, SystemConfig.UpdateType.BATCHER, abi.encode(newBatcherHash)); emit ConfigUpdate(0, SystemConfig.UpdateType.BATCHER, abi.encode(newBatcherHash));
...@@ -161,6 +182,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { ...@@ -161,6 +182,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
assertEq(sysConf.batcherHash(), newBatcherHash); assertEq(sysConf.batcherHash(), newBatcherHash);
} }
/// @dev Tests that `setGasConfig` updates the overhead and scalar successfully.
function testFuzz_setGasConfig_succeeds(uint256 newOverhead, uint256 newScalar) external { function testFuzz_setGasConfig_succeeds(uint256 newOverhead, uint256 newScalar) external {
vm.expectEmit(true, true, true, true); vm.expectEmit(true, true, true, true);
emit ConfigUpdate( emit ConfigUpdate(
...@@ -175,6 +197,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { ...@@ -175,6 +197,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
assertEq(sysConf.scalar(), newScalar); assertEq(sysConf.scalar(), newScalar);
} }
/// @dev Tests that `setGasLimit` updates the gas limit successfully.
function testFuzz_setGasLimit_succeeds(uint64 newGasLimit) external { function testFuzz_setGasLimit_succeeds(uint64 newGasLimit) external {
uint64 minimumGasLimit = sysConf.minimumGasLimit(); uint64 minimumGasLimit = sysConf.minimumGasLimit();
newGasLimit = uint64( newGasLimit = uint64(
...@@ -189,6 +212,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { ...@@ -189,6 +212,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
assertEq(sysConf.gasLimit(), newGasLimit); assertEq(sysConf.gasLimit(), newGasLimit);
} }
/// @dev Tests that `setUnsafeBlockSigner` updates the block signer successfully.
function testFuzz_setUnsafeBlockSigner_succeeds(address newUnsafeSigner) external { function testFuzz_setUnsafeBlockSigner_succeeds(address newUnsafeSigner) external {
vm.expectEmit(true, true, true, true); vm.expectEmit(true, true, true, true);
emit ConfigUpdate( emit ConfigUpdate(
......
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