Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 102 additions & 101 deletions test/L1/BalanceTracker.t.sol

Large diffs are not rendered by default.

132 changes: 51 additions & 81 deletions test/L1/ETHLockbox.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol";
/// @title ETHLockbox_TestInit
/// @notice Base contract that sets up the testing environment for ETHLockbox tests.
abstract contract ETHLockbox_TestInit is CommonTest {
error InvalidInitialization();

event ETHLocked(IOptimismPortal2 indexed portal, uint256 amount);
event ETHUnlocked(IOptimismPortal2 indexed portal, uint256 amount);
event PortalAuthorized(IOptimismPortal2 indexed portal);
Expand All @@ -41,6 +39,28 @@ abstract contract ETHLockbox_TestInit is CommonTest {
// If the ETHLockbox system feature is not enabled, skip these tests.
skipIfSysFeatureDisabled(Features.ETH_LOCKBOX);
}

function _mockPortalSharedOwnerAndSuperchainConfig(IOptimismPortal2 _portal) internal {
vm.mockCall(
address(_portal), abi.encodeCall(IProxyAdminOwnedBase.proxyAdminOwner, ()), abi.encode(proxyAdminOwner)
);
vm.mockCall(
address(_portal), abi.encodeCall(IOptimismPortal2.superchainConfig, ()), abi.encode(superchainConfig)
);
}

function _authorizePortalIfNeeded(IOptimismPortal2 _portal) internal {
if (!ethLockbox.authorizedPortals(_portal)) {
vm.prank(proxyAdminOwner);
ethLockbox.authorizePortal(_portal);
}
}

function _mockLockboxSharedOwner(address _lockbox) internal {
vm.mockCall(
address(_lockbox), abi.encodeCall(IProxyAdminOwnedBase.proxyAdminOwner, ()), abi.encode(proxyAdminOwner)
);
}
}

