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
10 changes: 10 additions & 0 deletions test/src/concrete/Extrospect.checkNotEOFBytecode.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ contract ExtrospectCheckNotEOFBytecodeTest is ExtrospectEquivalence {
LibExtrospectBytecode.checkNotEOFBytecode(clean);
}

/// Bytecode whose only notable content is a reachable CREATE (a metamorphic
/// risk op) is NOT EOF, so this must return without reverting. Pins that
/// `checkNotEOFBytecode` delegates to the EOF check and not to the
/// metamorphic check, which would revert `Metamorphic(1 << 0xF0)` here.
function testCheckNotEOFBytecodeMetamorphicButNotEOF() external view {
bytes memory createOnly = hex"F0";
extrospect.checkNotEOFBytecode(createOnly);
LibExtrospectBytecode.checkNotEOFBytecode(createOnly);
}

function testCheckNotEOFBytecodeEquivalenceRevert() external {
bytes memory eof = hex"EF00010203";
vm.expectRevert(LibExtrospectBytecode.EOFBytecodeNotSupported.selector);
Expand Down
27 changes: 27 additions & 0 deletions test/src/concrete/Extrospect.isERC1167Proxy.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,31 @@ contract ExtrospectIsERC1167ProxyTest is ExtrospectEquivalence {
assertEq(extIsProxy, libIsProxy);
assertEq(extImpl, libImpl);
}

/// A well-formed ERC1167 proxy: the concrete must return the implementation
/// address embedded in the bytecode, not just the boolean. A delegation
/// that dropped the second return component would yield address(0) here.
function testIsERC1167ProxyConcreteImplementationAddress() external view {
address expectedImplementation = address(0x00112233445566778899AABbCCdDeeFf00112233);
bytes memory proxy =
abi.encodePacked(hex"363d3d373d3d3d363d73", expectedImplementation, hex"5af43d82803e903d91602b57fd5bf3");
assertEq(proxy.length, 45);
(bool extIsProxy, address extImpl) = extrospect.isERC1167Proxy(proxy);
assertTrue(extIsProxy);
assertEq(extImpl, expectedImplementation);
}

/// EOF bytecode of exactly the ERC1167 proxy length returns
/// `(false, address(0))` through the external entry point rather than
/// reverting.
function testIsERC1167ProxyEquivalenceEOF() external view {
bytes memory bytecode =
hex"EF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
(bool extIsProxy, address extImpl) = extrospect.isERC1167Proxy(bytecode);
(bool libIsProxy, address libImpl) = LibExtrospectERC1167Proxy.isERC1167Proxy(bytecode);
assertFalse(extIsProxy);
assertEq(extImpl, address(0));
assertEq(extIsProxy, libIsProxy);
assertEq(extImpl, libImpl);
}
}
10 changes: 10 additions & 0 deletions test/src/concrete/Extrospect.scanEVMOpcodesPresentInBytecode.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,14 @@ contract ExtrospectScanEVMOpcodesPresentInBytecodeTest is ExtrospectEquivalence
function testScanEVMOpcodesPresentInBytecodeEquivalenceEOF() external {
assertScanEquivalence(hex"EF0000");
}

/// `hex"00F0"` is STOP followed by CREATE, so CREATE is present in the
/// bytecode but unreachable (no JUMPDEST resumes execution after the halt).
/// The concrete must report the PRESENT bitmap — STOP and CREATE — which a
/// delegation to the reachable scan would not contain.
function testScanEVMOpcodesPresentInBytecodeUnreachableCreateCounted() external view {
//forge-lint: disable-next-line(incorrect-shift)
uint256 expected = uint256(1) | (uint256(1) << uint256(0xF0));
assertEq(extrospect.scanEVMOpcodesPresentInBytecode(hex"00F0"), expected);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,13 @@ contract ExtrospectScanEVMOpcodesReachableInBytecodeTest is ExtrospectEquivalenc
function testScanEVMOpcodesReachableInBytecodeEquivalenceEOF() external {
assertScanEquivalence(hex"EF0000");
}

/// `hex"00F0"` is STOP followed by CREATE, so only STOP is reachable. The
/// concrete must report the REACHABLE bitmap, which a delegation to the
/// present scan would pollute with the CREATE bit.
function testScanEVMOpcodesReachableInBytecodeUnreachableCreateNotCounted() external view {
//forge-lint: disable-next-line(incorrect-shift)
uint256 expected = uint256(1);
assertEq(extrospect.scanEVMOpcodesReachableInBytecode(hex"00F0"), expected);
}
}
Loading