1

I am trying to convert the assembly code into Solidity given at the link: What is a function Selector The code is trying to invoke the function func(...) of Contract1 given below:

contract Contract1 {
    function func(uint256 x, uint8 y) public returns (uint32, uint32) {...}
}
contract Contract2{
/* .......
 */
        assembly
        {
                let success := call(
                    gas,           // pass the remaining gas to the function
                    dest,          // the address of the contract1 instance
                    0,             // pass 0 wei to the function
                    add(data, 32), // the actual data starts after the length of 'data'
                    mload(data),   // the length of 'data' appears at the first 32 bytes
                    ret,           // the address of the output
                    8              // the size of the output
                )
                if iszero(success) {
                    revert(0, 0)
                }
        }
/*....*/
}

Is the following statement correct?

(success, errCode, arg1, arg2) =dest.func.value()(  uint256(789), uint8(123));

arg1 & arg2 would hold the two values returned by func() of Contract1. Somebody please guide me.

Zulfi.

1

You need to write the following:

(bool success, ) = dest.call(data);

As the docs says:

In order to interface with contracts that do not adhere to the ABI, or to get more direct control over the encoding, the functions call, delegatecall and staticcall are provided. They all take a single bytes memory parameter and return the success condition (as a bool) and the returned data (bytes memory). The functions abi.encode, abi.encodePacked, abi.encodeWithSelector and abi.encodeWithSignature can be used to encode structured data.

Suppose the next implementation of the func() of Contract1.

function func(uint256 x, uint8 y) public returns (uint32, uint32) {
    return(uint32(x), uint32(y));
}

Code of Contract2.

contract Contract2 {

    Contract1 public contract1 = new Contract1();

    function func() public returns (uint32, uint32) {

        uint32[2] memory ret;

        address dest = address(contract1);

        bytes4 selector = contract1.func.selector;
        //bytes4 selector = bytes4(keccak256("func(uint256,uint8)"));

        bytes memory data = abi.encodeWithSelector(selector, uint256(789), uint8(123));
        (bool success, ) = dest.call(data);
        require(success);

        assembly {
            let size := returndatasize
            returndatacopy(ret, 0, size)
        }
        return (ret[0], ret[1]);
    }
}

Assembly used here is to manage the returned data of the function call. If you use the tuple (bool success, bytes memory returnData) you will get the returned data as bytes memory and you'll need to convert it to return as two uint32 values.

  • call, send, transfer invoke the fallback function. Is it not possible to call the function by its name? Will this not create a confusion if we have a fallback function in Contract1? – zak100 Jul 1 at 2:26
  • @zak100 Yes, you can call func()by its name if you have the ABI or a contract instance of Contract1, but in the answer I suppose that you want to call the function using the selector without assembly code. It won't create any confusion because the fallback function is called if the contract doesn't recognise the selector or if no selector is provided. – alberto Jul 1 at 8:31

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.