0

For example I want to write a contract where when one passes the address of another contract to it, it will check whether this other contract has the name() function, and if the name() function returns a proper result, it will record the result of the name() function mapped to the address, otherwise it will record an empty string mapped to the address.

I don't want to do it off-chain as I want to be sure the address to name string mappings recorded in my contract are always the correct ones (or at least as correct as the blockchain itself), not susceptible to centralized manipulation or off-chain program bugs.

So far the only way I've found is to use inline assembly to read the bytecode from the address, and search for "name()"'s function signature (which is 06fdde03), but this kind of bytecode search is quite awkward and potentially very expensive. I wonder if there are better ways to accomplish this?


EDIT 1:

EIP165 is not the answer since it only specified to provide information for mandatory methods and specifically says optional methods should not be included in the interface specifier. Thus for example you can't know whether an ERC20 Token has the name(), symbol(), and decimals() functions with EIP165.

Also I'd say this question is not a duplicate of the How to check if a contract has a method? question since I'm thinking about more specific use cases, more specifically the optional methods in contract standards.


EDIT 2:

After some research, it seems for those optional pure/view functions, the noThrowCall function in the EIP165 example code can be modified for this purpose. After some more searching around, I come up with the following code

pragma solidity >= 0.5.0;

library GetName {
    function readOptional(address addr, bytes memory data) internal view returns (bytes memory result) {
        bool success;
        bytes memory retData;
        (success, retData) = addr.staticcall(data);
        if (success) {
            return retData;
        } else {
            return abi.encode(0x0);
        }
    }

    function getNameOrEmpty(address addr) internal view returns (string memory result) {
        return abi.decode(readOptional(addr, abi.encodeWithSignature("name()")), (string));
    }
}

contract Testing {
    using GetName for address;

    mapping (address => string) public record;

    function recordName(address addr) public {
        record[addr] = addr.getNameOrEmpty();
    }
}

This contract will record the return value of the name() function while record an empty string when the input address does not have a name() function. However there's still a problem that if the contract at the input address has a name() function that returns not a string but an int or something, the above code will still throw an error and revert. I don't mind recording an empty string if the name() function does not return a string (since that means it does not adhere to the ERC20's optional name function), but I don't want it to throw and revert, any idea?

  • What parameters does the function take and what does it return? – goodvibration Aug 22 at 11:24
  • @goodvibration, for real applications it should be arbitrary, for this example it's just a name() function which takes no argument and returns a string/bytes result. – hellopeach Aug 22 at 11:27
  • Do you happen to know the maximum length of the return-value? – goodvibration Aug 22 at 11:30
  • @goodvibration, for real applications, no, for this example, let's say 256 bytes? – hellopeach Aug 22 at 11:39
  • There's no way to check that besides using EIP 165. Checking bytecode doesn't work if the target contract is a proxy that only executes a delegatecall, also the compiler can generate optimized code that gets rid of functions ids. – Ismael Aug 22 at 16:36

Your Answer

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

Browse other questions tagged or ask your own question.