Proxy Contract _delegatecall return data

Hi Andrew, @abcoathup

I trust that you are well.

I’m working with the proxy.sol contract in Remix. If I send a transaction with an encoded function call in the payload to my proxy contract, it will trigger the fallback function which will call the below _delegate function. The _delegate function will then send the encoded function call to the implementation contract.

However, the _delegate function doesn’t specify a return variable; only that it does return any returned data if the function call was successful. How do I access that returned data?

  function _delegate(address implementation) internal {
    assembly {
      calldatacopy(0, 0, calldatasize)
      let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0)
      returndatacopy(0, 0, returndatasize)
      switch result
      case 0 { revert(0, returndatasize) }
      default { return(0, returndatasize) }
    }
  }

Cheers.

Sincerely,
Craig

2 Likes

I think when you use Proxy pattern, you can not determine the type of return value, such as, when calls transfer(), it will return bool, and when calls name(), it will return string.

1 Like

Hi @cjd9s,

You can use the ABI of the implementation contract with the address of the proxy to interact with the proxy contract.


In Remix I deployed the Box contract as my implementation contract and then deployed the TransparentUpgradeableProxy using the address of the Box contract, an other address as the admin and initializing with 0x6057361d000000000000000000000000000000000000000000000000000000000000002a
(which is calling store with the value 42).

I then used Remix to interact with a Box contract using the address of the proxy I just deployed.

Box.sol

// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract Box {
    uint256 private value;

    // Emitted when the stored value changes
    event ValueChanged(uint256 newValue);

    // Stores a new value in the contract
    function store(uint256 newValue) public {
        value = newValue;
        emit ValueChanged(newValue);
    }

    // Reads the last stored value
    function retrieve() public view returns (uint256) {
        return value;
    }
}

OpenZeppelinContracts.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.2;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.0/contracts/proxy/TransparentUpgradeableProxy.sol";

MyContract

I used the following to encode the initialization 0x6057361d000000000000000000000000000000000000000000000000000000000000002a

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract MyContract {
    
    function calculate() public pure returns (bytes memory) {
        uint256 value = 42;
        bytes memory payload = abi.encodeWithSignature("store(uint256)", value);

        return payload;
    }
}