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?

11
+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) }
}
  • 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. – Micah Zoltu Aug 1 '17 at 14:40
  • There is no such way currently. – axic Aug 1 '17 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? – zeekay May 4 '18 at 18:27

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.