L1BlockInterop.t.sol 12.2 KB
Newer Older
1 2 3
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

4
// Testing
5 6 7 8
import { CommonTest } from "test/setup/CommonTest.sol";

// Libraries
import { StaticConfig } from "src/libraries/StaticConfig.sol";
9
import { Predeploys } from "src/libraries/Predeploys.sol";
10 11
import "src/libraries/L1BlockErrors.sol";

12
// Interfaces
13
import { IL1BlockInterop, ConfigType } from "interfaces/L2/IL1BlockInterop.sol";
14

15
contract L1BlockInteropTest is CommonTest {
16 17 18 19 20
    event GasPayingTokenSet(address indexed token, uint8 indexed decimals, bytes32 name, bytes32 symbol);
    event DependencyAdded(uint256 indexed chainId);
    event DependencyRemoved(uint256 indexed chainId);

    modifier prankDepositor() {
21
        vm.startPrank(_l1BlockInterop().DEPOSITOR_ACCOUNT());
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
        _;
        vm.stopPrank();
    }

    /// @notice Marked virtual to be overridden in
    ///         test/kontrol/deployment/DeploymentSummary.t.sol
    function setUp() public virtual override {
        super.enableInterop();
        super.setUp();
    }

    /// @dev Tests that an arbitrary chain ID can be added to the dependency set.
    function testFuzz_isInDependencySet_succeeds(uint256 _chainId) public prankDepositor {
        vm.assume(_chainId != block.chainid);

37
        _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId));
38

39
        assertTrue(_l1BlockInterop().isInDependencySet(_chainId));
40 41 42 43
    }

    /// @dev Tests that `isInDependencySet` returns true when the chain's chain ID is passed as the input.
    function test_isInDependencySet_chainChainId_succeeds() public view {
44
        assertTrue(_l1BlockInterop().isInDependencySet(block.chainid));
45 46 47 48 49 50 51 52
    }

    /// @dev Tests that `isInDependencySet` reverts when the input chain ID is not in the dependency set
    ///      and is not the chain's chain ID.
    function testFuzz_isInDependencySet_notDependency_reverts(uint256 _chainId) public view {
        vm.assume(_chainId != block.chainid);

        // Check that the chain ID is not in the dependency set
53
        assertFalse(_l1BlockInterop().isInDependencySet(_chainId));
54 55 56 57 58 59
    }

    /// @dev Tests that `isInDependencySet` returns false when the dependency set is empty.
    function testFuzz_isInDependencySet_dependencySetEmpty_succeeds(uint256 _chainId) public view {
        vm.assume(_chainId != block.chainid);

60
        assertEq(_l1BlockInterop().dependencySetSize(), 0);
61

62
        assertFalse(_l1BlockInterop().isInDependencySet(_chainId));
63 64 65 66 67 68 69 70
    }

    /// @dev Tests that the dependency set size is correct when adding an arbitrary number of chain IDs.
    function testFuzz_dependencySetSize_succeeds(uint8 _dependencySetSize) public prankDepositor {
        uint256 uniqueCount = 0;

        for (uint256 i = 0; i < _dependencySetSize; i++) {
            if (i == block.chainid) continue;
71
            _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(i));
72
            uniqueCount++;
73 74
        }

75
        assertEq(_l1BlockInterop().dependencySetSize(), uniqueCount);
76 77 78 79
    }

    /// @dev Tests that the dependency set size is correct when the dependency set is empty.
    function test_dependencySetSize_dependencySetEmpty_succeeds() public view {
80
        assertEq(_l1BlockInterop().dependencySetSize(), 0);
81 82 83 84 85 86 87 88 89
    }

    /// @dev Tests that the config for adding a dependency can be set.
    function testFuzz_setConfig_addDependency_succeeds(uint256 _chainId) public prankDepositor {
        vm.assume(_chainId != block.chainid);

        vm.expectEmit(address(l1Block));
        emit DependencyAdded(_chainId);

90
        _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId));
91 92 93
    }

    /// @dev Tests that adding a dependency reverts if it's the chain's chain id
94
    function test_setConfig_addDependencyButChainChainId_reverts() public prankDepositor {
95
        vm.expectRevert(AlreadyDependency.selector);
96
        _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(block.chainid));
97 98 99
    }

    /// @dev Tests that adding a dependency already in the set reverts
