1

I have a special contract with few extra functions. In the transfer wei function I want to send it to the special method or if receiver doesn't have it (because is a wallet or doesn't inherit from my abstract or interface), via normal transfer. How can I check if addressTo inherits from my special interface or abstract contract that contain my payable function?

  • Does this interface contain non-constant functions? – goodvibration Apr 8 at 8:46
  • It contains canHoldWei external view, receiveWei external payable, getBalance public view, transfer public – Radeg90 Apr 8 at 8:55
0

Smart contract inheritance and interfaces are a syntactic sugar in Solidity. They cannot be recognized from byte code. So the only thing you may probably check is that byte code of a smart contract you are calling is exactly the one you need. To do so you should use assembly instructions extcodesize and extcodecopy.

0

If all the functions in your special interface are constant (either pure or view), then you can call function external_call (see Gnosis MultiSigWallet) for each one of the functions in your special interface, and then determine that to is the address of a special contract if and only if all the calls have returned true.

For example, suppose that you have:

interface SpecialInterface {
    function func1(uint256) external pure returns (bool);
    function func2(uint256, bool) external pure returns (uint256);
    function func3(uint256, uint256) external pure returns (bool);
}

Then in your transfer function, you can check the to address as follows:

contract MyErc20Contract {
    function transfer(address to, uint256 value) public returns (bool) {
        bytes32 data1 = keccak256("func1(uint256)");
        bytes32 data2 = keccak256("func2(uint256,bool)");
        bytes32 data3 = keccak256("func3(uint256,uint256)");
        bool result1 = external_call(to, 0, data1.length, abi.encodePacked(data1));
        bool result2 = external_call(to, 0, data2.length, abi.encodePacked(data2));
        bool result3 = external_call(to, 0, data3.length, abi.encodePacked(data3));
        if (result1 && result2 && result3) {
            // `to` is the address of a special contract
        }
        else {
            // `to` is not the address of a special contract
        }
    }

    function external_call(address destination, uint value, uint dataLength, bytes data) private returns (bool) {
        bool result;
        assembly {
            let x := mload(0x40)   // "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention)
            let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that
            result := call(
                sub(gas, 34710),   // 34710 is the value that solidity is currently emitting
                                   // It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) +
                                   // callNewAccountGas (25000, in case the destination address does not exist and needs creating)
                destination,
                value,
                d,
                dataLength,        // Size of the input (in bytes) - this is what fixes the padding problem
                x,
                0                  // Output is ignored, therefore the output size is zero
            )
        }
        return result;
    }
}

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.