diff --git a/src/utils/EnumerableSetLib.sol b/src/utils/EnumerableSetLib.sol index 723edb4e2..79729d9e3 100644 --- a/src/utils/EnumerableSetLib.sol +++ b/src/utils/EnumerableSetLib.sol @@ -772,6 +772,7 @@ library EnumerableSetLib { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { + value := shr(96, shl(96, value)) if iszero(value) { value := _ZERO_SENTINEL } result := not(0) let rootPacked := sload(rootSlot) diff --git a/src/utils/g/EnumerableSetLib.sol b/src/utils/g/EnumerableSetLib.sol index 2a240a9ab..bee5f85ee 100644 --- a/src/utils/g/EnumerableSetLib.sol +++ b/src/utils/g/EnumerableSetLib.sol @@ -780,6 +780,7 @@ library EnumerableSetLib { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { + value := shr(96, shl(96, value)) if iszero(value) { value := _ZERO_SENTINEL } result := not(0) let rootPacked := sload(rootSlot) diff --git a/test/EnumerableSetLib.t.sol b/test/EnumerableSetLib.t.sol index a8964ba61..aa767cf79 100644 --- a/test/EnumerableSetLib.t.sol +++ b/test/EnumerableSetLib.t.sol @@ -904,4 +904,36 @@ contract EnumerableSetLibTest is SoladyTest { } } } + + function testIndexOfDirtyUpperBits() public { + addressSet.add(address(0)); + for (uint256 i = 1; i != 5; ++i) { + addressSet.add(address(uint160(i))); + } + assertEq(addressSet.length(), 5); + + address dirtyZero = _dirtyAddress(address(0), 1); + assertTrue(addressSet.contains(dirtyZero)); + assertEq(addressSet.indexOf(dirtyZero), 0); + + address dirtyThree = _dirtyAddress(address(uint160(3)), 0xabc); + assertTrue(addressSet.contains(dirtyThree)); + assertEq(addressSet.indexOf(dirtyThree), addressSet.indexOf(address(uint160(3)))); + } + + function testIndexOfDirtyUpperBitsLazy() public { + addressSet.add(address(0)); + addressSet.add(address(uint160(1))); + assertEq(addressSet.length(), 2); + + assertEq(addressSet.indexOf(_dirtyAddress(address(0), 1)), 0); + assertEq(addressSet.indexOf(_dirtyAddress(address(uint160(1)), 0xabc)), 1); + } + + function _dirtyAddress(address a, uint256 dirt) internal pure returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := or(a, shl(160, dirt)) + } + } }