100
    function test_setConfig_addDependencyButAlreadyDependency_reverts(uint256 _chainId) public prankDepositor {
101 102
        vm.assume(_chainId != block.chainid);

103
        _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId));
104 105

        vm.expectRevert(AlreadyDependency.selector);
106
        _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId));
107 108 109
    }

    /// @dev Tests that setting the add dependency config as not the depositor reverts.
110
    function testFuzz_setConfig_addDependencyButNotDepositor_reverts(uint256 _chainId) public {
111
        vm.expectRevert(NotDepositor.selector);
112
        _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId));
113 114 115
    }

    /// @dev Tests that setting the add dependency config when the dependency set size is too large reverts.
116
    function test_setConfig_addDependencyButDependencySetSizeTooLarge_reverts() public prankDepositor {
117
        for (uint256 i = 0; i < type(uint8).max; i++) {
118
            _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(i));
119
        }
120

121
        assertEq(_l1BlockInterop().dependencySetSize(), type(uint8).max);
122 123

        vm.expectRevert(DependencySetSizeTooLarge.selector);
124
        _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(1));
125 126
    }

127 128 129 130 131
    /// @dev Tests that the config for removing a dependency can be set.
    function testFuzz_setConfig_removeDependency_succeeds(uint256 _chainId) public prankDepositor {
        vm.assume(_chainId != block.chainid);

        // Add the chain ID to the dependency set before removing it
132
        _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId));
133 134 135 136

        vm.expectEmit(address(l1Block));
        emit DependencyRemoved(_chainId);

137
        _l1BlockInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId));
138 139
    }

140
    /// @dev Tests that setting the remove dependency config as not the depositor reverts.
141
    function testFuzz_setConfig_removeDependencyButNotDepositor_reverts(uint256 _chainId) public {
142
        vm.expectRevert(NotDepositor.selector);
143
        _l1BlockInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId));
144 145 146
    }

    /// @dev Tests that setting the remove dependency config for the chain's chain ID reverts.
147
    function test_setConfig_removeDependencyButChainChainId_reverts() public prankDepositor {
148
        vm.expectRevert(CantRemovedDependency.selector);
149
        _l1BlockInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(block.chainid));
150 151 152
    }

    /// @dev Tests that setting the remove dependency config for a chain ID that is not in the dependency set reverts.
153
    function testFuzz_setConfig_removeDependencyButNotDependency_reverts(uint256 _chainId) public prankDepositor {
154 155 156
        vm.assume(_chainId != block.chainid);

        vm.expectRevert(NotDependency.selector);
157
        _l1BlockInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId));
158 159
    }

160
    /// @dev Returns the L1BlockInterop instance.
161 162
    function _l1BlockInterop() internal view returns (IL1BlockInterop) {
        return IL1BlockInterop(address(l1Block));
163 164 165
    }
}

166
contract L1BlockInteropIsDeposit_Test is L1BlockInteropTest {
167 168 169 170
    /// @dev Tests that `isDeposit` reverts if the caller is not the cross L2 inbox.
    function test_isDeposit_notCrossL2Inbox_reverts(address _caller) external {
        vm.assume(_caller != Predeploys.CROSS_L2_INBOX);
        vm.expectRevert(NotCrossL2Inbox.selector);
171
        _l1BlockInterop().isDeposit();
172 173 174 175 176 177
    }

    /// @dev Tests that `isDeposit` always returns the correct value.
    function test_isDeposit_succeeds() external {
        // Assert is false if the value is not updated
        vm.prank(Predeploys.CROSS_L2_INBOX);
178
        assertEq(_l1BlockInterop().isDeposit(), false);
179

180 181 182
        /// @dev Assuming that `setL1BlockValuesInterop` will set the proper value. That function is tested as well
        vm.prank(_l1BlockInterop().DEPOSITOR_ACCOUNT());
        _l1BlockInterop().setL1BlockValuesInterop();
183 184 185

        // Assert is true if the value is updated
        vm.prank(Predeploys.CROSS_L2_INBOX);
186
        assertEq(_l1BlockInterop().isDeposit(), true);
187 188 189
    }
}

