0

I would like to use low-level call to make calls to my contract. The function takes a callback function as an argument and I am not able to encode it.

This is my code:

contract B{
   event Foo();
   ...
   function foo(bytes32[10] calldata values,function(int256[] memory, bytes32[] memory) external callback){
       emit Foo();
       ...
   }

}

contract A{

    address b;
    ...

    function bar(){
       (bool success, bytes memory data) = b.call(
            abi.encodeWithSignature(
                "foo(bytes32[10],function(int256[],bytes32[]))",
                myArray,
                this.callback
            )
        );
        if (!success) {
            revert("CALL Failed");
        }
    }

    function callback(int256[] calldata mapInt,bytes32[] calldata mapBytes32) external {
        ...
    }

I did manage to create a correct encoding using web3, which I compared with the signature in the ABI:

var encoded = web3.eth.abi.encodeFunctionSignature({
    name: "foo",
    type: "function",
    inputs: [
        {
            type: "bytes32[10]",
            name: "values",
        },
        {
            type: "function",
            name: "callback",
            inputs: [
                {
                    type: "int256[]",
                },
                {
                    type: "bytes32[]",
                },
            ],
        },
    ],
});

How can I accomplish this in solidity? The encoding in bar() does not work.

Update: Using the bytes4 encoded signature below does not work either:

b.call(abi.encodeWithSelector(bytes4(0x48160c65), myArray,this.callback));
1

From solidity documentation:

If external function types are used outside of the context of Solidity, they are treated as the function type, which encodes the address followed by the function identifier together in a single bytes24 type.

You can calculate the the function signature with web3.eth.abi.encodeFunctionSignature("foo(bytes32[10],function)"). That returns 0x2729727a.

Full example follows:

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

contract B {
   event Foo(uint256 x);

   function foo(bytes32[10] calldata values, function(int256[] memory, bytes32[] memory) external callback) external {
       int256[] memory r = new int256[](1);
       r[0] = 1234;
       bytes32[] memory s = new bytes32[](1);
       s[0] = bytes32(uint256(4321));
       callback(r, s);
       emit Foo(1111);
   }

}

contract A {
    address public b;
    
    event Callback(uint256);
    
    constructor() {
        b = address(new B());
    }

    function bar() public{
        bytes32[10] memory myArray;
        (bool success, bytes memory data) = b.call(
            abi.encodeWithSignature(
                "foo(bytes32[10],function)",
                myArray,
                this.callback
            )
        );
        require(success, "CALL Failed");
    }

    function callback(int256[] calldata mapInt, bytes32[] calldata mapBytes32) external {
        emit Callback(4444);
    }
}

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.