Commit a0ff1cc9 authored by Andreas Bigger's avatar Andreas Bigger

Port all remaining test files to triple slash natspec styling.

parent 3c0e8a98
......@@ -5,9 +5,7 @@ import { Test } from "forge-std/Test.sol";
import { AddressAliasHelper } from "../vendor/AddressAliasHelper.sol";
contract AddressAliasHelper_applyAndUndo_Test is Test {
/**
* @notice Tests that applying and then undoing an alias results in the original address.
*/
/// @notice Tests that applying and then undoing an alias results in the original address.
function testFuzz_applyAndUndo_succeeds(address _address) external {
address aliased = AddressAliasHelper.applyL1ToL2Alias(_address);
address unaliased = AddressAliasHelper.undoL1ToL2Alias(aliased);
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
......@@ -6,41 +6,32 @@ import { AdminFaucetAuthModule } from "../periphery/faucet/authmodules/AdminFauc
import { Faucet } from "../periphery/faucet/Faucet.sol";
import { FaucetHelper } from "./Helpers.sol";
/**
* @title AdminFaucetAuthModuleTest
* @notice Tests the AdminFaucetAuthModule contract.
*/
/// @title AdminFaucetAuthModuleTest
/// @notice Tests the AdminFaucetAuthModule contract.
contract AdminFaucetAuthModuleTest is Test {
/**
* @notice The admin of the `AdminFaucetAuthModule` contract.
*/
/// @notice The admin of the `AdminFaucetAuthModule` contract.
address internal admin;
/**
* @notice Private key of the `admin`.
*/
/// @notice Private key of the `admin`.
uint256 internal adminKey;
/**
* @notice Not an admin of the `AdminFaucetAuthModule` contract.
*/
/// @notice Not an admin of the `AdminFaucetAuthModule` contract.
address internal nonAdmin;
/**
* @notice Private key of the `nonAdmin`.
*/
/// @notice Private key of the `nonAdmin`.
uint256 internal nonAdminKey;
/**
* @notice An instance of the `AdminFaucetAuthModule` contract.
*/
/// @notice An instance of the `AdminFaucetAuthModule` contract.
AdminFaucetAuthModule internal adminFam;
/**
* @notice An instance of the `FaucetHelper` contract.
*/
/// @notice An instance of the `FaucetHelper` contract.
FaucetHelper internal faucetHelper;
string internal adminFamName = "AdminFAM";
string internal adminFamVersion = "1";
/**
* @notice Deploy the `AdminFaucetAuthModule` contract.
*/
/// @notice Deploy the `AdminFaucetAuthModule` contract.
function setUp() external {
adminKey = 0xB0B0B0B0;
admin = vm.addr(adminKey);
......@@ -53,10 +44,7 @@ contract AdminFaucetAuthModuleTest is Test {
faucetHelper = new FaucetHelper();
}
/**
* @notice Get signature as a bytes blob.
*
*/
/// @notice Get signature as a bytes blob.
function _getSignature(uint256 _signingPrivateKey, bytes32 _digest)
internal
pure
......@@ -68,11 +56,9 @@ contract AdminFaucetAuthModuleTest is Test {
return signature;
}
/**
* @notice Signs a proof with the given private key and returns the signature using
* the given EIP712 domain separator. This assumes that the issuer's address is the
* corresponding public key to _issuerPrivateKey.
*/
/// @notice Signs a proof with the given private key and returns the signature using
/// the given EIP712 domain separator. This assumes that the issuer's address is the
/// corresponding public key to _issuerPrivateKey.
function issueProofWithEIP712Domain(
uint256 _issuerPrivateKey,
bytes memory _eip712Name,
......@@ -101,9 +87,7 @@ contract AdminFaucetAuthModuleTest is Test {
);
}
/**
* @notice assert that verify returns true for valid proofs signed by admins.
*/
/// @notice Assert that verify returns true for valid proofs signed by admins.
function test_adminProof_verify_succeeds() external {
bytes32 nonce = faucetHelper.consumeNonce();
address fundsReceiver = makeAddr("fundsReceiver");
......@@ -129,9 +113,7 @@ contract AdminFaucetAuthModuleTest is Test {
);
}
/**
* @notice assert that verify returns false for proofs signed by nonadmins.
*/
/// @notice Assert that verify returns false for proofs signed by nonadmins.
function test_nonAdminProof_verify_succeeds() external {
bytes32 nonce = faucetHelper.consumeNonce();
address fundsReceiver = makeAddr("fundsReceiver");
......@@ -157,10 +139,8 @@ contract AdminFaucetAuthModuleTest is Test {
);
}
/**
* @notice assert that verify returns false for proofs where the id in the proof is different
* than the id in the call to verify.
*/
/// @notice Assert that verify returns false for proofs where the id in the proof is different
/// than the id in the call to verify.
function test_proofWithWrongId_verify_succeeds() external {
bytes32 nonce = faucetHelper.consumeNonce();
address fundsReceiver = makeAddr("fundsReceiver");
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
/* Testing utilities */
// Testing utilities
import { Test } from "forge-std/Test.sol";
import { TestERC20 } from "./Helpers.sol";
import { TestERC721 } from "./Helpers.sol";
......@@ -53,12 +53,12 @@ contract AssetReceiver_Initializer is Test {
}
contract AssetReceiverTest is AssetReceiver_Initializer {
// Tests if the owner was set correctly during deploy
/// @notice Tests if the owner was set correctly during deploy.
function test_constructor_succeeds() external {
assertEq(address(alice), assetReceiver.owner());
}
// Tests that receive works as inteded
/// @notice Tests that receive works as inteded.
function test_receive_succeeds() external {
// Check that contract balance is 0 initially
assertEq(address(assetReceiver).balance, 0);
......@@ -74,7 +74,8 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
assertEq(address(assetReceiver).balance, 100);
}
// Tests withdrawETH function with only an address as argument, called by owner
/// @notice Tests withdrawETH function with only an address
/// as an argument, called by owner.
function test_withdrawETH_succeeds() external {
// Check contract initial balance
assertEq(address(assetReceiver).balance, 0);
......@@ -96,14 +97,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
assertEq(address(alice).balance, 2 ether);
}
// withdrawETH should fail if called by non-owner
/// @notice withdrawETH should fail if called by non-owner.
function test_withdrawETH_unauthorized_reverts() external {
vm.deal(address(assetReceiver), 1 ether);
vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawETH(payable(alice));
}
// Similar as withdrawETH but specify amount to withdraw
/// @notice Similar as withdrawETH but specify amount to withdraw.
function test_withdrawETHwithAmount_succeeds() external {
assertEq(address(assetReceiver).balance, 0);
......@@ -124,14 +125,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
assertEq(address(alice).balance, 1.5 ether);
}
// withdrawETH with address and amount as arguments called by non-owner
/// @notice withdrawETH with address and amount as arguments called by non-owner.
function test_withdrawETHwithAmount_unauthorized_reverts() external {
vm.deal(address(assetReceiver), 1 ether);
vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawETH(payable(alice), 0.5 ether);
}
// Test withdrawERC20 with token and address arguments, from owner
/// @notice Test withdrawERC20 with token and address arguments, from owner.
function test_withdrawERC20_succeeds() external {
// check balances before the call
assertEq(testERC20.balanceOf(address(assetReceiver)), 0);
......@@ -152,14 +153,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
assertEq(testERC20.balanceOf(address(assetReceiver)), 0);
}
// Same as withdrawERC20 but call from non-owner
/// @notice Same as withdrawERC20 but call from non-owner.
function test_withdrawERC20_unauthorized_reverts() external {
deal(address(testERC20), address(assetReceiver), 100_000);
vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawERC20(testERC20, alice);
}
// Similar as withdrawERC20 but specify amount to withdraw
/// @notice Similar as withdrawERC20 but specify amount to withdraw.
function test_withdrawERC20withAmount_succeeds() external {
// check balances before the call
assertEq(testERC20.balanceOf(address(assetReceiver)), 0);
......@@ -180,14 +181,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
assertEq(testERC20.balanceOf(address(assetReceiver)), 50_000);
}
// Similar as withdrawERC20 with amount but call from non-owner
/// @notice Similar as withdrawERC20 with amount but call from non-owner.
function test_withdrawERC20withAmount_unauthorized_reverts() external {
deal(address(testERC20), address(assetReceiver), 100_000);
vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawERC20(testERC20, alice, 50_000);
}
// Test withdrawERC721 from owner
/// @notice Test withdrawERC721 from owner.
function test_withdrawERC721_succeeds() external {
// Check owner of the token before calling withdrawERC721
assertEq(testERC721.ownerOf(DEFAULT_TOKEN_ID), alice);
......@@ -208,7 +209,7 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
assertEq(testERC721.ownerOf(DEFAULT_TOKEN_ID), alice);
}
// Similar as withdrawERC721 but call from non-owner
/// @notice Similar as withdrawERC721 but call from non-owner.
function test_withdrawERC721_unauthorized_reverts() external {
vm.prank(alice);
testERC721.transferFrom(alice, address(assetReceiver), DEFAULT_TOKEN_ID);
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
/* Testing utilities */
// Testing utilities
import { Test } from "forge-std/Test.sol";
import { Vm } from "forge-std/Vm.sol";
import "./CommonTest.t.sol";
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
// Testing utilities
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
import { CheckBalanceHigh } from "../periphery/drippie/dripchecks/CheckBalanceHigh.sol";
/**
* @title CheckBalanceHighTest
* @notice Tests the CheckBalanceHigh contract via fuzzing both the success case
* and the failure case.
*/
/// @title CheckBalanceHighTest
/// @notice Tests the CheckBalanceHigh contract via fuzzing both the success case
/// and the failure case.
contract CheckBalanceHighTest is Test {
/**
* @notice An instance of the CheckBalanceHigh contract.
*/
/// @notice An instance of the CheckBalanceHigh contract.
CheckBalanceHigh c;
/**
* @notice Deploy the `CheckTrue` contract.
*/
/// @notice Deploy the `CheckTrue` contract.
function setUp() external {
c = new CheckBalanceHigh();
}
/**
* @notice Fuzz the `check` function and assert that it always returns true
* when the target's balance is larger than the threshold.
*/
/// @notice Fuzz the `check` function and assert that it always returns true
/// when the target's balance is larger than the threshold.
function testFuzz_check_succeeds(address _target, uint256 _threshold) external {
CheckBalanceHigh.Params memory p = CheckBalanceHigh.Params({
target: _target,
......@@ -39,10 +31,8 @@ contract CheckBalanceHighTest is Test {
assertEq(c.check(abi.encode(p)), true);
}
/**
* @notice Fuzz the `check` function and assert that it always returns false
* when the target's balance is smaller than the threshold.
*/
/// @notice Fuzz the `check` function and assert that it always returns false
/// when the target's balance is smaller than the threshold.
function testFuzz_check_lowBalance_fails(address _target, uint256 _threshold) external {
CheckBalanceHigh.Params memory p = CheckBalanceHigh.Params({
target: _target,
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
import { CheckBalanceLow } from "../periphery/drippie/dripchecks/CheckBalanceLow.sol";
/**
* @title CheckBalanceLowTest
* @notice Tests the CheckBalanceLow contract via fuzzing both the success case
* and the failure case.
*/
/// @title CheckBalanceLowTest
/// @notice Tests the CheckBalanceLow contract via fuzzing both the success case
/// and the failure case.
contract CheckBalanceLowTest is Test {
/**
* @notice An instance of the CheckBalanceLow contract.
*/
/// @notice An instance of the CheckBalanceLow contract.
CheckBalanceLow c;
/**
* @notice Deploy the `CheckBalanceLow` contract.
*/
/// @notice Deploy the `CheckBalanceLow` contract.
function setUp() external {
c = new CheckBalanceLow();
}
/**
* @notice Fuzz the `check` function and assert that it always returns true
* when the target's balance is smaller than the threshold.
*/
/// @notice Fuzz the `check` function and assert that it always returns true
/// when the target's balance is smaller than the threshold.
function testFuzz_check_succeeds(address _target, uint256 _threshold) external {
CheckBalanceLow.Params memory p = CheckBalanceLow.Params({
target: _target,
......@@ -37,10 +29,8 @@ contract CheckBalanceLowTest is Test {
assertEq(c.check(abi.encode(p)), true);
}
/**
* @notice Fuzz the `check` function and assert that it always returns false
* when the target's balance is larger than the threshold.
*/
/// @notice Fuzz the `check` function and assert that it always returns false
/// when the target's balance is larger than the threshold.
function testFuzz_check_highBalance_fails(address _target, uint256 _threshold) external {
CheckBalanceLow.Params memory p = CheckBalanceLow.Params({
target: _target,
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
......@@ -7,11 +7,9 @@ import {
IGelatoTreasury
} from "../periphery/drippie/dripchecks/CheckGelatoLow.sol";
/**
* @title MockGelatoTreasury
* @notice Mocks the Gelato treasury for testing purposes. Allows arbitrary
* setting of user balances.
*/
/// @title MockGelatoTreasury
/// @notice Mocks the Gelato treasury for testing purposes. Allows arbitrary
/// setting of user balances.
contract MockGelatoTreasury is IGelatoTreasury {
mapping(address => mapping(address => uint256)) private tokenBalances;
......@@ -28,39 +26,27 @@ contract MockGelatoTreasury is IGelatoTreasury {
}
}
/**
* @title CheckGelatoLowTest
* @notice Tests the CheckBalanceHigh contract via fuzzing both the success case
* and the failure case.
*/
/// @title CheckGelatoLowTest
/// @notice Tests the CheckBalanceHigh contract via fuzzing both the success case
/// and the failure case.
contract CheckGelatoLowTest is Test {
/**
* @notice An instance of the CheckGelatoLow contract.
*/
/// @notice An instance of the CheckGelatoLow contract.
CheckGelatoLow c;
/**
* @notice An instance of the MockGelatoTreasury contract.
*/
/// @notice An instance of the MockGelatoTreasury contract.
MockGelatoTreasury gelato;
/**
* @notice The account Gelato uses to represent ether
*/
/// @notice The account Gelato uses to represent ether
address internal constant eth = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/**
* @notice Deploy the `CheckGelatoLow` and `MockGelatoTreasury` contracts.
*/
/// @notice Deploy the `CheckGelatoLow` and `MockGelatoTreasury` contracts.
function setUp() external {
c = new CheckGelatoLow();
gelato = new MockGelatoTreasury();
}
/**
* @notice Fuzz the `check` function and assert that it always returns true
* when the user's balance in the treasury is less than the threshold.
*/
/// @notice Fuzz the `check` function and assert that it always returns true
/// when the user's balance in the treasury is less than the threshold.
function testFuzz_check_succeeds(uint256 _threshold, address _recipient) external {
CheckGelatoLow.Params memory p = CheckGelatoLow.Params({
treasury: address(gelato),
......@@ -73,11 +59,9 @@ contract CheckGelatoLowTest is Test {
assertEq(c.check(abi.encode(p)), true);
}
/**
* @notice Fuzz the `check` function and assert that it always returns false
* when the user's balance in the treasury is greater than or equal
* to the threshold.
*/
/// @notice Fuzz the `check` function and assert that it always returns false
/// when the user's balance in the treasury is greater than or equal
/// to the threshold.
function testFuzz_check_highBalance_fails(uint256 _threshold, address _recipient) external {
CheckGelatoLow.Params memory p = CheckGelatoLow.Params({
treasury: address(gelato),
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
import { CheckTrue } from "../periphery/drippie/dripchecks/CheckTrue.sol";
/**
* @title CheckTrueTest
* @notice Ensures that the CheckTrue DripCheck contract always returns true.
*/
/// @title CheckTrueTest
/// @notice Ensures that the CheckTrue DripCheck contract always returns true.
contract CheckTrueTest is Test {
/**
* @notice An instance of the CheckTrue contract.
*/
/// @notice An instance of the CheckTrue contract.
CheckTrue c;
/**
* @notice Deploy the `CheckTrue` contract.
*/
/// @notice Deploy the `CheckTrue` contract.
function setUp() external {
c = new CheckTrue();
}
/**
* @notice Fuzz the `check` function and assert that it always returns true.
*/
/// @notice Fuzz the `check` function and assert that it always returns true.
function testFuzz_always_true_succeeds(bytes memory input) external {
assertEq(c.check(input), true);
}
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
/* Testing utilities */
// Testing utilities
import { Test, StdUtils } from "forge-std/Test.sol";
import { L2OutputOracle } from "../L1/L2OutputOracle.sol";
import { L2ToL1MessagePasser } from "../L2/L2ToL1MessagePasser.sol";
......@@ -766,9 +766,7 @@ contract ConfigurableCaller {
event WhatHappened(bool success, bytes returndata);
/**
* @notice Call the configured target with the configured payload OR revert.
*/
/// @notice Call the configured target with the configured payload OR revert.
function call() external {
if (doRevert) {
revert("ConfigurableCaller: revert");
......@@ -787,31 +785,23 @@ contract ConfigurableCaller {
}
}
/**
* @notice Set whether or not to have `call` revert.
*/
/// @notice Set whether or not to have `call` revert.
function setDoRevert(bool _doRevert) external {
doRevert = _doRevert;
}
/**
* @notice Set the target for the call made in `call`.
*/
/// @notice Set the target for the call made in `call`.
function setTarget(address _target) external {
target = _target;
}
/**
* @notice Set the payload for the call made in `call`.
*/
/// @notice Set the payload for the call made in `call`.
function setPayload(bytes calldata _payload) external {
payload = _payload;
}
/**
* @notice Fallback function that reverts if `doRevert` is true.
* Otherwise, it does nothing.
*/
/// @notice Fallback function that reverts if `doRevert` is true.
/// Otherwise, it does nothing.
fallback() external {
if (doRevert) {
revert("ConfigurableCaller: revert");
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
......@@ -7,14 +7,12 @@ import { IDripCheck } from "../periphery/drippie/IDripCheck.sol";
import { CheckTrue } from "../periphery/drippie/dripchecks/CheckTrue.sol";
import { SimpleStorage } from "./Helpers.sol";
/**
* @title TestDrippie
* @notice This is a wrapper contract around Drippie used for testing.
* Returning an entire `Drippie.DripState` causes stack too
* deep errors without `--vir-ir` which causes the compile time
* to go up by ~4x. Each of the methods is a simple getter around
* parts of the `DripState`.
*/
/// @title TestDrippie
/// @notice This is a wrapper contract around Drippie used for testing.
/// Returning an entire `Drippie.DripState` causes stack too
/// deep errors without `--vir-ir` which causes the compile time
/// to go up by ~4x. Each of the methods is a simple getter around
/// parts of the `DripState`.
contract TestDrippie is Drippie {
constructor(address owner) Drippie(owner) {}
......@@ -47,58 +45,38 @@ contract TestDrippie is Drippie {
}
}
/**
* @title Drippie_Test
* @notice Test coverage of the Drippie contract.
*/
/// @title Drippie_Test
/// @notice Test coverage of the Drippie contract.
contract Drippie_Test is Test {
/**
* @notice Emitted when a drip is executed.
*/
/// @notice Emitted when a drip is executed.
event DripExecuted(string indexed nameref, string name, address executor, uint256 timestamp);
/**
* @notice Emitted when a drip's status is updated.
*/
/// @notice Emitted when a drip's status is updated.
event DripStatusUpdated(string indexed nameref, string name, Drippie.DripStatus status);
/**
* @notice Emitted when a drip is created.
*/
/// @notice Emitted when a drip is created.
event DripCreated(string indexed nameref, string name, Drippie.DripConfig config);
/**
* @notice Address of the test DripCheck. CheckTrue is deployed
* here so it always returns true.
*/
/// @notice Address of the test DripCheck. CheckTrue is deployed
/// here so it always returns true.
IDripCheck check;
/**
* @notice Address of a SimpleStorage contract. Used to test that
* calls are actually made by Drippie.
*/
/// @notice Address of a SimpleStorage contract. Used to test that
/// calls are actually made by Drippie.
SimpleStorage simpleStorage;
/**
* @notice Address of the Drippie contract.
*/
/// @notice Address of the Drippie contract.
TestDrippie drippie;
/**
* @notice Address of the Drippie owner
*/
/// @notice Address of the Drippie owner
address constant alice = address(0x42);
/**
* @notice The name of the default drip
*/
/// @notice The name of the default drip
string constant dripName = "foo";
/**
* @notice Set up the test suite by deploying a CheckTrue DripCheck.
* This is a mock that always returns true. Alice is the owner
* and also give drippie 1 ether so that it can balance transfer.
*/
/// @notice Set up the test suite by deploying a CheckTrue DripCheck.
/// This is a mock that always returns true. Alice is the owner
/// and also give drippie 1 ether so that it can balance transfer.
function setUp() external {
check = IDripCheck(new CheckTrue());
simpleStorage = new SimpleStorage();
......@@ -107,12 +85,10 @@ contract Drippie_Test is Test {
vm.deal(address(drippie), 1 ether);
}
/**
* @notice Builds a default Drippie.DripConfig. Uses CheckTrue as the
* dripcheck so it will always be able to do its DripActions.
* Gives a dummy DripAction that does a simple transfer to
* a dummy address.
*/
/// @notice Builds a default Drippie.DripConfig. Uses CheckTrue as the
/// dripcheck so it will always be able to do its DripActions.
/// Gives a dummy DripAction that does a simple transfer to
/// a dummy address.
function _defaultConfig() internal view returns (Drippie.DripConfig memory) {
Drippie.DripAction[] memory actions = new Drippie.DripAction[](1);
actions[0] = Drippie.DripAction({ target: payable(address(0x44)), data: hex"", value: 1 });
......@@ -127,9 +103,7 @@ contract Drippie_Test is Test {
});
}
/**
* @notice Creates a default drip using the default drip config.
*/
/// @notice Creates a default drip using the default drip config.
function _createDefaultDrip(string memory name) internal {
address owner = drippie.owner();
Drippie.DripConfig memory cfg = _defaultConfig();
......@@ -137,18 +111,14 @@ contract Drippie_Test is Test {
drippie.create(name, cfg);
}
/**
* @notice Moves the block's timestamp forward so that it is
* possible to execute a drip.
*/
/// @notice Moves the block's timestamp forward so that it is
/// possible to execute a drip.
function _warpToExecutable(string memory name) internal {
Drippie.DripConfig memory config = drippie.dripConfig(name);
vm.warp(config.interval + drippie.dripStateLast(name));
}
/**
* @notice Creates a drip and asserts that it was configured as expected.
*/
/// @notice Creates a drip and asserts that it was configured as expected.
function test_create_succeeds() external {
Drippie.DripConfig memory cfg = _defaultConfig();
vm.expectEmit(true, true, true, true);
......@@ -185,9 +155,7 @@ contract Drippie_Test is Test {
}
}
/**
* @notice Ensures that the same drip cannot be created two times.
*/
/// @notice Ensures that the same drip cannot be created two times.
function test_create_calledTwice_reverts() external {
vm.startPrank(drippie.owner());
Drippie.DripConfig memory cfg = _defaultConfig();
......@@ -197,9 +165,7 @@ contract Drippie_Test is Test {
vm.stopPrank();
}
/**
* @notice Ensures that only the owner of Drippie can create a drip.
*/
/// @notice Ensures that only the owner of Drippie can create a drip.
function testFuzz_owner_unauthorized_reverts(address caller) external {
vm.assume(caller != drippie.owner());
vm.prank(caller);
......@@ -207,9 +173,7 @@ contract Drippie_Test is Test {
drippie.create(dripName, _defaultConfig());
}
/**
* @notice The owner should be able to set the status of the drip.
*/
/// @notice The owner should be able to set the status of the drip.
function test_set_status_succeeds() external {
vm.expectEmit(true, true, true, true);
emit DripCreated(dripName, dripName, _defaultConfig());
......@@ -255,9 +219,7 @@ contract Drippie_Test is Test {
}
}
/**
* @notice The drip status cannot be set back to NONE after it is created.
*/
/// @notice The drip status cannot be set back to NONE after it is created.
function test_set_statusNone_reverts() external {
_createDefaultDrip(dripName);
......@@ -268,10 +230,8 @@ contract Drippie_Test is Test {
drippie.status(dripName, Drippie.DripStatus.NONE);
}
/**
* @notice The owner cannot set the status of the drip to the status that
* it is already set as.
*/
/// @notice The owner cannot set the status of the drip to the status that
/// it is already set as.
function test_set_statusSame_reverts() external {
_createDefaultDrip(dripName);
......@@ -282,10 +242,8 @@ contract Drippie_Test is Test {
drippie.status(dripName, Drippie.DripStatus.PAUSED);
}
/**
* @notice The owner should be able to archive the drip if it is in the
* paused state.
*/
/// @notice The owner should be able to archive the drip if it is in the
/// paused state.
function test_shouldArchive_ifPaused_succeeds() external {
_createDefaultDrip(dripName);
......@@ -306,10 +264,8 @@ contract Drippie_Test is Test {
assertEq(uint256(status), uint256(Drippie.DripStatus.ARCHIVED));
}
/**
* @notice The owner should not be able to archive the drip if it is in the
* active state.
*/
/// @notice The owner should not be able to archive the drip if it is in the
/// active state.
function test_shouldNotArchive_ifActive_reverts() external {
_createDefaultDrip(dripName);
......@@ -323,30 +279,24 @@ contract Drippie_Test is Test {
drippie.status(dripName, Drippie.DripStatus.ARCHIVED);
}
/**
* @notice The owner should not be allowed to pause the drip if it
* has already been archived.
*/
/// @notice The owner should not be allowed to pause the drip if it
/// has already been archived.
function test_shouldNotAllowPaused_ifArchived_reverts() external {
_createDefaultDrip(dripName);
_notAllowFromArchive(dripName, Drippie.DripStatus.PAUSED);
}
/**
* @notice The owner should not be allowed to make the drip active again if
* it has already been archived.
*/
/// @notice The owner should not be allowed to make the drip active again if
/// it has already been archived.
function test_shouldNotAllowActive_ifArchived_reverts() external {
_createDefaultDrip(dripName);
_notAllowFromArchive(dripName, Drippie.DripStatus.ACTIVE);
}
/**
* @notice Archive the drip and then attempt to set the status to the passed
* in status.
*/
/// @notice Archive the drip and then attempt to set the status to the passed
/// in status.
function _notAllowFromArchive(string memory name, Drippie.DripStatus status) internal {
address owner = drippie.owner();
vm.prank(owner);
......@@ -358,9 +308,7 @@ contract Drippie_Test is Test {
drippie.status(name, status);
}
/**
* @notice Attempt to update a drip that does not exist.
*/
/// @notice Attempt to update a drip that does not exist.
function test_name_notExist_reverts() external {
string memory otherName = "bar";
......@@ -373,9 +321,7 @@ contract Drippie_Test is Test {
drippie.status(otherName, Drippie.DripStatus.ARCHIVED);
}
/**
* @notice Expect a revert when attempting to set the status when not the owner.
*/
/// @notice Expect a revert when attempting to set the status when not the owner.
function test_status_unauthorized_reverts() external {
_createDefaultDrip(dripName);
......@@ -383,9 +329,7 @@ contract Drippie_Test is Test {
drippie.status(dripName, Drippie.DripStatus.ACTIVE);
}
/**
* @notice The drip should execute and be able to transfer value.
*/
/// @notice The drip should execute and be able to transfer value.
function test_drip_amount_succeeds() external {
_createDefaultDrip(dripName);
......@@ -415,9 +359,7 @@ contract Drippie_Test is Test {
drippie.drip(dripName);
}
/**
* @notice A single DripAction should be able to make a state modifying call.
*/
/// @notice A single DripAction should be able to make a state modifying call.
function test_trigger_oneFunction_succeeds() external {
Drippie.DripConfig memory cfg = _defaultConfig();
......@@ -452,9 +394,7 @@ contract Drippie_Test is Test {
assertEq(simpleStorage.get(key), value);
}
/**
* @notice Multiple drip actions should be able to be triggered with the same check.
*/
/// @notice Multiple drip actions should be able to be triggered with the same check.
function test_trigger_twoFunctions_succeeds() external {
Drippie.DripConfig memory cfg = _defaultConfig();
Drippie.DripAction[] memory actions = new Drippie.DripAction[](2);
......@@ -511,11 +451,9 @@ contract Drippie_Test is Test {
assertEq(simpleStorage.get(keyTwo), valueTwo);
}
/**
* @notice The drips can only be triggered once per interval. Attempt to
* trigger the same drip multiple times in the same interval. Then
* move forward to the next interval and it should trigger.
*/
/// @notice The drips can only be triggered once per interval. Attempt to
/// trigger the same drip multiple times in the same interval. Then
/// move forward to the next interval and it should trigger.
function test_twice_inOneInterval_reverts() external {
_createDefaultDrip(dripName);
......@@ -547,10 +485,8 @@ contract Drippie_Test is Test {
drippie.drip(dripName);
}
/**
* @notice It should revert if attempting to trigger a drip that does not exist.
* Note that the drip was never created at the beginning of the test.
*/
/// @notice It should revert if attempting to trigger a drip that does not exist.
/// Note that the drip was never created at the beginning of the test.
function test_drip_notExist_reverts() external {
vm.prank(drippie.owner());
......@@ -559,9 +495,7 @@ contract Drippie_Test is Test {
drippie.drip(dripName);
}
/**
* @notice The owner cannot trigger the drip when it is paused.
*/
/// @notice The owner cannot trigger the drip when it is paused.
function test_not_active_reverts() external {
_createDefaultDrip(dripName);
......@@ -575,9 +509,7 @@ contract Drippie_Test is Test {
drippie.drip(dripName);
}
/**
* @notice The interval must be 0 if reentrant is set on the config.
*/
/// @notice The interval must be 0 if reentrant is set on the config.
function test_reentrant_succeeds() external {
address owner = drippie.owner();
Drippie.DripConfig memory cfg = _defaultConfig();
......@@ -594,10 +526,8 @@ contract Drippie_Test is Test {
assertEq(_cfg.interval, 0);
}
/**
* @notice A non zero interval when reentrant is true will cause a revert
* when creating a drip.
*/
/// @notice A non zero interval when reentrant is true will cause a revert
/// when creating a drip.
function test_drip_reentrant_reverts() external {
address owner = drippie.owner();
Drippie.DripConfig memory cfg = _defaultConfig();
......@@ -610,10 +540,8 @@ contract Drippie_Test is Test {
drippie.create(dripName, cfg);
}
/**
* @notice If reentrant is false and the interval is 0 then it should
* revert when the drip is created.
*/
/// @notice If reentrant is false and the interval is 0 then it should
/// revert when the drip is created.
function test_notReentrant_zeroInterval_reverts() external {
address owner = drippie.owner();
Drippie.DripConfig memory cfg = _defaultConfig();
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
......@@ -45,9 +45,7 @@ contract Faucet_Initializer is Test {
_initializeContracts();
}
/**
* @notice Instantiates a Faucet.
*/
/// @notice Instantiates a Faucet.
function _initializeContracts() internal {
faucet = new Faucet(faucetContractAdmin);
......@@ -76,10 +74,7 @@ contract Faucet_Initializer is Test {
vm.stopPrank();
}
/**
* @notice Get signature as a bytes blob.
*
*/
/// @notice Get signature as a bytes blob.
function _getSignature(uint256 _signingPrivateKey, bytes32 _digest)
internal
pure
......@@ -91,11 +86,9 @@ contract Faucet_Initializer is Test {
return signature;
}
/**
* @notice Signs a proof with the given private key and returns the signature using
* the given EIP712 domain separator. This assumes that the issuer's address is the
* corresponding public key to _issuerPrivateKey.
*/
/// @notice Signs a proof with the given private key and returns the signature using
/// the given EIP712 domain separator. This assumes that the issuer's address is the
/// corresponding public key to _issuerPrivateKey.
function issueProofWithEIP712Domain(
uint256 _issuerPrivateKey,
bytes memory _eip712Name,
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol";
......@@ -66,38 +66,27 @@ contract SimpleStorage {
}
}
/**
* Simple helper contract that helps with testing flow and signature for OptimistInviter contract.
* Made this a separate contract instead of including in OptimistInviter.t.sol for reusability.
*/
/// @notice Simple helper contract that helps with testing flow and signature for
/// OptimistInviter contract. Made this a separate contract instead of including
/// in OptimistInviter.t.sol for reusability.
contract OptimistInviterHelper {
/**
* @notice EIP712 typehash for the ClaimableInvite type.
*/
/// @notice EIP712 typehash for the ClaimableInvite type.
bytes32 public constant CLAIMABLE_INVITE_TYPEHASH =
keccak256("ClaimableInvite(address issuer,bytes32 nonce)");
/**
* @notice EIP712 typehash for the EIP712Domain type that is included as part of the signature.
*/
/// @notice EIP712 typehash for the EIP712Domain type that is included as part of the signature.
bytes32 public constant EIP712_DOMAIN_TYPEHASH =
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
/**
* @notice Address of OptimistInviter contract we are testing.
*/
/// @notice Address of OptimistInviter contract we are testing.
OptimistInviter public optimistInviter;
/**
* @notice OptimistInviter contract name. Used to construct the EIP-712 domain.
*/
/// @notice OptimistInviter contract name. Used to construct the EIP-712 domain.
string public name;
/**
* @notice Keeps track of current nonce to generate new nonces for each invite.
*/
/// @notice Keeps track of current nonce to generate new nonces for each invite.
uint256 public currentNonce;
constructor(OptimistInviter _optimistInviter, string memory _name) {
......@@ -105,13 +94,9 @@ contract OptimistInviterHelper {
name = _name;
}
/**
* @notice Returns the hash of the struct ClaimableInvite.
*
* @param _claimableInvite ClaimableInvite struct to hash.
*
* @return EIP-712 typed struct hash.
*/
/// @notice Returns the hash of the struct ClaimableInvite.
/// @param _claimableInvite ClaimableInvite struct to hash.
/// @return EIP-712 typed struct hash.
function getClaimableInviteStructHash(OptimistInviter.ClaimableInvite memory _claimableInvite)
public
pure
......@@ -127,23 +112,16 @@ contract OptimistInviterHelper {
);
}
/**
* @notice Returns a bytes32 nonce that should change everytime. In practice, people should use
* pseudorandom nonces.
*
* @return Nonce that should be used as part of ClaimableInvite.
*/
/// @notice Returns a bytes32 nonce that should change everytime. In practice, people should use
/// pseudorandom nonces.
/// @return Nonce that should be used as part of ClaimableInvite.
function consumeNonce() public returns (bytes32) {
return bytes32(keccak256(abi.encode(currentNonce++)));
}
/**
* @notice Returns a ClaimableInvite with the issuer and current nonce.
*
* @param _issuer Issuer to include in the ClaimableInvite.
*
* @return ClaimableInvite that can be hashed & signed.
*/
/// @notice Returns a ClaimableInvite with the issuer and current nonce.
/// @param _issuer Issuer to include in the ClaimableInvite.
/// @return ClaimableInvite that can be hashed & signed.
function getClaimableInviteWithNewNonce(address _issuer)
public
returns (OptimistInviter.ClaimableInvite memory)
......@@ -151,13 +129,9 @@ contract OptimistInviterHelper {
return OptimistInviter.ClaimableInvite(_issuer, consumeNonce());
}
/**
* @notice Computes the EIP712 digest with default correct parameters.
*
* @param _claimableInvite ClaimableInvite struct to hash.
*
* @return EIP-712 compatible digest.
*/
/// @notice Computes the EIP712 digest with default correct parameters.
/// @param _claimableInvite ClaimableInvite struct to hash.
/// @return EIP-712 compatible digest.
function getDigest(OptimistInviter.ClaimableInvite calldata _claimableInvite)
public
view
......@@ -173,18 +147,14 @@ contract OptimistInviterHelper {
);
}
/**
* @notice Computes the EIP712 digest with the given domain parameters.
* Used for testing that different domain parameters fail.
*
* @param _claimableInvite ClaimableInvite struct to hash.
* @param _name Contract name to use in the EIP712 domain.
* @param _version Contract version to use in the EIP712 domain.
* @param _chainid Chain ID to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
*
* @return EIP-712 compatible digest.
*/
/// @notice Computes the EIP712 digest with the given domain parameters.
/// Used for testing that different domain parameters fail.
/// @param _claimableInvite ClaimableInvite struct to hash.
/// @param _name Contract name to use in the EIP712 domain.
/// @param _version Contract version to use in the EIP712 domain.
/// @param _chainid Chain ID to use in the EIP712 domain.
/// @param _verifyingContract Address to use in the EIP712 domain.
/// @return EIP-712 compatible digest.
function getDigestWithEIP712Domain(
OptimistInviter.ClaimableInvite calldata _claimableInvite,
bytes memory _name,
......@@ -206,11 +176,9 @@ contract OptimistInviterHelper {
}
}
// solhint-disable max-line-length
/**
* Simple ERC1271 wallet that can be used to test the ERC1271 signature checker.
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/mocks/ERC1271WalletMock.sol
*/
/// @notice Simple ERC1271 wallet that can be used to test the ERC1271 signature checker.
/// @notice https://github.com/OpenZeppelin/openzeppelin-contracts/
/// blob/master/contracts/mocks/ERC1271WalletMock.sol
contract TestERC1271Wallet is Ownable, IERC1271 {
constructor(address originalOwner) {
transferOwnership(originalOwner);
......@@ -227,46 +195,31 @@ contract TestERC1271Wallet is Ownable, IERC1271 {
}
}
/**
* Simple helper contract that helps with testing the Faucet contract.
*/
/// @notice Simple helper contract that helps with testing the Faucet contract.
contract FaucetHelper {
/**
* @notice EIP712 typehash for the Proof type.
*/
/// @notice EIP712 typehash for the Proof type.
bytes32 public constant PROOF_TYPEHASH =
keccak256("Proof(address recipient,bytes32 nonce,bytes32 id)");
/**
* @notice EIP712 typehash for the EIP712Domain type that is included as part of the signature.
*/
/// @notice EIP712 typehash for the EIP712Domain type that is included as part of the signature.
bytes32 public constant EIP712_DOMAIN_TYPEHASH =
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
/**
* @notice Keeps track of current nonce to generate new nonces for each drip.
*/
/// @notice Keeps track of current nonce to generate new nonces for each drip.
uint256 public currentNonce;
/**
* @notice Returns a bytes32 nonce that should change everytime. In practice, people should use
* pseudorandom nonces.
*
* @return Nonce that should be used as part of drip parameters.
*/
/// @notice Returns a bytes32 nonce that should change everytime. In practice, people should use
/// pseudorandom nonces.
/// @return Nonce that should be used as part of drip parameters.
function consumeNonce() public returns (bytes32) {
return bytes32(keccak256(abi.encode(currentNonce++)));
}
/**
* @notice Returns the hash of the struct Proof.
*
* @param _proof Proof struct to hash.
*
* @return EIP-712 typed struct hash.
*/
/// @notice Returns the hash of the struct Proof.
/// @param _proof Proof struct to hash.
/// @return EIP-712 typed struct hash.
function getProofStructHash(AdminFaucetAuthModule.Proof memory _proof)
public
pure
......@@ -275,20 +228,16 @@ contract FaucetHelper {
return keccak256(abi.encode(PROOF_TYPEHASH, _proof.recipient, _proof.nonce, _proof.id));
}
/**
* @notice Computes the EIP712 digest with the given domain parameters.
* Used for testing that different domain parameters fail.
*
* @param _proof Proof struct to hash.
* @param _name Contract name to use in the EIP712 domain.
* @param _version Contract version to use in the EIP712 domain.
* @param _chainid Chain ID to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
*
* @return EIP-712 compatible digest.
*/
/// @notice Computes the EIP712 digest with the given domain parameters.
/// Used for testing that different domain parameters fail.
/// @param _proof Proof struct to hash.
/// @param _name Contract name to use in the EIP712 domain.
/// @param _version Contract version to use in the EIP712 domain.
/// @param _chainid Chain ID to use in the EIP712 domain.
/// @param _verifyingContract Address to use in the EIP712 domain.
/// @param _verifyingContract Address to use in the EIP712 domain.
/// @param _verifyingContract Address to use in the EIP712 domain.
/// @return EIP-712 compatible digest.
function getDigestWithEIP712Domain(
AdminFaucetAuthModule.Proof memory _proof,
bytes memory _name,
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.9.0;
/* Testing utilities */
// Testing utilities
import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
import { Optimist } from "../periphery/op-nft/Optimist.sol";
......@@ -67,9 +67,7 @@ contract Optimist_Initializer is Test {
address internal bob;
address internal sally;
/**
* @notice BaseURI attestor sets the baseURI of the Optimist NFT.
*/
/// @notice BaseURI attestor sets the baseURI of the Optimist NFT.
function _attestBaseURI(string memory _baseUri) internal {
bytes32 baseURIAttestationKey = optimist.BASE_URI_ATTESTATION_KEY();
AttestationStation.AttestationData[]
......@@ -91,9 +89,7 @@ contract Optimist_Initializer is Test {
attestationStation.attest(attestationData);
}
/**
* @notice Allowlist attestor creates an attestation for an address.
*/
/// @notice Allowlist attestor creates an attestation for an address.
function _attestAllowlist(address _about) internal {
bytes32 attestationKey = optimistAllowlist.OPTIMIST_CAN_MINT_ATTESTATION_KEY();
AttestationStation.AttestationData[]
......@@ -114,9 +110,7 @@ contract Optimist_Initializer is Test {
assertTrue(optimist.isOnAllowList(_about));
}
/**
* @notice Coinbase Quest attestor creates an attestation for an address.
*/
/// @notice Coinbase Quest attestor creates an attestation for an address.
function _attestCoinbaseQuest(address _about) internal {
bytes32 attestationKey = optimistAllowlist.COINBASE_QUEST_ELIGIBLE_ATTESTATION_KEY();
AttestationStation.AttestationData[]
......@@ -137,9 +131,7 @@ contract Optimist_Initializer is Test {
assertTrue(optimist.isOnAllowList(_about));
}
/**
* @notice Issues invite, then claims it using the claimer's address.
*/
/// @notice Issues invite, then claims it using the claimer's address.
function _inviteAndClaim(address _about) internal {
uint256 inviterPrivateKey = 0xbeefbeef;
address inviter = vm.addr(inviterPrivateKey);
......@@ -179,9 +171,7 @@ contract Optimist_Initializer is Test {
assertTrue(optimist.isOnAllowList(_about));
}
/**
* @notice Mocks the allowlistAttestor to always return true for a given address.
*/
/// @notice Mocks the allowlistAttestor to always return true for a given address.
function _mockAllowlistTrueFor(address _claimer) internal {
vm.mockCall(
address(optimistAllowlist),
......@@ -192,9 +182,7 @@ contract Optimist_Initializer is Test {
assertTrue(optimist.isOnAllowList(_claimer));
}
/**
* @notice Returns address as uint256.
*/
/// @notice Returns address as uint256.
function _getTokenId(address _owner) internal pure returns (uint256) {
return uint256(uint160(address(_owner)));
}
......@@ -245,9 +233,7 @@ contract Optimist_Initializer is Test {
}
contract OptimistTest is Optimist_Initializer {
/**
* @notice Check that constructor and initializer parameters are correctly set.
*/
/// @notice Check that constructor and initializer parameters are correctly set.
function test_initialize_succeeds() external {
// expect name to be set
assertEq(optimist.name(), name);
......@@ -259,10 +245,8 @@ contract OptimistTest is Optimist_Initializer {
assertEq(optimist.version(), "2.0.0");
}
/**
* @notice Bob should be able to mint an NFT if he is allowlisted
* by the allowlistAttestor and has a balance of 0.
*/
/// @notice Bob should be able to mint an NFT if he is allowlisted
/// by the allowlistAttestor and has a balance of 0.
function test_mint_afterAllowlistAttestation_succeeds() external {
// bob should start with 0 balance
assertEq(optimist.balanceOf(bob), 0);
......@@ -287,10 +271,8 @@ contract OptimistTest is Optimist_Initializer {
assertEq(optimist.balanceOf(bob), 1);
}
/**
* @notice Bob should be able to mint an NFT if he claimed an invite through OptimistInviter
* and has a balance of 0.
*/
/// @notice Bob should be able to mint an NFT if he claimed an invite through OptimistInviter
/// and has a balance of 0.
function test_mint_afterInviteClaimed_succeeds() external {
// bob should start with 0 balance
assertEq(optimist.balanceOf(bob), 0);
......@@ -315,10 +297,8 @@ contract OptimistTest is Optimist_Initializer {
assertEq(optimist.balanceOf(bob), 1);
}
/**
* @notice Bob should be able to mint an NFT if he has an attestation from Coinbase Quest
* attestor and has a balance of 0.
*/
/// @notice Bob should be able to mint an NFT if he has an attestation from Coinbase Quest
/// attestor and has a balance of 0.
function test_mint_afterCoinbaseQuestAttestation_succeeds() external {
// bob should start with 0 balance
assertEq(optimist.balanceOf(bob), 0);
......@@ -343,9 +323,7 @@ contract OptimistTest is Optimist_Initializer {
assertEq(optimist.balanceOf(bob), 1);
}
/**
* @notice Multiple valid attestations should allow Bob to mint.
*/
/// @notice Multiple valid attestations should allow Bob to mint.
function test_mint_afterMultipleAttestations_succeeds() external {
// bob should start with 0 balance
assertEq(optimist.balanceOf(bob), 0);
......@@ -376,9 +354,7 @@ contract OptimistTest is Optimist_Initializer {
assertEq(optimist.balanceOf(bob), 1);
}
/**
* @notice Sally should be able to mint a token on behalf of bob.
*/
/// @notice Sally should be able to mint a token on behalf of bob.
function test_mint_secondaryMinter_succeeds() external {
_mockAllowlistTrueFor(bob);
......@@ -394,18 +370,14 @@ contract OptimistTest is Optimist_Initializer {
assertEq(optimist.balanceOf(bob), 1);
}
/**
* @notice Bob should not be able to mint an NFT if he is not allowlisted.
*/
/// @notice Bob should not be able to mint an NFT if he is not allowlisted.
function test_mint_forNonAllowlistedClaimer_reverts() external {
vm.prank(bob);
vm.expectRevert("Optimist: address is not on allowList");
optimist.mint(bob);
}
/**
* @notice Bob's tx should revert if he already minted.
*/
/// @notice Bob's tx should revert if he already minted.
function test_mint_forAlreadyMintedClaimer_reverts() external {
_attestAllowlist(bob);
......@@ -421,9 +393,7 @@ contract OptimistTest is Optimist_Initializer {
optimist.mint(bob);
}
/**
* @notice The baseURI should be set by attestation station by the baseURIAttestor.
*/
/// @notice The baseURI should be set by attestation station by the baseURIAttestor.
function test_baseURI_returnsCorrectBaseURI_succeeds() external {
_attestBaseURI(base_uri);
......@@ -440,9 +410,7 @@ contract OptimistTest is Optimist_Initializer {
assertEq(optimist.baseURI(), base_uri);
}
/**
* @notice tokenURI should return the token uri for a minted token.
*/
/// @notice tokenURI should return the token uri for a minted token.
function test_tokenURI_returnsCorrectTokenURI_succeeds() external {
// we are using true but it can be any non empty value
_attestBaseURI(base_uri);
......@@ -460,9 +428,7 @@ contract OptimistTest is Optimist_Initializer {
);
}
/**
* @notice Should return the token id of the owner.
*/
/// @notice Should return the token id of the owner.
function test_tokenIdOfAddress_returnsOwnerID_succeeds() external {
uint256 willTokenId = 1024;
address will = address(1024);
......@@ -474,9 +440,7 @@ contract OptimistTest is Optimist_Initializer {
assertEq(optimist.tokenIdOfAddress(will), willTokenId);
}
/**
* @notice transferFrom should revert since Optimist is a SBT.
*/
/// @notice transferFrom should revert since Optimist is a SBT.
function test_transferFrom_soulbound_reverts() external {
_mockAllowlistTrueFor(bob);
......@@ -499,9 +463,7 @@ contract OptimistTest is Optimist_Initializer {
optimist.safeTransferFrom(bob, sally, _getTokenId(bob), bytes("0x"));
}
/**
* @notice approve should revert since Optimist is a SBT.
*/
/// @notice approve should revert since Optimist is a SBT.
function test_approve_soulbound_reverts() external {
_mockAllowlistTrueFor(bob);
......@@ -517,9 +479,7 @@ contract OptimistTest is Optimist_Initializer {
assertEq(optimist.getApproved(_getTokenId(bob)), address(0));
}
/**
* @notice setApprovalForAll should revert since Optimist is a SBT.
*/
/// @notice setApprovalForAll should revert since Optimist is a SBT.
function test_setApprovalForAll_soulbound_reverts() external {
_mockAllowlistTrueFor(bob);
......@@ -539,9 +499,7 @@ contract OptimistTest is Optimist_Initializer {
);
}
/**
* @notice Only owner should be able to burn token.
*/
/// @notice Only owner should be able to burn token.
function test_burn_byOwner_succeeds() external {
_mockAllowlistTrueFor(bob);
......@@ -557,9 +515,7 @@ contract OptimistTest is Optimist_Initializer {
assertEq(optimist.balanceOf(bob), 0);
}
/**
* @notice Non-owner attempting to burn token should revert.
*/
/// @notice Non-owner attempting to burn token should revert.
function test_burn_byNonOwner_reverts() external {
_mockAllowlistTrueFor(bob);
......@@ -576,20 +532,16 @@ contract OptimistTest is Optimist_Initializer {
assertEq(optimist.balanceOf(bob), 1);
}
/**
* @notice Should support ERC-721 interface.
*/
/// @notice Should support ERC-721 interface.
function test_supportsInterface_returnsCorrectInterfaceForERC721_succeeds() external {
bytes4 iface721 = type(IERC721).interfaceId;
// check that it supports ERC-721 interface
assertEq(optimist.supportsInterface(iface721), true);
}
/**
* @notice Checking that multi-call using the invite & claim flow works correctly, since the
* frontend will be making multicalls to improve UX. The OptimistInviter.claimInvite
* and Optimist.mint will be batched
*/
/// @notice Checking that multi-call using the invite & claim flow works correctly, since the
/// frontend will be making multicalls to improve UX. The OptimistInviter.claimInvite
/// and Optimist.mint will be batched
function test_multicall_batchingClaimAndMint_succeeds() external {
uint256 inviterPrivateKey = 0xbeefbeef;
address inviter = vm.addr(inviterPrivateKey);
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
/* Testing utilities */
// Testing utilities
import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
import { OptimistAllowlist } from "../periphery/op-nft/OptimistAllowlist.sol";
......@@ -106,10 +106,7 @@ contract OptimistAllowlist_Initializer is Test {
optimistInviter.claimInvite(claimer, claimableInvite, signature);
}
/**
* @notice Get signature as a bytes blob, since SignatureChecker takes arbitrary signature blobs.
*
*/
/// @notice Get signature as a bytes blob, since SignatureChecker takes arbitrary signature blobs.
function _getSignature(uint256 _signingPrivateKey, bytes32 _digest)
internal
pure
......@@ -149,42 +146,32 @@ contract OptimistAllowlistTest is OptimistAllowlist_Initializer {
assertEq(optimistAllowlist.version(), "1.0.0");
}
/**
* @notice Base case, a account without any relevant attestations should not be able to mint.
*/
/// @notice Base case, a account without any relevant attestations should not be able to mint.
function test_isAllowedToMint_withoutAnyAttestations_fails() external {
assertFalse(optimistAllowlist.isAllowedToMint(bob));
}
/**
* @notice After receiving a valid allowlist attestation, the account should be able to mint.
*/
/// @notice After receiving a valid allowlist attestation, the account should be able to mint.
function test_isAllowedToMint_fromAllowlistAttestor_succeeds() external {
attestAllowlist(bob);
assertTrue(optimistAllowlist.isAllowedToMint(bob));
}
/**
* @notice After receiving a valid attestation from the Coinbase Quest attestor,
* the account should be able to mint.
*/
/// @notice After receiving a valid attestation from the Coinbase Quest attestor,
/// the account should be able to mint.
function test_isAllowedToMint_fromCoinbaseQuestAttestor_succeeds() external {
attestCoinbaseQuest(bob);
assertTrue(optimistAllowlist.isAllowedToMint(bob));
}
/**
* @notice Account that received an attestation from the OptimistInviter contract by going
* through the claim invite flow should be able to mint.
*/
/// @notice Account that received an attestation from the OptimistInviter contract by going
/// through the claim invite flow should be able to mint.
function test_isAllowedToMint_fromInvite_succeeds() external {
inviteAndClaim(bob);
assertTrue(optimistAllowlist.isAllowedToMint(bob));
}
/**
* @notice Attestation from the wrong allowlist attestor should not allow minting.
*/
/// @notice Attestation from the wrong allowlist attestor should not allow minting.
function test_isAllowedToMint_fromWrongAllowlistAttestor_fails() external {
// Ted is not the allowlist attestor
vm.prank(ted);
......@@ -196,9 +183,7 @@ contract OptimistAllowlistTest is OptimistAllowlist_Initializer {
assertFalse(optimistAllowlist.isAllowedToMint(bob));
}
/**
* @notice Coinbase quest attestation from wrong attestor should not allow minting.
*/
/// @notice Coinbase quest attestation from wrong attestor should not allow minting.
function test_isAllowedToMint_fromWrongCoinbaseQuestAttestor_fails() external {
// Ted is not the coinbase quest attestor
vm.prank(ted);
......@@ -210,10 +195,8 @@ contract OptimistAllowlistTest is OptimistAllowlist_Initializer {
assertFalse(optimistAllowlist.isAllowedToMint(bob));
}
/**
* @notice Claiming an invite on the non-official OptimistInviter contract should not allow
* minting.
*/
/// @notice Claiming an invite on the non-official OptimistInviter contract should not allow
/// minting.
function test_isAllowedToMint_fromWrongOptimistInviter_fails() external {
vm.prank(ted);
attestationStation.attest(
......@@ -224,9 +207,7 @@ contract OptimistAllowlistTest is OptimistAllowlist_Initializer {
assertFalse(optimistAllowlist.isAllowedToMint(bob));
}
/**
* @notice Having multiple signals, even if one is invalid, should still allow minting.
*/
/// @notice Having multiple signals, even if one is invalid, should still allow minting.
function test_isAllowedToMint_withMultipleAttestations_succeeds() external {
attestAllowlist(bob);
attestCoinbaseQuest(bob);
......@@ -246,9 +227,7 @@ contract OptimistAllowlistTest is OptimistAllowlist_Initializer {
assertTrue(optimistAllowlist.isAllowedToMint(bob));
}
/**
* @notice Having falsy attestation value should not allow minting.
*/
/// @notice Having falsy attestation value should not allow minting.
function test_isAllowedToMint_fromAllowlistAttestorWithFalsyValue_fails() external {
// First sends correct attestation
attestAllowlist(bob);
......@@ -264,9 +243,7 @@ contract OptimistAllowlistTest is OptimistAllowlist_Initializer {
assertFalse(optimistAllowlist.isAllowedToMint(bob));
}
/**
* @notice Having falsy attestation value from Coinbase attestor should not allow minting.
*/
/// @notice Having falsy attestation value from Coinbase attestor should not allow minting.
function test_isAllowedToMint_fromCoinbaseQuestAttestorWithFalsyValue_fails() external {
// First sends correct attestation
attestAllowlist(bob);
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
/* Testing utilities */
// Testing utilities
import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
import { OptimistInviter } from "../periphery/op-nft/OptimistInviter.sol";
......@@ -69,9 +69,7 @@ contract OptimistInviter_Initializer is Test {
_initializeContracts();
}
/**
* @notice Instantiates an AttestationStation, and an OptimistInviter.
*/
/// @notice Instantiates an AttestationStation, and an OptimistInviter.
function _initializeContracts() internal {
attestationStation = new AttestationStation();
......@@ -88,16 +86,12 @@ contract OptimistInviter_Initializer is Test {
vm.warp(optimistInviter.MIN_COMMITMENT_PERIOD() + block.timestamp);
}
/**
* @notice Returns a user's current invite count, as stored in the AttestationStation.
*/
/// @notice Returns a user's current invite count, as stored in the AttestationStation.
function _getInviteCount(address _issuer) internal view returns (uint256) {
return optimistInviter.inviteCounts(_issuer);
}
/**
* @notice Returns true if claimer has the proper attestation from OptimistInviter to mint.
*/
/// @notice Returns true if claimer has the proper attestation from OptimistInviter to mint.
function _hasMintAttestation(address _claimer) internal view returns (bool) {
bytes memory attestation = attestationStation.attestations(
address(optimistInviter),
......@@ -107,10 +101,7 @@ contract OptimistInviter_Initializer is Test {
return attestation.length > 0;
}
/**
* @notice Get signature as a bytes blob, since SignatureChecker takes arbitrary signature blobs.
*
*/
/// @notice Get signature as a bytes blob, since SignatureChecker takes arbitrary signature blobs.
function _getSignature(uint256 _signingPrivateKey, bytes32 _digest)
internal
pure
......@@ -122,10 +113,8 @@ contract OptimistInviter_Initializer is Test {
return signature;
}
/**
* @notice Signs a claimable invite with the given private key and returns the signature using
* correct EIP712 domain separator.
*/
/// @notice Signs a claimable invite with the given private key and returns the signature using
/// correct EIP712 domain separator.
function _issueInviteAs(uint256 _privateKey)
internal
returns (OptimistInviter.ClaimableInvite memory, bytes memory)
......@@ -140,11 +129,9 @@ contract OptimistInviter_Initializer is Test {
);
}
/**
* @notice Signs a claimable invite with the given private key and returns the signature using
* the given EIP712 domain separator. This assumes that the issuer's address is the
* corresponding public key to _issuerPrivateKey.
*/
/// @notice Signs a claimable invite with the given private key and returns the signature using
/// the given EIP712 domain separator. This assumes that the issuer's address is the
/// corresponding public key to _issuerPrivateKey.
function _issueInviteWithEIP712Domain(
uint256 _issuerPrivateKey,
bytes memory _eip712Name,
......@@ -170,9 +157,7 @@ contract OptimistInviter_Initializer is Test {
);
}
/**
* @notice Commits a signature and claimer address to the OptimistInviter contract.
*/
/// @notice Commits a signature and claimer address to the OptimistInviter contract.
function _commitInviteAs(address _as, bytes memory _signature) internal {
vm.prank(_as);
bytes32 hashedSignature = keccak256(abi.encode(_as, _signature));
......@@ -182,11 +167,9 @@ contract OptimistInviter_Initializer is Test {
assertEq(optimistInviter.commitmentTimestamps(hashedSignature), block.timestamp);
}
/**
* @notice Signs a claimable invite with the given private key. The claimer commits then claims
* the invite. Checks that all expected events are emitted and that state is updated
* correctly. Returns the signature and invite for use in tests.
*/
/// @notice Signs a claimable invite with the given private key. The claimer commits then claims
/// the invite. Checks that all expected events are emitted and that state is updated
/// correctly. Returns the signature and invite for use in tests.
function _issueThenClaimShouldSucceed(uint256 _issuerPrivateKey, address _claimer)
internal
returns (OptimistInviter.ClaimableInvite memory, bytes memory)
......@@ -236,10 +219,8 @@ contract OptimistInviter_Initializer is Test {
return (claimableInvite, signature);
}
/**
* @notice Issues 3 invites to the given address. Checks that all expected events are emitted
* and that state is updated correctly.
*/
/// @notice Issues 3 invites to the given address. Checks that all expected events are emitted
/// and that state is updated correctly.
function _grantInvitesTo(address _to) internal {
address[] memory addresses = new address[](1);
addresses[0] = _to;
......@@ -267,11 +248,9 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
assertEq(optimistInviter.version(), "1.0.0");
}
/**
* @notice Alice the admin should be able to give Bob, Sally, and Carol 3 invites, and the
* OptimistInviter contract should increment invite counts on inviteCounts and issue
* 'optimist.can-invite' attestations.
*/
/// @notice Alice the admin should be able to give Bob, Sally, and Carol 3 invites, and the
/// OptimistInviter contract should increment invite counts on inviteCounts and issue
/// 'optimist.can-invite' attestations.
function test_grantInvites_adminAddingInvites_succeeds() external {
address[] memory addresses = new address[](3);
addresses[0] = bob;
......@@ -310,9 +289,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
assertEq(_getInviteCount(address(carolERC1271Wallet)), 3);
}
/**
* @notice Bob, who is not the invite granter, should not be able to issue invites.
*/
/// @notice Bob, who is not the invite granter, should not be able to issue invites.
function test_grantInvites_nonAdminAddingInvites_reverts() external {
address[] memory addresses = new address[](2);
addresses[0] = bob;
......@@ -323,9 +300,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
optimistInviter.setInviteCounts(addresses, 3);
}
/**
* @notice Sally should be able to commit an invite given by by Bob.
*/
/// @notice Sally should be able to commit an invite given by by Bob.
function test_commitInvite_committingForYourself_succeeds() external {
_grantInvitesTo(bob);
(, bytes memory signature) = _issueInviteAs(bobPrivateKey);
......@@ -337,9 +312,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
assertEq(optimistInviter.commitmentTimestamps(hashedSignature), block.timestamp);
}
/**
* @notice Sally should be able to Bob's for a different claimer, Eve.
*/
/// @notice Sally should be able to Bob's for a different claimer, Eve.
function test_commitInvite_committingForSomeoneElse_succeeds() external {
_grantInvitesTo(bob);
(, bytes memory signature) = _issueInviteAs(bobPrivateKey);
......@@ -351,9 +324,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
assertEq(optimistInviter.commitmentTimestamps(hashedSignature), block.timestamp);
}
/**
* @notice Attempting to commit the same hash twice should revert. This prevents griefing.
*/
/// @notice Attempting to commit the same hash twice should revert. This prevents griefing.
function test_commitInvite_committingSameHashTwice_reverts() external {
_grantInvitesTo(bob);
(, bytes memory signature) = _issueInviteAs(bobPrivateKey);
......@@ -368,18 +339,14 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
optimistInviter.commitInvite(hashedSignature);
}
/**
* @notice Bob issues signature, and Sally claims the invite. Bob's invite count should be
* decremented, and Sally should be able to mint.
*/
/// @notice Bob issues signature, and Sally claims the invite. Bob's invite count should be
/// decremented, and Sally should be able to mint.
function test_claimInvite_succeeds() external {
_grantInvitesTo(bob);
_issueThenClaimShouldSucceed(bobPrivateKey, sally);
}
/**
* @notice Bob issues signature, and Ted commits the invite for Sally. Eve claims for Sally.
*/
/// @notice Bob issues signature, and Ted commits the invite for Sally. Eve claims for Sally.
function test_claimInvite_claimForSomeoneElse_succeeds() external {
_grantInvitesTo(bob);
(
......@@ -428,9 +395,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
optimistInviter.claimInvite(sally, claimableInvite, signature);
}
/**
* @notice Signature issued for previous versions of the contract should fail.
*/
/// @notice Signature issued for previous versions of the contract should fail.
function test_claimInvite_usingSignatureIssuedForDifferentVersion_reverts() external {
_grantInvitesTo(bob);
(
......@@ -452,10 +417,8 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
optimistInviter.claimInvite(sally, claimableInvite, signature);
}
/**
* @notice Replay attack for signature issued for contract on different chain (ie. mainnet)
* should fail.
*/
/// @notice Replay attack for signature issued for contract on different chain (ie. mainnet)
/// should fail.
function test_claimInvite_usingSignatureIssuedForDifferentChain_reverts() external {
_grantInvitesTo(bob);
(
......@@ -477,10 +440,8 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
optimistInviter.claimInvite(sally, claimableInvite, signature);
}
/**
* @notice Replay attack for signature issued for instantiation of the OptimistInviter contract
* on a different address should fail.
*/
/// @notice Replay attack for signature issued for instantiation of the OptimistInviter contract
/// on a different address should fail.
function test_claimInvite_usingSignatureIssuedForDifferentContract_reverts() external {
_grantInvitesTo(bob);
(
......@@ -502,9 +463,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
optimistInviter.claimInvite(sally, claimableInvite, signature);
}
/**
* @notice Attempting to claim again using the same signature again should fail.
*/
/// @notice Attempting to claim again using the same signature again should fail.
function test_claimInvite_replayingUsedNonce_reverts() external {
_grantInvitesTo(bob);
......@@ -527,11 +486,9 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
optimistInviter.claimInvite(carol, claimableInvite, signature);
}
/**
* @notice Issuing signatures through a contract that implements ERC1271 should succeed (ie.
* Gnosis Safe or other smart contract wallets). Carol is using a ERC1271 contract
* wallet that is simply backed by her private key.
*/
/// @notice Issuing signatures through a contract that implements ERC1271 should succeed (ie.
/// Gnosis Safe or other smart contract wallets). Carol is using a ERC1271 contract
/// wallet that is simply backed by her private key.
function test_claimInvite_usingERC1271Wallet_succeeds() external {
_grantInvitesTo(address(carolERC1271Wallet));
......@@ -560,10 +517,8 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
assertEq(_getInviteCount(address(carolERC1271Wallet)), 2);
}
/**
* @notice Claimer must commit the signature before claiming the invite. Sally attempts to
* claim the Bob's invite without committing the signature first.
*/
/// @notice Claimer must commit the signature before claiming the invite. Sally attempts to
/// claim the Bob's invite without committing the signature first.
function test_claimInvite_withoutCommittingHash_reverts() external {
_grantInvitesTo(bob);
(
......@@ -576,9 +531,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
optimistInviter.claimInvite(sally, claimableInvite, signature);
}
/**
* @notice Using a signature that doesn't correspond to the claimable invite should fail.
*/
/// @notice Using a signature that doesn't correspond to the claimable invite should fail.
function test_claimInvite_withIncorrectSignature_reverts() external {
_grantInvitesTo(carol);
_grantInvitesTo(bob);
......@@ -598,10 +551,8 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
optimistInviter.claimInvite(sally, bobClaimableInvite, carolSignature);
}
/**
* @notice Attempting to use a signature from a issuer who never was granted invites should
* fail.
*/
/// @notice Attempting to use a signature from a issuer who never was granted invites should
/// fail.
function test_claimInvite_whenIssuerNeverReceivedInvites_reverts() external {
// Bob was never granted any invites, but issues an invite for Eve
(
......@@ -617,13 +568,10 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
optimistInviter.claimInvite(sally, claimableInvite, signature);
}
/**
* @notice Attempting to use a signature from a issuer who has no more invites should fail.
* Bob has 3 invites, but issues 4 invites for Sally, Carol, Ted, and Eve. Only the
* first 3 invites should be claimable. The last claimer, Eve, should not be able to
* claim the invite.
*
*/
/// @notice Attempting to use a signature from a issuer who has no more invites should fail.
/// Bob has 3 invites, but issues 4 invites for Sally, Carol, Ted, and Eve. Only the
/// first 3 invites should be claimable. The last claimer, Eve, should not be able to
/// claim the invite.
function test_claimInvite_whenIssuerHasNoInvitesLeft_reverts() external {
_grantInvitesTo(bob);
......
......@@ -3,10 +3,8 @@ pragma solidity ^0.8.0;
import { Bytes32AddressLib } from "@rari-capital/solmate/src/utils/Bytes32AddressLib.sol";
/**
* @title LibRLP
* @notice Via https://github.com/Rari-Capital/solmate/issues/207.
*/
/// @title LibRLP
/// @notice Via https://github.com/Rari-Capital/solmate/issues/207.
library LibRLP {
using Bytes32AddressLib for bytes32;
......
//SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
/* Testing utilities */
// Testing utilities
import { Test } from "forge-std/Test.sol";
import { CallRecorder } from "./Helpers.sol";
import { Reverter } from "./Helpers.sol";
......@@ -34,12 +34,12 @@ contract Transactor_Initializer is Test {
}
contract TransactorTest is Transactor_Initializer {
// Tests if the owner was set correctly during deploy
/// @notice Tests if the owner was set correctly during deploy
function test_constructor_succeeds() external {
assertEq(address(alice), transactor.owner());
}
// Tests CALL, should do a call to target
/// @notice Tests CALL, should do a call to target
function test_call_succeeds() external {
// Initialize call data
bytes memory data = abi.encodeWithSelector(callRecorded.record.selector);
......@@ -49,7 +49,7 @@ contract TransactorTest is Transactor_Initializer {
transactor.CALL(address(callRecorded), data, 200_000 wei);
}
// It should revert if called by non-owner
/// @notice It should revert if called by non-owner
function test_call_unauthorized_reverts() external {
// Initialize call data
bytes memory data = abi.encodeWithSelector(callRecorded.record.selector);
......@@ -59,6 +59,7 @@ contract TransactorTest is Transactor_Initializer {
transactor.CALL(address(callRecorded), data, 200_000 wei);
}
/// @notice Deletate call succeeds.
function test_delegateCall_succeeds() external {
// Initialize call data
bytes memory data = abi.encodeWithSelector(reverter.doRevert.selector);
......@@ -68,7 +69,7 @@ contract TransactorTest is Transactor_Initializer {
transactor.DELEGATECALL(address(reverter), data);
}
// It should revert if called by non-owner
/// @notice It should revert if called by non-owner
function test_delegateCall_unauthorized_reverts() external {
// Initialize call data
bytes memory data = abi.encodeWithSelector(reverter.doRevert.selector);
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
......@@ -7,9 +8,7 @@ import { AddressAliasHelper } from "../../vendor/AddressAliasHelper.sol";
contract AddressAliasHelper_Converter {
bool public failedRoundtrip;
/**
* @dev Allows the actor to convert L1 to L2 addresses and vice versa.
*/
/// @dev Allows the actor to convert L1 to L2 addresses and vice versa.
function convertRoundTrip(address addr) external {
// Alias our address
address aliasedAddr = AddressAliasHelper.applyL1ToL2Alias(addr);
......@@ -39,12 +38,11 @@ contract AddressAliasHelper_AddressAliasing_Invariant is StdInvariant, Test {
targetSelector(selector);
}
/**
* @custom:invariant Address aliases are always able to be undone.
*
* Asserts that an address that has been aliased with `applyL1ToL2Alias` can always
* be unaliased with `undoL1ToL2Alias`.
*/
/// @custom:invariant Address aliases are always able to be undone.
///
/// Asserts that an address that has been aliased with
/// `applyL1ToL2Alias` can always be unaliased with
/// `undoL1ToL2Alias`.
function invariant_round_trip_aliasing() external {
// ASSERTION: The round trip aliasing done in testRoundTrip(...) should never fail.
assertEq(actor.failedRoundtrip(), false);
......
......@@ -16,10 +16,8 @@ contract Burn_EthBurner is StdUtils {
vm = _vm;
}
/**
* @notice Takes an integer amount of eth to burn through the Burn library and
* updates the contract state if an incorrect amount of eth moved from the contract
*/
/// @notice Takes an integer amount of eth to burn through the Burn library and
/// updates the contract state if an incorrect amount of eth moved from the contract
function burnEth(uint256 _value) external {
uint256 preBurnvalue = bound(_value, 0, type(uint128).max);
......@@ -59,12 +57,10 @@ contract Burn_BurnEth_Invariant is StdInvariant, Test {
targetSelector(selector);
}
/**
* @custom:invariant `eth(uint256)` always burns the exact amount of eth passed.
*
* Asserts that when `Burn.eth(uint256)` is called, it always burns the exact amount
* of ETH passed to the function.
*/
/// @custom:invariant `eth(uint256)` always burns the exact amount of eth passed.
///
/// Asserts that when `Burn.eth(uint256)` is called, it always
/// burns the exact amount of ETH passed to the function.
function invariant_burn_eth() external {
// ASSERTION: The amount burned should always match the amount passed exactly
assertEq(actor.failedEthBurn(), false);
......
......@@ -16,11 +16,9 @@ contract Burn_GasBurner is StdUtils {
vm = _vm;
}
/**
* @notice Takes an integer amount of gas to burn through the Burn library and
* updates the contract state if at least that amount of gas was not burned
* by the library
*/
/// @notice Takes an integer amount of gas to burn through the Burn library and
/// updates the contract state if at least that amount of gas was not burned
/// by the library
function burnGas(uint256 _value) external {
// cap the value to the max resource limit
uint256 MAX_RESOURCE_LIMIT = 8_000_000;
......@@ -59,12 +57,10 @@ contract Burn_BurnGas_Invariant is StdInvariant, Test {
targetSelector(selector);
}
/**
* @custom:invariant `gas(uint256)` always burns at least the amount of gas passed.
*
* Asserts that when `Burn.gas(uint256)` is called, it always burns at least the amount
* of gas passed to the function.
*/
/// @custom:invariant `gas(uint256)` always burns at least the amount of gas passed.
///
/// Asserts that when `Burn.gas(uint256)` is called, it always burns
/// at least the amount of gas passed to the function.
function invariant_burn_gas() external {
// ASSERTION: The amount burned should always match the amount passed exactly
assertEq(actor.failedGasBurn(), false);
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { StdUtils } from "forge-std/StdUtils.sol";
......@@ -36,9 +37,8 @@ contract RelayActor is StdUtils {
doFail = _doFail;
}
/**
* Relays a message to the `L1CrossDomainMessenger` with a random `version`, and `_message`.
*/
/// @notice Relays a message to the `L1CrossDomainMessenger` with a random `version`,
/// and `_message`.
function relay(
uint8 _version,
uint8 _value,
......@@ -143,21 +143,19 @@ contract XDM_MinGasLimits_Succeeds is XDM_MinGasLimits {
super.init(false);
}
/**
* @custom:invariant A call to `relayMessage` should succeed if at least the minimum gas limit
* can be supplied to the target context, there is enough gas to complete
* execution of `relayMessage` after the target context's execution is
* finished, and the target context did not revert.
*
* There are two minimum gas limits here:
*
* - The outer min gas limit is for the call from the `OptimismPortal` to the
* `L1CrossDomainMessenger`, and it can be retrieved by calling the xdm's `baseGas` function
* with the `message` and inner limit.
*
* - The inner min gas limit is for the call from the `L1CrossDomainMessenger` to the target
* contract.
*/
/// @custom:invariant A call to `relayMessage` should succeed if at least the minimum gas limit
/// can be supplied to the target context, there is enough gas to complete
/// execution of `relayMessage` after the target context's execution is
/// finished, and the target context did not revert.
///
/// There are two minimum gas limits here:
///
/// - The outer min gas limit is for the call from the `OptimismPortal` to the
/// `L1CrossDomainMessenger`, and it can be retrieved by calling the xdm's
/// `baseGas` function with the `message` and inner limit.
///
/// - The inner min gas limit is for the call from the
/// `L1CrossDomainMessenger` to the target contract.
function invariant_minGasLimits() external {
uint256 length = actor.numHashes();
for (uint256 i = 0; i < length; ++i) {
......@@ -177,22 +175,20 @@ contract XDM_MinGasLimits_Reverts is XDM_MinGasLimits {
super.init(true);
}
/**
* @custom:invariant A call to `relayMessage` should assign the message hash to the
* `failedMessages` mapping if not enough gas is supplied to forward
* `minGasLimit` to the target context or if there is not enough gas to
* complete execution of `relayMessage` after the target context's execution
* is finished.
*
* There are two minimum gas limits here:
*
* - The outer min gas limit is for the call from the `OptimismPortal` to the
* `L1CrossDomainMessenger`, and it can be retrieved by calling the xdm's `baseGas` function
* with the `message` and inner limit.
*
* - The inner min gas limit is for the call from the `L1CrossDomainMessenger` to the target
* contract.
*/
/// @custom:invariant A call to `relayMessage` should assign the message hash to the
/// `failedMessages` mapping if not enough gas is supplied to forward
/// `minGasLimit` to the target context or if there is not enough gas to
/// complete execution of `relayMessage` after the target context's execution
/// is finished.
///
/// There are two minimum gas limits here:
///
/// - The outer min gas limit is for the call from the `OptimismPortal` to the
/// `L1CrossDomainMessenger`, and it can be retrieved by calling the xdm's
/// `baseGas` function with the `message` and inner limit.
///
/// - The inner min gas limit is for the call from the
/// `L1CrossDomainMessenger` to the target contract.
function invariant_minGasLimits() external {
uint256 length = actor.numHashes();
for (uint256 i = 0; i < length; ++i) {
......
......@@ -9,11 +9,9 @@ contract Encoding_Converter {
bool public failedRoundtripAToB;
bool public failedRoundtripBToA;
/**
* @notice Takes a pair of integers to be encoded into a versioned nonce with the
* Encoding library and then decoded and updates the test contract's state
* indicating if the round trip encoding failed.
*/
/// @notice Takes a pair of integers to be encoded into a versioned nonce with the
/// Encoding library and then decoded and updates the test contract's state
/// indicating if the round trip encoding failed.
function convertRoundTripAToB(uint240 _nonce, uint16 _version) external {
// Encode the nonce and version
uint256 encodedVersionedNonce = Encoding.encodeVersionedNonce(_nonce, _version);
......@@ -30,11 +28,9 @@ contract Encoding_Converter {
}
}
/**
* @notice Takes an integer representing a packed version and nonce and attempts
* to decode them using the Encoding library before re-encoding and updates
* the test contract's state indicating if the round trip encoding failed.
*/
/// @notice Takes an integer representing a packed version and nonce and attempts
/// to decode them using the Encoding library before re-encoding and updates
/// the test contract's state indicating if the round trip encoding failed.
function convertRoundTripBToA(uint256 _versionedNonce) external {
// Decode the nonce and version
uint240 decodedNonce;
......@@ -68,22 +64,19 @@ contract Encoding_Invariant is StdInvariant, Test {
targetSelector(selector);
}
/**
* @custom:invariant `convertRoundTripAToB` never fails.
*
* Asserts that a raw versioned nonce can be encoded / decoded to reach the same raw value.
*/
/// @custom:invariant `convertRoundTripAToB` never fails.
///
/// Asserts that a raw versioned nonce can be encoded / decoded
/// to reach the same raw value.
function invariant_round_trip_encoding_AToB() external {
// ASSERTION: The round trip encoding done in testRoundTripAToB(...)
assertEq(actor.failedRoundtripAToB(), false);
}
/**
* @custom:invariant `convertRoundTripBToA` never fails.
*
* Asserts that an encoded versioned nonce can always be decoded / re-encoded to reach
* the same encoded value.
*/
/// @custom:invariant `convertRoundTripBToA` never fails.
///
/// Asserts that an encoded versioned nonce can always be decoded /
/// re-encoded to reach the same encoded value.
function invariant_round_trip_encoding_BToA() external {
// ASSERTION: The round trip encoding done in testRoundTripBToA should never
// fail.
......
......@@ -11,10 +11,9 @@ contract Hash_CrossDomainHasher {
bool public failedCrossDomainHashV0;
bool public failedCrossDomainHashV1;
/**
* @notice Takes the necessary parameters to perform a cross domain hash with a randomly
* generated version. Only schema versions 0 and 1 are supported and all others should revert.
*/
/// @notice Takes the necessary parameters to perform a cross domain hash with a randomly
/// generated version. Only schema versions 0 and 1 are supported and all others
/// should revert.
function hashCrossDomainMessageHighVersion(
uint16 _version,
uint240 _nonce,
......@@ -37,10 +36,9 @@ contract Hash_CrossDomainHasher {
}
}
/**
* @notice Takes the necessary parameters to perform a cross domain hash using the v0 schema
* and compares the output of a call to the unversioned function to the v0 function directly
*/
/// @notice Takes the necessary parameters to perform a cross domain hash using the v0 schema
/// and compares the output of a call to the unversioned function to the v0 function
/// directly.
function hashCrossDomainMessageV0(
uint240 _nonce,
address _sender,
......@@ -75,10 +73,9 @@ contract Hash_CrossDomainHasher {
}
}
/**
* @notice Takes the necessary parameters to perform a cross domain hash using the v1 schema
* and compares the output of a call to the unversioned function to the v1 function directly
*/
/// @notice Takes the necessary parameters to perform a cross domain hash using the v1 schema
/// and compares the output of a call to the unversioned function to the v1 function
/// directly.
function hashCrossDomainMessageV1(
uint240 _nonce,
address _sender,
......@@ -133,36 +130,31 @@ contract Hashing_Invariant is StdInvariant, Test {
targetSelector(selector);
}
/**
* @custom:invariant `hashCrossDomainMessage` reverts if `version` is > `1`.
*
* The `hashCrossDomainMessage` function should always revert if the `version` passed is > `1`.
*/
/// @custom:invariant `hashCrossDomainMessage` reverts if `version` is > `1`.
///
/// The `hashCrossDomainMessage` function should always revert if
/// the `version` passed is > `1`.
function invariant_hash_xdomain_msg_high_version() external {
// ASSERTION: The round trip aliasing done in testRoundTrip(...) should never fail.
assertFalse(actor.failedCrossDomainHashHighVersion());
}
/**
* @custom:invariant `version` = `0`: `hashCrossDomainMessage` and `hashCrossDomainMessageV0`
* are equivalent.
*
* If the version passed is 0, `hashCrossDomainMessage` and `hashCrossDomainMessageV0` should be
* equivalent.
*/
/// @custom:invariant `version` = `0`: `hashCrossDomainMessage` and `hashCrossDomainMessageV0`
/// are equivalent.
///
/// If the version passed is 0, `hashCrossDomainMessage` and
/// `hashCrossDomainMessageV0` should be equivalent.
function invariant_hash_xdomain_msg_0() external {
// ASSERTION: A call to hashCrossDomainMessage and hashCrossDomainMessageV0
// should always match when the version passed is 0
assertFalse(actor.failedCrossDomainHashV0());
}
/**
* @custom:invariant `version` = `1`: `hashCrossDomainMessage` and `hashCrossDomainMessageV1`
* are equivalent.
*
* If the version passed is 1, `hashCrossDomainMessage` and `hashCrossDomainMessageV1` should be
* equivalent.
*/
/// @custom:invariant `version` = `1`: `hashCrossDomainMessage` and `hashCrossDomainMessageV1`
/// are equivalent.
///
/// If the version passed is 1, `hashCrossDomainMessage` and
/// `hashCrossDomainMessageV1` should be equivalent.
function invariant_hash_xdomain_msg_1() external {
// ASSERTION: A call to hashCrossDomainMessage and hashCrossDomainMessageV1
// should always match when the version passed is 1
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { L2OutputOracle_Initializer } from "../CommonTest.t.sol";
......@@ -13,9 +14,7 @@ contract L2OutputOracle_Proposer {
vm = _vm;
}
/**
* @dev Allows the actor to propose an L2 output to the `L2OutputOracle`
*/
/// @dev Allows the actor to propose an L2 output to the `L2OutputOracle`
function proposeL2Output(
bytes32 _outputRoot,
uint256 _l2BlockNumber,
......@@ -49,13 +48,11 @@ contract L2OutputOracle_MonotonicBlockNumIncrease_Invariant is L2OutputOracle_In
targetSelector(selector);
}
/**
* @custom:invariant The block number of the output root proposals should monotonically
* increase.
*
* When a new output is submitted, it should never be allowed to correspond to a block
* number that is less than the current output.
*/
/// @custom:invariant The block number of the output root proposals should monotonically
/// increase.
///
/// When a new output is submitted, it should never be allowed to
/// correspond to a block number that is less than the current output.
function invariant_monotonicBlockNumIncrease() external {
// Assert that the block number of proposals must monotonically increase.
assertTrue(oracle.nextBlockNumber() >= oracle.latestBlockNumber());
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { StdUtils } from "forge-std/Test.sol";
......@@ -148,13 +149,11 @@ contract OptimismPortal_Deposit_Invariant is Portal_Initializer {
targetSelector(selector);
}
/**
* @custom:invariant Deposits of any value should always succeed unless
* `_to` = `address(0)` or `_isCreation` = `true`.
*
* All deposits, barring creation transactions and transactions sent to `address(0)`,
* should always succeed.
*/
/// @custom:invariant Deposits of any value should always succeed unless
/// `_to` = `address(0)` or `_isCreation` = `true`.
///
/// All deposits, barring creation transactions and transactions
/// sent to `address(0)`, should always succeed.
function invariant_deposit_completes() external {
assertEq(actor.failedToComplete(), false);
}
......@@ -178,13 +177,11 @@ contract OptimismPortal_CannotTimeTravel is OptimismPortal_Invariant_Harness {
excludeSender(address(multisig));
}
/**
* @custom:invariant `finalizeWithdrawalTransaction` should revert if the finalization
* period has not elapsed.
*
* A withdrawal that has been proven should not be able to be finalized until after
* the finalization period has elapsed.
*/
/// @custom:invariant `finalizeWithdrawalTransaction` should revert if the finalization
/// period has not elapsed.
///
/// A withdrawal that has been proven should not be able to be finalized
/// until after the finalization period has elapsed.
function invariant_cannotFinalizeBeforePeriodHasPassed() external {
vm.expectRevert("OptimismPortal: proven withdrawal finalization period has not elapsed");
op.finalizeWithdrawalTransaction(_defaultTx);
......@@ -215,13 +212,11 @@ contract OptimismPortal_CannotFinalizeTwice is OptimismPortal_Invariant_Harness
excludeSender(address(multisig));
}
/**
* @custom:invariant `finalizeWithdrawalTransaction` should revert if the withdrawal
* has already been finalized.
*
* Ensures that there is no chain of calls that can be made that allows a withdrawal
* to be finalized twice.
*/
/// @custom:invariant `finalizeWithdrawalTransaction` should revert if the withdrawal
/// has already been finalized.
///
/// Ensures that there is no chain of calls that can be made that
/// allows a withdrawal to be finalized twice.
function invariant_cannotFinalizeTwice() external {
vm.expectRevert("OptimismPortal: withdrawal has already been finalized");
op.finalizeWithdrawalTransaction(_defaultTx);
......@@ -249,14 +244,13 @@ contract OptimismPortal_CanAlwaysFinalizeAfterWindow is OptimismPortal_Invariant
excludeSender(address(multisig));
}
/**
* @custom:invariant A withdrawal should **always** be able to be finalized
* `FINALIZATION_PERIOD_SECONDS` after it was successfully proven.
*
* This invariant asserts that there is no chain of calls that can be made that
* will prevent a withdrawal from being finalized exactly `FINALIZATION_PERIOD_SECONDS`
* after it was successfully proven.
*/
/// @custom:invariant A withdrawal should **always** be able to be finalized
/// `FINALIZATION_PERIOD_SECONDS` after it was successfully proven.
///
/// This invariant asserts that there is no chain of calls that can
/// be made that will prevent a withdrawal from being finalized
/// exactly `FINALIZATION_PERIOD_SECONDS` after it was successfully
/// proven.
function invariant_canAlwaysFinalize() external {
uint256 bobBalanceBefore = address(bob).balance;
......
......@@ -45,10 +45,8 @@ contract ResourceMetering_User is StdUtils, ResourceMetering {
return rcfg;
}
/**
* @notice Takes the necessary parameters to allow us to burn arbitrary amounts of gas to test
* the underlying resource metering/gas market logic
*/
/// @notice Takes the necessary parameters to allow us to burn arbitrary amounts of gas to test
/// the underlying resource metering/gas market logic
function burn(uint256 _gasToBurn, bool _raiseBaseFee) public {
// Part 1: we cache the current param values and do some basic checks on them.
uint256 cachedPrevBaseFee = uint256(params.prevBaseFee);
......@@ -169,78 +167,67 @@ contract ResourceMetering_Invariant is StdInvariant, Test {
targetSelector(selector);
}
/**
* @custom:invariant The base fee should increase if the last block used more
* than the target amount of gas
*
* If the last block used more than the target amount of gas (and there were no
* empty blocks in between), ensure this block's baseFee increased, but not by
* more than the max amount per block.
*/
/// @custom:invariant The base fee should increase if the last block used more
/// than the target amount of gas.
///
/// If the last block used more than the target amount of gas
/// (and there were no empty blocks in between), ensure this
/// block's baseFee increased, but not by more than the max amount
/// per block.
function invariant_high_usage_raise_baseFee() external {
assertFalse(actor.failedRaiseBaseFee());
}
/**
* @custom:invariant The base fee should decrease if the last block used less
* than the target amount of gas
*
* If the previous block used less than the target amount of gas, the base fee should decrease,
* but not more than the max amount.
*/
/// @custom:invariant The base fee should decrease if the last block used less
/// than the target amount of gas.
///
/// If the previous block used less than the target amount of gas,
/// the base fee should decrease, but not more than the max amount.
function invariant_low_usage_lower_baseFee() external {
assertFalse(actor.failedLowerBaseFee());
}
/**
* @custom:invariant A block's base fee should never be below `MINIMUM_BASE_FEE`
*
* This test asserts that a block's base fee can never drop below the
* `MINIMUM_BASE_FEE` threshold.
*/
/// @custom:invariant A block's base fee should never be below `MINIMUM_BASE_FEE`.
///
/// This test asserts that a block's base fee can never drop
/// below the `MINIMUM_BASE_FEE` threshold.
function invariant_never_below_min_baseFee() external {
assertFalse(actor.failedNeverBelowMinBaseFee());
}
/**
* @custom:invariant A block can never consume more than `MAX_RESOURCE_LIMIT` gas.
*
* This test asserts that a block can never consume more than the `MAX_RESOURCE_LIMIT`
* gas threshold.
*/
/// @custom:invariant A block can never consume more than `MAX_RESOURCE_LIMIT` gas.
///
/// This test asserts that a block can never consume more than
/// the `MAX_RESOURCE_LIMIT` gas threshold.
function invariant_never_above_max_gas_limit() external {
assertFalse(actor.failedMaxGasPerBlock());
}
/**
* @custom:invariant The base fee can never be raised more than the max base fee change.
*
* After a block consumes more gas than the target gas, the base fee cannot be raised
* more than the maximum amount allowed. The max base fee change (per-block) is derived
* as follows: `prevBaseFee / BASE_FEE_MAX_CHANGE_DENOMINATOR`
*/
/// @custom:invariant The base fee can never be raised more than the max base fee change.
///
/// After a block consumes more gas than the target gas, the base fee
/// cannot be raised more than the maximum amount allowed. The max base
/// fee change (per-block) is derived as follows:
/// `prevBaseFee / BASE_FEE_MAX_CHANGE_DENOMINATOR`
function invariant_never_exceed_max_increase() external {
assertFalse(actor.failedMaxRaiseBaseFeePerBlock());
}
/**
* @custom:invariant The base fee can never be lowered more than the max base fee change.
*
* After a block consumes less than the target gas, the base fee cannot be lowered more
* than the maximum amount allowed. The max base fee change (per-block) is derived as
*follows: `prevBaseFee / BASE_FEE_MAX_CHANGE_DENOMINATOR`
*/
/// @custom:invariant The base fee can never be lowered more than the max base fee change.
///
/// After a block consumes less than the target gas, the base fee cannot
/// be lowered more than the maximum amount allowed. The max base fee
/// change (per-block) is derived as follows:
/// `prevBaseFee / BASE_FEE_MAX_CHANGE_DENOMINATOR`
function invariant_never_exceed_max_decrease() external {
assertFalse(actor.failedMaxLowerBaseFeePerBlock());
}
/**
* @custom:invariant The `maxBaseFeeChange` calculation over multiple blocks can never
* underflow.
*
* When calculating the `maxBaseFeeChange` after multiple empty blocks, the calculation
* should never be allowed to underflow.
*/
/// @custom:invariant The `maxBaseFeeChange` calculation over multiple blocks can never
/// underflow.
///
/// When calculating the `maxBaseFeeChange` after multiple empty blocks,
/// the calculation should never be allowed to underflow.
function invariant_never_underflow() external {
assertFalse(actor.underflow());
}
......
......@@ -23,13 +23,11 @@ contract SafeCall_Succeeds_Invariants is Test {
vm.deal(address(actor), type(uint128).max);
}
/**
* @custom:invariant If `callWithMinGas` performs a call, then it must always
* provide at least the specified minimum gas limit to the subcontext.
*
* If the check for remaining gas in `SafeCall.callWithMinGas` passes, the
* subcontext of the call below it must be provided at least `minGas` gas.
*/
/// @custom:invariant If `callWithMinGas` performs a call, then it must always
/// provide at least the specified minimum gas limit to the subcontext.
///
/// If the check for remaining gas in `SafeCall.callWithMinGas` passes, the
/// subcontext of the call below it must be provided at least `minGas` gas.
function invariant_callWithMinGas_alwaysForwardsMinGas_succeeds() public {
assertEq(actor.numCalls(), 0, "no failed calls allowed");
}
......@@ -56,14 +54,12 @@ contract SafeCall_Fails_Invariants is Test {
vm.deal(address(actor), type(uint128).max);
}
/**
* @custom:invariant `callWithMinGas` reverts if there is not enough gas to pass
* to the subcontext.
*
* If there is not enough gas in the callframe to ensure that `callWithMinGas`
* can provide the specified minimum gas limit to the subcontext of the call,
* then `callWithMinGas` must revert.
*/
/// @custom:invariant `callWithMinGas` reverts if there is not enough gas to pass
/// to the subcontext.
///
/// If there is not enough gas in the callframe to ensure that
/// `callWithMinGas` can provide the specified minimum gas limit
/// to the subcontext of the call, then `callWithMinGas` must revert.
function invariant_callWithMinGas_neverForwardsMinGas_reverts() public {
assertEq(actor.numCalls(), 0, "no successful calls allowed");
}
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
......@@ -37,10 +38,8 @@ contract SystemConfig_GasLimitLowerBound_Invariant is Test {
targetSelector(selector);
}
/**
* @custom:invariant The gas limit of the `SystemConfig` contract can never be lower
* than the hard-coded lower bound.
*/
/// @custom:invariant The gas limit of the `SystemConfig` contract can never be lower
/// than the hard-coded lower bound.
function invariant_gasLimitLowerBound() external {
assertTrue(config.gasLimit() >= config.minimumGasLimit());
}
......
# `AddressAliasHelper` Invariants
## Address aliases are always able to be undone.
**Test:** [`AddressAliasHelper.t.sol#L48`](../contracts/test/invariants/AddressAliasHelper.t.sol#L48)
**Test:** [`AddressAliasHelper.t.sol#L46`](../contracts/test/invariants/AddressAliasHelper.t.sol#L46)
Asserts that an address that has been aliased with `applyL1ToL2Alias` can always be unaliased with `undoL1ToL2Alias`.
\ No newline at end of file
# `Burn.Eth` Invariants
## `eth(uint256)` always burns the exact amount of eth passed.
**Test:** [`Burn.Eth.t.sol#L68`](../contracts/test/invariants/Burn.Eth.t.sol#L68)
**Test:** [`Burn.Eth.t.sol#L64`](../contracts/test/invariants/Burn.Eth.t.sol#L64)
Asserts that when `Burn.eth(uint256)` is called, it always burns the exact amount of ETH passed to the function.
\ No newline at end of file
# `Burn.Gas` Invariants
## `gas(uint256)` always burns at least the amount of gas passed.
**Test:** [`Burn.Gas.t.sol#L68`](../contracts/test/invariants/Burn.Gas.t.sol#L68)
**Test:** [`Burn.Gas.t.sol#L64`](../contracts/test/invariants/Burn.Gas.t.sol#L64)
Asserts that when `Burn.gas(uint256)` is called, it always burns at least the amount of gas passed to the function.
\ No newline at end of file
# `CrossDomainMessenger` Invariants
## A call to `relayMessage` should succeed if at least the minimum gas limit can be supplied to the target context, there is enough gas to complete execution of `relayMessage` after the target context's execution is finished, and the target context did not revert.
**Test:** [`CrossDomainMessenger.t.sol#L161`](../contracts/test/invariants/CrossDomainMessenger.t.sol#L161)
**Test:** [`CrossDomainMessenger.t.sol#L159`](../contracts/test/invariants/CrossDomainMessenger.t.sol#L159)
There are two minimum gas limits here:
- The outer min gas limit is for the call from the `OptimismPortal` to the `L1CrossDomainMessenger`, and it can be retrieved by calling the xdm's `baseGas` function with the `message` and inner limit.
- The inner min gas limit is for the call from the `L1CrossDomainMessenger` to the target contract.
## A call to `relayMessage` should assign the message hash to the `failedMessages` mapping if not enough gas is supplied to forward `minGasLimit` to the target context or if there is not enough gas to complete execution of `relayMessage` after the target context's execution is finished.
**Test:** [`CrossDomainMessenger.t.sol#L196`](../contracts/test/invariants/CrossDomainMessenger.t.sol#L196)
**Test:** [`CrossDomainMessenger.t.sol#L192`](../contracts/test/invariants/CrossDomainMessenger.t.sol#L192)
There are two minimum gas limits here:
- The outer min gas limit is for the call from the `OptimismPortal` to the `L1CrossDomainMessenger`, and it can be retrieved by calling the xdm's `baseGas` function with the `message` and inner limit.
......
# `Encoding` Invariants
## `convertRoundTripAToB` never fails.
**Test:** [`Encoding.t.sol#L76`](../contracts/test/invariants/Encoding.t.sol#L76)
**Test:** [`Encoding.t.sol#L71`](../contracts/test/invariants/Encoding.t.sol#L71)
Asserts that a raw versioned nonce can be encoded / decoded to reach the same raw value.
## `convertRoundTripBToA` never fails.
**Test:** [`Encoding.t.sol#L87`](../contracts/test/invariants/Encoding.t.sol#L87)
**Test:** [`Encoding.t.sol#L80`](../contracts/test/invariants/Encoding.t.sol#L80)
Asserts that an encoded versioned nonce can always be decoded / re-encoded to reach the same encoded value.
\ No newline at end of file
# `Hashing` Invariants
## `hashCrossDomainMessage` reverts if `version` is > `1`.
**Test:** [`Hashing.t.sol#L141`](../contracts/test/invariants/Hashing.t.sol#L141)
**Test:** [`Hashing.t.sol#L137`](../contracts/test/invariants/Hashing.t.sol#L137)
The `hashCrossDomainMessage` function should always revert if the `version` passed is > `1`.
## `version` = `0`: `hashCrossDomainMessage` and `hashCrossDomainMessageV0` are equivalent.
**Test:** [`Hashing.t.sol#L153`](../contracts/test/invariants/Hashing.t.sol#L153)
**Test:** [`Hashing.t.sol#L147`](../contracts/test/invariants/Hashing.t.sol#L147)
If the version passed is 0, `hashCrossDomainMessage` and `hashCrossDomainMessageV0` should be equivalent.
## `version` = `1`: `hashCrossDomainMessage` and `hashCrossDomainMessageV1` are equivalent.
**Test:** [`Hashing.t.sol#L166`](../contracts/test/invariants/Hashing.t.sol#L166)
**Test:** [`Hashing.t.sol#L158`](../contracts/test/invariants/Hashing.t.sol#L158)
If the version passed is 1, `hashCrossDomainMessage` and `hashCrossDomainMessageV1` should be equivalent.
\ No newline at end of file
# `L2OutputOracle` Invariants
## The block number of the output root proposals should monotonically increase.
**Test:** [`L2OutputOracle.t.sol#L59`](../contracts/test/invariants/L2OutputOracle.t.sol#L59)
**Test:** [`L2OutputOracle.t.sol#L56`](../contracts/test/invariants/L2OutputOracle.t.sol#L56)
When a new output is submitted, it should never be allowed to correspond to a block number that is less than the current output.
\ No newline at end of file
# `OptimismPortal` Invariants
## Deposits of any value should always succeed unless `_to` = `address(0)` or `_isCreation` = `true`.
**Test:** [`OptimismPortal.t.sol#L158`](../contracts/test/invariants/OptimismPortal.t.sol#L158)
**Test:** [`OptimismPortal.t.sol#L157`](../contracts/test/invariants/OptimismPortal.t.sol#L157)
All deposits, barring creation transactions and transactions sent to `address(0)`, should always succeed.
## `finalizeWithdrawalTransaction` should revert if the finalization period has not elapsed.
**Test:** [`OptimismPortal.t.sol#L188`](../contracts/test/invariants/OptimismPortal.t.sol#L188)
**Test:** [`OptimismPortal.t.sol#L185`](../contracts/test/invariants/OptimismPortal.t.sol#L185)
A withdrawal that has been proven should not be able to be finalized until after the finalization period has elapsed.
## `finalizeWithdrawalTransaction` should revert if the withdrawal has already been finalized.
**Test:** [`OptimismPortal.t.sol#L225`](../contracts/test/invariants/OptimismPortal.t.sol#L225)
**Test:** [`OptimismPortal.t.sol#L220`](../contracts/test/invariants/OptimismPortal.t.sol#L220)
Ensures that there is no chain of calls that can be made that allows a withdrawal to be finalized twice.
## A withdrawal should **always** be able to be finalized `FINALIZATION_PERIOD_SECONDS` after it was successfully proven.
**Test:** [`OptimismPortal.t.sol#L260`](../contracts/test/invariants/OptimismPortal.t.sol#L260)
**Test:** [`OptimismPortal.t.sol#L254`](../contracts/test/invariants/OptimismPortal.t.sol#L254)
This invariant asserts that there is no chain of calls that can be made that will prevent a withdrawal from being finalized exactly `FINALIZATION_PERIOD_SECONDS` after it was successfully proven.
\ No newline at end of file
# `ResourceMetering` Invariants
## The base fee should increase if the last block used more than the target amount of gas
**Test:** [`ResourceMetering.t.sol#L180`](../contracts/test/invariants/ResourceMetering.t.sol#L180)
## The base fee should increase if the last block used more than the target amount of gas.
**Test:** [`ResourceMetering.t.sol#L177`](../contracts/test/invariants/ResourceMetering.t.sol#L177)
If the last block used more than the target amount of gas (and there were no empty blocks in between), ensure this block's baseFee increased, but not by more than the max amount per block.
## The base fee should decrease if the last block used less than the target amount of gas
**Test:** [`ResourceMetering.t.sol#L191`](../contracts/test/invariants/ResourceMetering.t.sol#L191)
## The base fee should decrease if the last block used less than the target amount of gas.
**Test:** [`ResourceMetering.t.sol#L186`](../contracts/test/invariants/ResourceMetering.t.sol#L186)
If the previous block used less than the target amount of gas, the base fee should decrease, but not more than the max amount.
## A block's base fee should never be below `MINIMUM_BASE_FEE`
**Test:** [`ResourceMetering.t.sol#L201`](../contracts/test/invariants/ResourceMetering.t.sol#L201)
## A block's base fee should never be below `MINIMUM_BASE_FEE`.
**Test:** [`ResourceMetering.t.sol#L194`](../contracts/test/invariants/ResourceMetering.t.sol#L194)
This test asserts that a block's base fee can never drop below the `MINIMUM_BASE_FEE` threshold.
## A block can never consume more than `MAX_RESOURCE_LIMIT` gas.
**Test:** [`ResourceMetering.t.sol#L211`](../contracts/test/invariants/ResourceMetering.t.sol#L211)
**Test:** [`ResourceMetering.t.sol#L202`](../contracts/test/invariants/ResourceMetering.t.sol#L202)
This test asserts that a block can never consume more than the `MAX_RESOURCE_LIMIT` gas threshold.
## The base fee can never be raised more than the max base fee change.
**Test:** [`ResourceMetering.t.sol#L222`](../contracts/test/invariants/ResourceMetering.t.sol#L222)
**Test:** [`ResourceMetering.t.sol#L212`](../contracts/test/invariants/ResourceMetering.t.sol#L212)
After a block consumes more gas than the target gas, the base fee cannot be raised more than the maximum amount allowed. The max base fee change (per-block) is derived as follows: `prevBaseFee / BASE_FEE_MAX_CHANGE_DENOMINATOR`
## The base fee can never be lowered more than the max base fee change.
**Test:** [`ResourceMetering.t.sol#L233`](../contracts/test/invariants/ResourceMetering.t.sol#L233)
**Test:** [`ResourceMetering.t.sol#L222`](../contracts/test/invariants/ResourceMetering.t.sol#L222)
After a block consumes less than the target gas, the base fee cannot be lowered more than the maximum amount allowed. The max base fee change (per-block) is derived as follows: `prevBaseFee / BASE_FEE_MAX_CHANGE_DENOMINATOR`
## The `maxBaseFeeChange` calculation over multiple blocks can never underflow.
**Test:** [`ResourceMetering.t.sol#L244`](../contracts/test/invariants/ResourceMetering.t.sol#L244)
**Test:** [`ResourceMetering.t.sol#L231`](../contracts/test/invariants/ResourceMetering.t.sol#L231)
When calculating the `maxBaseFeeChange` after multiple empty blocks, the calculation should never be allowed to underflow.
\ No newline at end of file
# `SafeCall` Invariants
## If `callWithMinGas` performs a call, then it must always provide at least the specified minimum gas limit to the subcontext.
**Test:** [`SafeCall.t.sol#L33`](../contracts/test/invariants/SafeCall.t.sol#L33)
**Test:** [`SafeCall.t.sol#L31`](../contracts/test/invariants/SafeCall.t.sol#L31)
If the check for remaining gas in `SafeCall.callWithMinGas` passes, the subcontext of the call below it must be provided at least `minGas` gas.
## `callWithMinGas` reverts if there is not enough gas to pass to the subcontext.
**Test:** [`SafeCall.t.sol#L67`](../contracts/test/invariants/SafeCall.t.sol#L67)
**Test:** [`SafeCall.t.sol#L63`](../contracts/test/invariants/SafeCall.t.sol#L63)
If there is not enough gas in the callframe to ensure that `callWithMinGas` can provide the specified minimum gas limit to the subcontext of the call, then `callWithMinGas` must revert.
\ No newline at end of file
......@@ -11,8 +11,6 @@ const BASE_INVARIANTS_DIR = path.join(
const BASE_DOCS_DIR = path.join(__dirname, '..', 'invariant-docs')
const BASE_INVARIANT_GH_URL = '../contracts/test/invariants/'
const NATSPEC_INV = '@custom:invariant'
const BLOCK_COMMENT_PREFIX_REGEX = /\*(\/)?/
const BLOCK_COMMENT_HEADER_REGEX = /\*\s(.)+/
// Represents an invariant test contract
type Contract = {
......@@ -30,10 +28,8 @@ type InvariantDoc = {
const writtenFiles = []
/**
* Lazy-parses all test files in the `contracts/test/invariants` directory to generate documentation
* on all invariant tests.
*/
// Lazy-parses all test files in the `contracts/test/invariants` directory
// to generate documentation on all invariant tests.
const docGen = (dir: string): void => {
// Grab all files within the invariants test dir
const files = fs.readdirSync(dir)
......@@ -58,33 +54,25 @@ const docGen = (dir: string): void => {
for (let i = 0; i < lines.length; i++) {
let line = lines[i]
if (line.startsWith('/**')) {
// We are at the beginning of a new doc comment. Reset the `currentDoc`.
currentDoc = {}
// Move on to the next line
line = lines[++i]
// We have an invariant doc
if (line.startsWith(`* ${NATSPEC_INV}`)) {
if (line.startsWith(`/// ${NATSPEC_INV}`)) {
// Assign the header of the invariant doc.
// TODO: Handle ambiguous case for `INVARIANT: ` prefix.
// TODO: Handle multi-line headers.
currentDoc = {
header: line.replace(`* ${NATSPEC_INV}`, '').trim(),
header: line.replace(`/// ${NATSPEC_INV}`, '').trim(),
desc: '',
}
// If the header is multi-line, continue appending to the `currentDoc`'s header.
while (BLOCK_COMMENT_HEADER_REGEX.test((line = lines[++i]))) {
currentDoc.header += ` ${line
.replace(BLOCK_COMMENT_PREFIX_REGEX, '')
.trim()}`
line = lines[++i]
while (line.startsWith(`///`) && line.trim() !== '///') {
currentDoc.header += ` ${line.replace(`///`, '').trim()}`
line = lines[++i]
}
// Process the description
while ((line = lines[++i]).startsWith('*')) {
line = line.replace(BLOCK_COMMENT_PREFIX_REGEX, '').trim()
while ((line = lines[++i]).startsWith('///')) {
line = line.replace('///', '').trim()
// If the line has any contents, insert it into the desc.
// Otherwise, consider it a linebreak.
......@@ -98,7 +86,6 @@ const docGen = (dir: string): void => {
contract.docs.push(currentDoc)
}
}
}
// Add the contract to the array of docs
docs.push(contract)
......@@ -133,9 +120,7 @@ const docGen = (dir: string): void => {
)
}
/**
* Generate a table of contents for all invariant docs and place it in the README.
*/
// Generate a table of contents for all invariant docs and place it in the README.
const tocGen = (): void => {
const autoTOCPrefix = '<!-- START autoTOC -->\n'
const autoTOCPostfix = '<!-- END autoTOC -->\n'
......@@ -165,9 +150,7 @@ const tocGen = (): void => {
)
}
/**
* Render a `Contract` object into valid markdown.
*/
// Render a `Contract` object into valid markdown.
const renderContractDoc = (contract: Contract, header: boolean): string => {
const _header = header ? `# \`${contract.name}\` Invariants\n` : ''
const docs = contract.docs
......
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