6

Let's suppose I have a simple delegatecall based relay contract. It looks up the contract implementation from a registry and passes the call to the upgradeable implementation:

contract Relay {

    address public registrarAddr;
    string public name;

    function Relay(address _registrarAddr, string _name) {
        registrarAddr = _registrarAddr;
        name = _name;
    }

    function getImplAddr() constant returns (address) {
        Registrar registrar = Registrar(registrarAddr);
        return registrar.addr(name);
    }

    function() {
        address currentVersion = this.getImplAddr();
        if(!currentVersion.delegatecall(msg.data)) throw;
    }
}

As you see the current function() {} has a special check for delegatecall return values, as this is based on an example code.

The question is, how delegatecall handle return values? Can I modify this delegatecall hook to perform normal web3 contract.call().balanceOf(addr) style functions for reading public values from the implementation contract? Or if I set up a relay contract do I need to have special logic in place to read the data from the contract what I would normally do with call()? Are there any examples of such arrangements?

1

1 Answer 1

12
+50

delegatecall is not supposed to handle return values as it cannot be aware of the length of the other side (unless there would be a dedicated parameter passed to it). Currently, the delegatecall Solidity built-in method does not support supplying the return value size, nor getting the return value out after the call.

According to the documentation it should always return a boolean signaling the execution outcome. It seems the compiler may currently have a problem, see https://github.com/ethereum/solidity/issues/2678.

To get the result out, you will need to know the return value size and use inline assembly:

assembly {
    let returnSize = 32
    calldatacopy(0xff, 0, calldatasize)
    let _retVal = delegatecall(gas, currentVersion, 0xff, calldatasize, 0, returnSize)
    switch _retval case 0 { revert(0,0) } default { return(0, returnSize) }
}
3
  • Using this syntax (not inline assembly) is there a way to pass return length to delegate call? I know how to do a delegate call with a return value in assembly, but I'm trying really hard to avoid dropping down into inline assembly because it quickly becomes very difficult to read. Aug 1, 2017 at 14:40
  • There is no such way currently.
    – axic
    Aug 1, 2017 at 14:41
  • How do you determine returnSize? What is significance of 32. Is it possible to predict return size (or look it up) per function? May 4, 2018 at 18:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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