Skip to content

Incorrect interface detector#

Reports multiple different issues when implementing ERC-20/ERC-721/ERC-1155 interfaces.

Missing functions & events#

One or more functions or events are missing from the contract. The recognition is based on the function/event selectors.

Example#

pragma solidity ^0.8;

contract MyToken { // (1)!
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    event Transfer(address indexed from, address indexed to, uint256 value);

    function approve(address spender, uint256 value) external returns (bool) {
        // ...
    }

    function transfer(address to, uint256 value) external returns (bool) {
        // ...
    }
}
  1. The contract does not implement the transferFrom function and the Approval event defined in the ERC20 standard.

Incorrect state mutability#

Some functions are marked as view in the token standards as they are not supposed to modify the state. The detector reports functions that should be marked as view but are not.

Example#

pragma solidity ^0.8;

contract MyToken {
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(
        address indexed owner, address indexed spender, uint256 value
    );

    function totalSupply() external returns (uint256) { // (1)!
        // ...
    }

    function approve(address spender, uint256 value) external returns (bool) {
        // ...
    }

    function transfer(address to, uint256 value) external returns (bool) {
        // ...
    }

    function transferFrom(
        address from, address to, uint256 value
    ) external returns (bool) {
        // ...
    }
}
  1. The totalSupply function should be marked as pure or view, but it is not.

Incorrect return type#

Return types do not affect the function selectors. Still, tokens implemented according to the standard should return values as specified in the standard.

Example#

pragma solidity ^0.8;

contract MyToken {
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(
        address indexed owner, address indexed spender, uint256 value
    );

    function approve(address spender, uint256 value) external { // (1)!
        // ...
    }

    function transfer(address to, uint256 value) external { // (2)!
        // ...
    }

    function transferFrom(
        address from, address to, uint256 value
    ) external { // (3)!
        // ...
    }
}
  1. The approve function should return a bool value, but it does not.
  2. The transfer function should return a bool value, but it does not.
  3. The transferFrom function should return a bool value, but it does not.

Indexed event parameters#

Indexed event parameters do not affect the event selectors, but they still should be used according to the standard.

Example#

pragma solidity ^0.8;

contract MyToken {
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    event Transfer(address indexed from, address to, uint256 value); // (1)!
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 indexed value // (2)!
    );

    function approve(address spender, uint256 value) external returns (bool) {
        // ...
    }

    function transfer(address to, uint256 value) external returns (bool) {
        // ...
    }

    function transferFrom(
        address from, address to, uint256 value
    ) external returns (bool) {
        // ...
    }
}
  1. The to parameter of the Transfer event should be indexed, but it is not.
  2. The value parameter of the Approval event should not be indexed, but it is.

Anonymous events#

Events defined in the token standards should not be anonymous.

Example#

pragma solidity ^0.8;

contract MyToken {
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    event Transfer(
        address indexed from, address indexed to, uint256 value
    ) anonymous; // (1)!
    event Approval(
        address indexed owner, address indexed spender, uint256 value
    );

    function approve(address spender, uint256 value) external returns (bool) {
        // ...
    }

    function transfer(address to, uint256 value) external returns (bool) {
        // ...
    }

    function transferFrom(
        address from, address to, uint256 value
    ) external returns (bool) {
        // ...
    }
}
  1. The Transfer event should not be anonymous, but it is.

Parameters#

Command-line name TOML name Type Default value Description
--erc20-threshold erc20_threshold int 4 Number of ERC-20 functions/events required to consider a contract an ERC-20 token.
--erc721-threshold erc721_threshold int 6 Number of ERC-721 functions/events required to consider a contract an ERC-721 token.
--erc1155-threshold erc1155_threshold int 4 Number of ERC-1155 functions/events required to consider a contract an ERC-1155 token.