/// @title ETHLockbox_Version_Test
Expand All @@ -56,6 +76,14 @@ contract ETHLockbox_Version_Test is ETHLockbox_TestInit {
/// @title ETHLockbox_Initialize_Test
/// @notice Test contract for the initialize function.
contract ETHLockbox_Initialize_Test is ETHLockbox_TestInit {
StorageSlot internal initializedSlot;

function setUp() public override {
super.setUp();

initializedSlot = ForgeArtifacts.getSlot("ETHLockbox", "_initialized");
}

/// @notice Tests the superchain config was correctly set during initialization.
function test_initialize_succeeds() public view {
assertEq(address(ethLockbox.systemConfig().superchainConfig()), address(superchainConfig));
Expand All @@ -67,14 +95,9 @@ contract ETHLockbox_Initialize_Test is ETHLockbox_TestInit {
/// but confirms that the initValue is not incremented incorrectly if an upgrade
/// function is not present.
function test_initialize_correctInitializerValue_succeeds() public view {
// Get the slot for _initialized.
StorageSlot memory slot = ForgeArtifacts.getSlot("ETHLockbox", "_initialized");

// Get the initializer value.
bytes32 slotVal = vm.load(address(ethLockbox), bytes32(slot.slot));
bytes32 slotVal = vm.load(address(ethLockbox), bytes32(initializedSlot.slot));
uint8 val = uint8(uint256(slotVal) & 0xFF);

// Assert that the initializer value matches the expected value.
assertEq(val, ethLockbox.initVersion());
}

Expand All @@ -85,11 +108,8 @@ contract ETHLockbox_Initialize_Test is ETHLockbox_TestInit {
// Prank as the not ProxyAdmin or ProxyAdmin owner.
vm.assume(_sender != address(proxyAdmin) && _sender != proxyAdminOwner);

// Get the slot for _initialized.
StorageSlot memory slot = ForgeArtifacts.getSlot("ETHLockbox", "_initialized");

// Set the initialized slot to 0.
vm.store(address(ethLockbox), bytes32(slot.slot), bytes32(0));
vm.store(address(ethLockbox), bytes32(initializedSlot.slot), bytes32(0));

// Expect the revert with `ProxyAdminOwnedBase_NotProxyAdminOrProxyAdminOwner` selector
vm.expectRevert(IProxyAdminOwnedBase.ProxyAdminOwnedBase_NotProxyAdminOrProxyAdminOwner.selector);
Expand Down Expand Up @@ -183,10 +203,9 @@ contract ETHLockbox_AuthorizePortal_Test is ETHLockbox_TestInit {
/// @notice Tests the `authorizePortal` function succeeds using the `optimismPortal2` address
/// as the portal.
function test_authorizePortal_succeeds() public {
// Calculate the correct storage slot for the mapping value
bytes32 mappingSlot = bytes32(uint256(1)); // position on the layout
StorageSlot memory authorizedPortalsSlot = ForgeArtifacts.getSlot("ETHLockbox", "authorizedPortals");
address key = address(optimismPortal2);
bytes32 slot = keccak256(abi.encode(key, mappingSlot));
bytes32 slot = keccak256(abi.encode(key, bytes32(authorizedPortalsSlot.slot)));

// Reset the authorization status to false
vm.store(address(ethLockbox), slot, bytes32(0));
Expand All @@ -203,21 +222,11 @@ contract ETHLockbox_AuthorizePortal_Test is ETHLockbox_TestInit {
assertTrue(ethLockbox.authorizedPortals(optimismPortal2));
}

/// @notice Tests the `authorizeLockbox` function succeeds
/// @notice Tests the `authorizePortal` function succeeds
function testFuzz_authorizePortal_succeeds(IOptimismPortal2 _portal) public {
assumeNotForgeAddress(address(_portal));

// Mock the admin owner of the portal to be the same as the current lockbox proxy admin
// owner
vm.mockCall(
address(_portal), abi.encodeCall(IProxyAdminOwnedBase.proxyAdminOwner, ()), abi.encode(proxyAdminOwner)
);

// Mock the SuperchainConfig on the portal to be the same as the SuperchainConfig on the
// Lockbox.
vm.mockCall(
address(_portal), abi.encodeCall(IOptimismPortal2.superchainConfig, ()), abi.encode(superchainConfig)
);
_mockPortalSharedOwnerAndSuperchainConfig(_portal);

// Expect the `PortalAuthorized` event to be emitted
vm.expectEmit(address(ethLockbox));
Expand Down Expand Up @@ -245,11 +254,7 @@ contract ETHLockbox_ReceiveLiquidity_Test is ETHLockbox_TestInit {
// Deal the value to the lockbox
deal(address(_lockbox), _value);

// Mock the admin owner of the lockbox to be the same as the current lockbox proxy admin
// owner
vm.mockCall(
address(_lockbox), abi.encodeCall(IProxyAdminOwnedBase.proxyAdminOwner, ()), abi.encode(proxyAdminOwner)
);
_mockLockboxSharedOwner(_lockbox);

// Authorize the lockbox if needed
if (!ethLockbox.authorizedLockboxes(IETHLockbox(_lockbox))) {
Expand Down Expand Up @@ -323,23 +328,10 @@ contract ETHLockbox_LockETH_Test is ETHLockbox_TestInit {
assumeNotForgeAddress(address(_portal));
vm.assume(address(_portal) != address(ethLockbox));

// Mock the admin owner of the portal to be the same as the current lockbox proxy admin
// owner
vm.mockCall(
address(_portal), abi.encodeCall(IProxyAdminOwnedBase.proxyAdminOwner, ()), abi.encode(proxyAdminOwner)
);

// Mock the SuperchainConfig on the portal to be the same as the SuperchainConfig on the
// lockbox.
vm.mockCall(
address(_portal), abi.encodeCall(IOptimismPortal2.superchainConfig, ()), abi.encode(superchainConfig)
);
_mockPortalSharedOwnerAndSuperchainConfig(_portal);

// Set the portal as an authorized portal if needed
if (!ethLockbox.authorizedPortals(_portal)) {
vm.prank(proxyAdminOwner);
ethLockbox.authorizePortal(_portal);
}
_authorizePortalIfNeeded(_portal);

// Deal the ETH amount to the portal
vm.deal(address(_portal), _amount);
Expand Down Expand Up @@ -450,49 +442,41 @@ contract ETHLockbox_UnlockETH_Test is ETHLockbox_TestInit {

/// @notice Tests the ETH is correctly unlocked when the caller is an authorized portal.
function testFuzz_unlockETH_multiplePortals_succeeds(IOptimismPortal2 _portal, uint256 _value) public {
// Since on the fork the `_portal` fuzzed address doesn't exist, we skip the test
if (isForkTest()) vm.skip(true);
assumeNotForgeAddress(address(_portal));
vm.assume(address(_portal) != address(ethLockbox));

// Mock the admin owner of the portal to be the same as the current lockbox proxy admin
// owner
vm.mockCall(
address(_portal), abi.encodeCall(IProxyAdminOwnedBase.proxyAdminOwner, ()), abi.encode(proxyAdminOwner)
);

// Mock the SuperchainConfig on the portal to be the same as the SuperchainConfig on the
// lockbox.

_mockPortalSharedOwnerAndSuperchainConfig(_portal);
vm.mockCall(
address(_portal), abi.encodeCall(IOptimismPortal2.superchainConfig, ()), abi.encode(superchainConfig)
address(_portal), abi.encodeCall(IOptimismPortal2.l2Sender, ()), abi.encode(Constants.DEFAULT_L2_SENDER)
);

// Set the portal as an authorized portal if needed
if (!ethLockbox.authorizedPortals(_portal)) {
vm.prank(proxyAdminOwner);
ethLockbox.authorizePortal(_portal);
}
_authorizePortalIfNeeded(_portal);

// Deal the ETH amount to the lockbox
vm.deal(address(ethLockbox), _value);

// Get the balance of the portal and lockbox before the unlock to compare later on the
// assertions
uint256 portalBalanceBefore = address(optimismPortal2).balance;
uint256 portalBalanceBefore = address(_portal).balance;
uint256 lockboxBalanceBefore = address(ethLockbox).balance;

// Expect `donateETH` function to be called on Portal
vm.expectCall(address(optimismPortal2), abi.encodeCall(IOptimismPortal2.donateETH, ()));
vm.expectCall(address(_portal), abi.encodeCall(IOptimismPortal2.donateETH, ()));

// Look for the emit of the `ETHUnlocked` event
vm.expectEmit(address(ethLockbox));
emit ETHUnlocked(optimismPortal2, _value);
emit ETHUnlocked(_portal, _value);

// Call the `unlockETH` function with the portal
vm.prank(address(optimismPortal2));
vm.prank(address(_portal));
ethLockbox.unlockETH(_value);

// Assert the portal's balance increased and the lockbox's balance decreased by the amount
// unlocked
assertEq(address(optimismPortal2).balance, portalBalanceBefore + _value);
assertEq(address(_portal).balance, portalBalanceBefore + _value);
assertEq(address(ethLockbox).balance, lockboxBalanceBefore - _value);
}
}
Expand Down Expand Up @@ -532,11 +516,7 @@ contract ETHLockbox_AuthorizeLockbox_Test is ETHLockbox_TestInit {
function testFuzz_authorizeLockbox_succeeds(address _lockbox) public {
assumeNotForgeAddress(_lockbox);

// Mock the admin owner of the lockbox to be the same as the current lockbox proxy admin
// owner
vm.mockCall(
address(_lockbox), abi.encodeCall(IProxyAdminOwnedBase.proxyAdminOwner, ()), abi.encode(proxyAdminOwner)
);
_mockLockboxSharedOwner(_lockbox);

// Expect the `LockboxAuthorized` event to be emitted
vm.expectEmit(address(ethLockbox));
Expand Down Expand Up @@ -611,16 +591,6 @@ contract ETHLockbox_MigrateLiquidity_Test is ETHLockbox_TestInit {
vm.prank(proxyAdminOwner);
IETHLockbox(destinationLockbox).authorizeLockbox(ethLockbox);

// Mock the calls for checks on the destination lockbox so it can receive the migration
vm.mockCall(
address(destinationLockbox),
abi.encodeCall(IProxyAdminOwnedBase.proxyAdminOwner, ()),
abi.encode(proxyAdminOwner)
);
vm.mockCall(
address(destinationLockbox), abi.encodeCall(IETHLockbox.authorizedLockboxes, (ethLockbox)), abi.encode(true)
);

// Deal the balance to both lockboxes
deal(address(ethLockbox), _originLockboxBalance);
deal(address(destinationLockbox), _destinationLockboxBalance);
Expand Down
Loading
Loading