diff --git a/src/libraries/LibNonReentrancy.sol b/src/libraries/LibNonReentrancy.sol index c0889a19..c50073a3 100644 --- a/src/libraries/LibNonReentrancy.sol +++ b/src/libraries/LibNonReentrancy.sol @@ -32,7 +32,9 @@ library LibNonReentrancy { bytes32 position = NON_REENTRANT_SLOT; assembly ("memory-safe") { if tload(position) { - mstore(0x00, 0x43a0d067) + // Store the selector for "Reentrancy()" (0xab143c06) at the beginning of memory. + // We shift left by 224 bits (256 - 32) to left-align the 4-byte selector in the 32-byte slot. + mstore(0x00, shl(224, 0xab143c06)) revert(0x00, 0x04) } tstore(position, 1) diff --git a/test/libraries/LibNonReentrancy.t.sol b/test/libraries/LibNonReentrancy.t.sol new file mode 100644 index 00000000..3a33ee0d --- /dev/null +++ b/test/libraries/LibNonReentrancy.t.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.30; + +import {Test} from "forge-std/Test.sol"; +import {LibNonReentrancy} from "src/libraries/LibNonReentrancy.sol"; +import {NonReentrantHarness} from "test/libraries/harnesses/LibNonReentrancyHarness.sol"; + +contract LibNonReentrancyTest is Test { + NonReentrantHarness internal harness; + + function setUp() public { + harness = new NonReentrantHarness(); + } + + function test_GuardedIncrement_IncrementsCounter() public { + harness.guardedIncrement(); + assertEq(harness.counter(), 1); + } + + function test_GuardedIncrement_AllowsSequentialCalls() public { + harness.guardedIncrement(); + harness.guardedIncrement(); + assertEq(harness.counter(), 2); + } + + function test_RevertWhen_ReenteringFunction() public { + vm.expectRevert(LibNonReentrancy.Reentrancy.selector); + harness.guardedIncrementAndReenter(); + } + + function test_GuardResetsAfterRevert() public { + vm.expectRevert(NonReentrantHarness.ForcedFailure.selector); + harness.guardedIncrementAndForceRevert(); + + harness.guardedIncrement(); + assertEq(harness.counter(), 1); + } +} diff --git a/test/libraries/harnesses/LibNonReentrancyHarness.sol b/test/libraries/harnesses/LibNonReentrancyHarness.sol new file mode 100644 index 00000000..fd31f62d --- /dev/null +++ b/test/libraries/harnesses/LibNonReentrancyHarness.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.30; + +import {LibNonReentrancy} from "src/libraries/LibNonReentrancy.sol"; + +contract NonReentrantHarness { + error ForcedFailure(); + + uint256 public counter; + + function guardedIncrement() public { + LibNonReentrancy.enter(); + counter++; + LibNonReentrancy.exit(); + } + + function guardedIncrementAndReenter() external { + LibNonReentrancy.enter(); + counter++; + + this.guardedIncrement(); + + LibNonReentrancy.exit(); + } + + function guardedIncrementAndForceRevert() external { + LibNonReentrancy.enter(); + counter++; + revert ForcedFailure(); + } +} diff --git a/test/token/ERC6909/ERC6909/ERC6909Facet.t.sol b/test/token/ERC6909/ERC6909/ERC6909Facet.t.sol index 75e12458..1583f628 100644 --- a/test/token/ERC6909/ERC6909/ERC6909Facet.t.sol +++ b/test/token/ERC6909/ERC6909/ERC6909Facet.t.sol @@ -41,6 +41,7 @@ contract ERC6909FacetTest is Test { } function testFuzz_Mint(address caller, address to, uint256 id, uint256 amount) external { + vm.assume(to != address(0)); vm.expectEmit(); emit ERC6909Facet.Transfer(caller, address(0), to, id, amount);