190 191 192 193
contract L1BlockInteropSetL1BlockValuesInterop_Test is L1BlockInteropTest {
    /// @dev Tests that `setL1BlockValuesInterop` reverts if sender address is not the depositor
    function test_setL1BlockValuesInterop_notDepositor_reverts(address _caller) external {
        vm.assume(_caller != _l1BlockInterop().DEPOSITOR_ACCOUNT());
194 195
        vm.prank(_caller);
        vm.expectRevert(NotDepositor.selector);
196
        _l1BlockInterop().setL1BlockValuesInterop();
197 198
    }

199 200
    /// @dev Tests that `setL1BlockValuesInterop` succeeds if sender address is the depositor
    function test_setL1BlockValuesInterop_succeeds(
201 202 203 204 205 206 207 208 209 210 211 212
        uint32 baseFeeScalar,
        uint32 blobBaseFeeScalar,
        uint64 sequenceNumber,
        uint64 timestamp,
        uint64 number,
        uint256 baseFee,
        uint256 blobBaseFee,
        bytes32 hash,
        bytes32 batcherHash
    )
        external
    {
213
        // Ensure the `isDepositTransaction` flag is false before calling `setL1BlockValuesInterop`
214
        vm.prank(Predeploys.CROSS_L2_INBOX);
215
        assertEq(_l1BlockInterop().isDeposit(), false);
216 217 218 219 220

        bytes memory setValuesEcotoneCalldata = abi.encodePacked(
            baseFeeScalar, blobBaseFeeScalar, sequenceNumber, timestamp, number, baseFee, blobBaseFee, hash, batcherHash
        );

221
        vm.prank(_l1BlockInterop().DEPOSITOR_ACCOUNT());
222
        (bool success,) = address(l1Block).call(
223
            abi.encodePacked(IL1BlockInterop.setL1BlockValuesInterop.selector, setValuesEcotoneCalldata)
224 225 226 227 228
        );
        assertTrue(success, "function call failed");

        // Assert that the `isDepositTransaction` flag was properly set to true
        vm.prank(Predeploys.CROSS_L2_INBOX);
229
        assertEq(_l1BlockInterop().isDeposit(), true);
230 231

        // Assert `setL1BlockValuesEcotone` was properly called, forwarding the calldata to it
232 233 234 235 236 237 238 239 240
        assertEq(_l1BlockInterop().baseFeeScalar(), baseFeeScalar, "base fee scalar not properly set");
        assertEq(_l1BlockInterop().blobBaseFeeScalar(), blobBaseFeeScalar, "blob base fee scalar not properly set");
        assertEq(_l1BlockInterop().sequenceNumber(), sequenceNumber, "sequence number not properly set");
        assertEq(_l1BlockInterop().timestamp(), timestamp, "timestamp not properly set");
        assertEq(_l1BlockInterop().number(), number, "number not properly set");
        assertEq(_l1BlockInterop().basefee(), baseFee, "base fee not properly set");
        assertEq(_l1BlockInterop().blobBaseFee(), blobBaseFee, "blob base fee not properly set");
        assertEq(_l1BlockInterop().hash(), hash, "hash not properly set");
        assertEq(_l1BlockInterop().batcherHash(), batcherHash, "batcher hash not properly set");
241 242 243
    }
}

244
contract L1BlockDepositsComplete_Test is L1BlockInteropTest {
245
    // @dev Tests that `depositsComplete` reverts if the caller is not the depositor.
246
    function test_depositsComplete_notDepositor_reverts(address _caller) external {
247
        vm.assume(_caller != _l1BlockInterop().DEPOSITOR_ACCOUNT());
248
        vm.expectRevert(NotDepositor.selector);
249
        _l1BlockInterop().depositsComplete();
250 251 252 253 254
    }

    // @dev Tests that `depositsComplete` succeeds if the caller is the depositor.
    function test_depositsComplete_succeeds() external {
        // Set the `isDeposit` flag to true
255 256
        vm.prank(_l1BlockInterop().DEPOSITOR_ACCOUNT());
        _l1BlockInterop().setL1BlockValuesInterop();
257 258 259

        // Assert that the `isDeposit` flag was properly set to true
        vm.prank(Predeploys.CROSS_L2_INBOX);
260
        assertTrue(_l1BlockInterop().isDeposit());
261 262

        // Call `depositsComplete`
263 264
        vm.prank(_l1BlockInterop().DEPOSITOR_ACCOUNT());
        _l1BlockInterop().depositsComplete();
265 266 267 268

        // Assert that the `isDeposit` flag was properly set to false
        /// @dev Assuming that `isDeposit()` wil return the proper value. That function is tested as well
        vm.prank(Predeploys.CROSS_L2_INBOX);
269
        assertEq(_l1BlockInterop().isDeposit(), false);
270 271
    }
}