5

I have got as far as generating the method ID for the function:

function transfer(address src, address dst, uint256 amount);

The method ID would be:

bytes4(keccak256("transfer(address,address,uint256)")) // 0xbeabacc8

How do I pass the function variables (on-chain) along with the method ID to a function:

function execute(address _target, bytes _data)

Where _data is the calldata of the transfer function.

2
  • Are you trying to call this on-chain or off-chain? Feb 27, 2020 at 17:50
  • 1
    This is an on-chain call, will update
    – Nick
    Feb 27, 2020 at 18:31

3 Answers 3

5

You can execute the call the following way (members of addresses, abi.encode*, low-level calls):

Example 1: Call using already calculated function signature (this answers your question)


bytes memory transferPayload = abi.encodeWithSelector(bytes4(0xbeabacc8), param1, param2, param3);
bytes memory executePayload = abi.encodeWithSignature("execute(address,bytes)", transferContractAdr, transferPayload);
(bool success, bytes memory returnData) = address(executeContractAdr).call(executePayload);
require(success, "low-level call of function execute failed [transfer(address,address,uint256), param1, param2, param3]");

Example 2: Call function and let Solidity automatically calculate the function signature


Just replace

bytes memory transferPayload = abi.encodeWithSelector(bytes4(0xbeabacc8), param1, param2, param3);

with

bytes memory transferPayload = abi.encodeWithSignature("transfer(address,address,uint256)", param1, param2, param3);

note 1: Please consider which call (call, callcode, delegatecall, staticcall) will be appropriate for your scenario

note 2: Replace the require statement with an appropriate try-catch block

note 3: If you call a function in the same contract, you can use address(this)

2

For on-chain transactions, you can use abi.encodeWithSelector. This article has a ton of great information about it.

In your case, you can do the following:

bytes4 methodSig = 0xbeabacc8;
address addressOne = address(0);
address addressTwo = address(1);
uint256 uintOne = 2;
abi.encodeWithSelector(
    methodSig,   
    addressOne,
    addressTwo,
    uintOne
);

See the official Solidity docs for more info.

1

Example 3: Use an interface and let Solidity handle the encodings for you


interface IExecute {
    function execute(address _target, bytes calldata _data) external;
}

bytes memory transferPayload = abi.encodeWithSignature(
    "transfer(address,address,uint256)",
    from, to, amount
);

IExecute(executeContractAddress).execute(
    transferContractAddress,
    transferPayload
);

Or even better, (this may not apply if you have specific logic in your execute function)

Example 4: Skip the execute contract altogether and create a direct interface


interface ITransfer {
    function transfer(address src, address dst, uint256 amount) external;
}

ITransfer(transferContractAddress).transfer(from, to, amount);

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.