Skip to content

staticcall is returning an unexpected result #391

@KitHat

Description

@KitHat

Description

There is a difference in regular call vs staticcall invocation of a method in contracts. In the attached contracts if you call ERC165MaliciousData.supportsInterface directly, it will return true. If you pass its address to ERC165Checker.supportsERC165InterfaceUnchecked it will return false.

contract ERC165MaliciousData {
    function supportsInterface(bytes4) public pure returns (bool) {
        assembly {
            mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            return(0, 32)
        }
    }
}

library ERC165Checker {
    function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
        (bool success, bool supported) = _trySupportsInterface(account, interfaceId);
        return success && supported;
    }

    function _trySupportsInterface(
        address account,
        bytes4 interfaceId
    ) private view returns (bool success, bool supported) {
        bytes4 selector = IERC165.supportsInterface.selector;

        assembly ("memory-safe") {
            mstore(0x00, selector)
            mstore(0x04, interfaceId)
            success := staticcall(30000, account, 0x00, 0x24, 0x00, 0x20)
            supported := and(
                gt(returndatasize(), 0x1F), // we have at least 32 bytes of returndata
                iszero(iszero(mload(0x00))) // the first 32 bytes of returndata are non-zero
            )
        }
    }
}

interface IERC165 {
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Environment

Substrate Revive Node: 19907546951
Solidity Version: 0.8.28
Test Framework: Hardhat
Chain ID: 420420420 (Revive local network)

Prerequisites

  1. Clone the reproduction repository:
git clone https://github.com/KitHat/erc165-error
  1. Copy the node binaries to the bin directory

Steps to reproduce

Run the tests in the reproduction repository:

npx hardhat test

Error log:

  ERC165
    1) should return true with a staticcall
    ✔ should return true with a regular call


  1 passing (321ms)
  1 failing

  1) ERC165
       should return true with a staticcall:

      AssertionError: expected false to be true
      + expected - actual

      -false
      +true
      
      at Context.<anonymous> (test/ERC165.test.js:13:90)
      at processTicksAndRejections (node:internal/process/task_queues:105:5)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions