Commit 4e9112da authored by clabby's avatar clabby

Break out `perMessageReentrancyGuard` into library

parent 441bb2c0
...@@ -239,7 +239,6 @@ MintManager_mint_Test:test_mint_moreThanCap_reverts() (gas: 142478) ...@@ -239,7 +239,6 @@ MintManager_mint_Test:test_mint_moreThanCap_reverts() (gas: 142478)
MintManager_upgrade_Test:test_upgrade_fromNotOwner_reverts() (gas: 10929) MintManager_upgrade_Test:test_upgrade_fromNotOwner_reverts() (gas: 10929)
MintManager_upgrade_Test:test_upgrade_fromOwner_succeeds() (gas: 23411) MintManager_upgrade_Test:test_upgrade_fromOwner_succeeds() (gas: 23411)
MintManager_upgrade_Test:test_upgrade_toZeroAddress_reverts() (gas: 10958) MintManager_upgrade_Test:test_upgrade_toZeroAddress_reverts() (gas: 10958)
OptimismPortal_Sherlock87_Test:test_finalizeWithdrawalTransaction_gasTooLowBrick_succeeds() (gas: 1073643)
OptimismMintableERC20_Test:test_bridge_succeeds() (gas: 7643) OptimismMintableERC20_Test:test_bridge_succeeds() (gas: 7643)
OptimismMintableERC20_Test:test_burn_notBridge_reverts() (gas: 11142) OptimismMintableERC20_Test:test_burn_notBridge_reverts() (gas: 11142)
OptimismMintableERC20_Test:test_burn_succeeds() (gas: 50960) OptimismMintableERC20_Test:test_burn_succeeds() (gas: 50960)
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
/**
* @title ReentrancyGuard
* @notice A contract that provides custom reentrancy guard modifiers.
*/
contract ReentrancyGuard {
/**
* @notice Modifier for a per-message reentrancy guard.
*/
modifier perMessageNonReentrant(bytes32 _msgHash) {
bytes32 _hashMsgHash;
assembly {
// Re-hash the `_msgHash` with the `0xcafebabe` salt to reduce the possibility
// of collisions with existing storage slots.
mstore(0x00, _msgHash)
mstore(0x20, 0xcafebabe)
_hashMsgHash := keccak256(0x00, 0x40)
// Check if the reentrancy lock for the `_msgHash` is set. If so, revert.
if sload(_hashMsgHash) {
// MEMORY SAFETY: We're reverting, so it's fine that we're clobbering the free memory
// pointer.
// Store selector for "Error(string)" in scratch space
mstore(0x00, 0x08c379a0)
// Store pointer to the string in scratch space
mstore(0x20, 0x20)
// Add the length of the "ReentrancyGuard: reentrant call" string (31 bytes)
mstore(0x40, 0x1f)
// Store "ReentrancyGuard: reentrant call" in the zero slot
// (plus a 0 byte for padding)
mstore(0x60, 0x5265656e7472616e637947756172643a207265656e7472616e742063616c6c00)
// Revert with 'Error("ReentrancyGuard: reentrant call")'
revert(0x1c, 0x64)
}
// Trigger the reentrancy lock for `_msgHash`.
sstore(_hashMsgHash, 0x01)
}
_;
assembly {
// Clear the reentrancy lock for `_msgHash`
sstore(_hashMsgHash, 0x00)
}
}
}
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
import { ReentrancyGuard } from "../libraries/ReentrancyGuard.sol";
contract ReentrancyGuard_Test is Test {
/// @dev The message hash passed to `noReentrance`
bytes32 internal constant MSG_HASH = keccak256(abi.encode("MESSAGE_HASH"));
NonReentrant internal reentrant;
function setUp() public {
reentrant = new NonReentrant();
}
function test_perMessageNonReentrant_reverts() public {
vm.expectRevert("ReentrancyGuard: reentrant call");
reentrant.noReentrance(MSG_HASH);
}
fallback() external {
reentrant.noReentrance(MSG_HASH);
}
}
contract NonReentrant is ReentrancyGuard {
function noReentrance(bytes32 _hash) external perMessageNonReentrant(_hash) {
assembly {
let success := call(
gas(),
caller(),
0,
0,
0,
0,
0
)
returndatacopy(0x00, 0x00, returndatasize())
switch success
case 0 {
revert(0x00, returndatasize())
}
default {
return(0x00, returndatasize())
}
}
}
}
...@@ -14,6 +14,7 @@ import { SafeCall } from "../libraries/SafeCall.sol"; ...@@ -14,6 +14,7 @@ import { SafeCall } from "../libraries/SafeCall.sol";
import { Hashing } from "../libraries/Hashing.sol"; import { Hashing } from "../libraries/Hashing.sol";
import { Encoding } from "../libraries/Encoding.sol"; import { Encoding } from "../libraries/Encoding.sol";
import { Constants } from "../libraries/Constants.sol"; import { Constants } from "../libraries/Constants.sol";
import { ReentrancyGuard } from "../libraries/ReentrancyGuard.sol";
/** /**
* @custom:legacy * @custom:legacy
...@@ -44,7 +45,8 @@ abstract contract CrossDomainMessenger is ...@@ -44,7 +45,8 @@ abstract contract CrossDomainMessenger is
CrossDomainMessengerLegacySpacer, CrossDomainMessengerLegacySpacer,
OwnableUpgradeable, OwnableUpgradeable,
PausableUpgradeable, PausableUpgradeable,
ReentrancyGuardUpgradeable ReentrancyGuardUpgradeable,
ReentrancyGuard
{ {
/** /**
* @notice Current message version identifier. * @notice Current message version identifier.
...@@ -176,44 +178,6 @@ abstract contract CrossDomainMessenger is ...@@ -176,44 +178,6 @@ abstract contract CrossDomainMessenger is
*/ */
event FailedRelayedMessage(bytes32 indexed msgHash); event FailedRelayedMessage(bytes32 indexed msgHash);
/**
* @notice Modifier for a per-message reentrancy guard.
*/
modifier perMessageNonReentrant(bytes32 _msgHash) {
bytes32 _hashMsgHash;
assembly {
// Re-hash the `_msgHash` with the `0xcafebabe` salt to reduce the possibility
// of collisions with existing storage slots.
mstore(0x00, _msgHash)
mstore(0x20, 0xcafebabe)
_hashMsgHash := keccak256(0x00, 0x40)
// Check if the reentrancy lock for the `_msgHash` is set. If so, revert.
if sload(_hashMsgHash) {
// SAFETY: We're reverting, so it's fine that we're clobbering the free memory
// pointer.
// Store selector for "Error(string)" in scratch space
mstore(0x00, 0x08c379a0)
// Store pointer to the string in scratch space
mstore(0x20, 0x20)
// Add the length of the "ReentrancyGuard: reentrant call" string (31 bytes)
mstore(0x40, 0x1f)
// Store "ReentrancyGuard: reentrant call" in the zero slot (plus a 0 byte for padding)
mstore(0x60, 0x5265656e7472616e637947756172643a207265656e7472616e742063616c6c00)
// Revert with 'Error("ReentrancyGuard: reentrant call")'
revert(0x1c, 0x64)
}
// Trigger the reentrancy lock for `_msgHash`.
sstore(_hashMsgHash, 0x01)
}
_;
assembly {
// Clear the reentrancy lock for `_msgHash`
sstore(_hashMsgHash, 0x00)
}
}
/** /**
* @param _otherMessenger Address of the messenger on the paired chain. * @param _otherMessenger Address of the messenger on the paired chain.
*/ */
......
...@@ -242,7 +242,11 @@ const check = { ...@@ -242,7 +242,11 @@ const check = {
signer signer
) )
await assertSemver(L2CrossDomainMessenger, 'L2CrossDomainMessenger', '1.1.0') await assertSemver(
L2CrossDomainMessenger,
'L2CrossDomainMessenger',
'1.1.0'
)
const xDomainMessageSenderSlot = await signer.provider.getStorageAt( const xDomainMessageSenderSlot = await signer.provider.getStorageAt(
predeploys.L2CrossDomainMessenger, predeploys.L2CrossDomainMessenger,
......
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