1

I'm trying to verify if an arbitrary contract complies ERC20. While doing so I'm checking if the contract code has the following markers:

totalSupply() - 18160ddd
balanceOf(address) - 70a08231
allowance(address,address) - dd62ed3e
transfer(address,uint256) - a9059cbb
approve(address,uint256) - 095ea7b3
transferFrom(address,address,uint256) - 23b872dd

But for the Reputation token and for some others this technique is not working. Returned code does not have the markers.

https://api.etherscan.io/api?module=proxy&action=eth_getCode&address=0x1985365e9f78359a9B6AD760e32412f4a445E862&tag=latest&apikey=YourApiKeyToken

While it is possible to check the balance with balanceOf function, even though the function signature 70a08231 is not present in the byte code. The same situation is for the totalSupply().

https://etherscan.io/token/0x1985365e9f78359a9B6AD760e32412f4a445E862#readContract

Am I missing something or the token is not complying ERC20? Why are not the markers present in the bytecode?

  • What makes you think it would be a fully-compliant ERC20 token? – Lauri Peltonen Sep 7 '18 at 7:58
  • Just Etherscan shows ERC20 token, but my point is that possible to call balanceOf function while in the bytecode the 70a08231 signature is not present – gagikk Sep 7 '18 at 8:10
  • I am also doing this, recognizing supporting interfaces in a contract, but I have chosen another path, I make the Call() to the contract, and check its output and error , if it produces an error I flag the contract as non-compliant. Your results prove I have chosen the right way, though I thought of checking for signatures too. – Nulik Sep 7 '18 at 13:59
  • my current rule to decide if a contract is ERC20 token is: totalSupply method exists + name method exists + symbol method exists + balanceOf method exists. Even if they return null values I am still considering them as ERC20 – Nulik Sep 7 '18 at 14:03
3

It looks like they actually follow a concept of "Universes", and each universe is an instance of the following:

contract Delegator is DelegationTarget {
    function Delegator(IController _controller, bytes32 _controllerLookupName) public {
        controller = _controller;
        controllerLookupName = _controllerLookupName;
    }

    function() external payable {
        // Do nothing if we haven't properly set up the delegator to delegate calls
        if (controllerLookupName == 0) {
            return;
        }

        // Get the delegation target contract
        address _target = controller.lookup(controllerLookupName);

        assembly {
            //0x40 is the address where the next free memory slot is stored in Solidity
            let _calldataMemoryOffset := mload(0x40)
            // new "memory end" including padding. The bitwise operations here ensure we get rounded up to the nearest 32 byte boundary
            let _size := and(add(calldatasize, 0x1f), not(0x1f))
            // Update the pointer at 0x40 to point at new free memory location so any theoretical allocation doesn't stomp our memory in this call
            mstore(0x40, add(_calldataMemoryOffset, _size))
            // Copy method signature and parameters of this call into memory
            calldatacopy(_calldataMemoryOffset, 0x0, calldatasize)
            // Call the actual method via delegation
            let _retval := delegatecall(gas, _target, _calldataMemoryOffset, calldatasize, 0, 0)
            switch _retval
            case 0 {
                // 0 == it threw, so we revert
                revert(0,0)
            } default {
                // If the call succeeded return the return data from the delegate call
                let _returndataMemoryOffset := mload(0x40)
                // Update the pointer at 0x40 again to point at new free memory location so any theoretical allocation doesn't stomp our memory in this call
                mstore(0x40, add(_returndataMemoryOffset, returndatasize))
                returndatacopy(_returndataMemoryOffset, 0x0, returndatasize)
                return(_returndataMemoryOffset, returndatasize)
            }
        }
    }
}

As you can see, it is simply a proxy contract that uses delegate call to invoke functions on the address returned by the controller. Your actual functions such as balanceOf will be defined on the target contract.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.