On-chain call from another contract
You can use abi.encode and abi.encodePacked to encode the data to bytes.
pragma solidity ^0.8.0;
contract MyContract {
function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external {
}
function passArray() external {
bytes memory data = abi.encode([
address(0x33),
address(0x44)
]);
this.uniswapV2Call(address(0x233), 1, 0, data);
}
function passFuncionCall() external {
bytes memory data = abi.encodePacked(
bytes4(keccak256('anotherfunction(uint256,address)')), // function signature
abi.encode(
123, // `anotherfunction()` arguments
address(0x45)
)
);
this.uniswapV2Call(address(0x233), 1, 0, data);
}
}
abi.encode leaves the leading/trailing (depending on the datatype) zeros of each argument, while abi.encodePacked trims them.
So the combination of encodePacked and encode in the passFunctionCall example returns
0x
58de5f3c // function signature
000000000000000000000000000000000000000000000000000000000000007b // 1st argument
0000000000000000000000000000000000000000000000000000000000000045 // 2nd argument
If you only encoded all params, it would leave the trailing zeros for the bytes4 type, which you don't want in this case, because the recipient would read (hex)"64 zeros" instead of (hex)"7b" as the first argument, the other argument would be incorrect as well, and the (hex)"45" would be ignored.
0x
58de5f3c00000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000007b
0000000000000000000000000000000000000000000000000000000000000045
// same data, just differently formatted for readability
0x
58de5f3c // function signature
0000000000000000000000000000000000000000000000000000000000000000 // 1st argument
0000000000000000000000000000000000000000000000000000007b00000000 // 2nd argument
00000000000000000000000000000000000000000000000000000045 // ignored
Off-chain generate the bytes argument.
You can use web3.eth.abi.encodeParameter() for example to encode the address array
const data = web3.eth.abi.encodeParameter('address[2]', ['0x0000000000000000000000000000000000000033','0x0000000000000000000000000000000000000044']);
returns
0x
0000000000000000000000000000000000000000000000000000000000000033
0000000000000000000000000000000000000000000000000000000000000044
Or you can use the encodeFunctionCall() to get bytes for the function call.
const data = web3.eth.abi.encodeFunctionCall({
name: 'anotherfunction',
type: 'function',
inputs: [{
type: 'uint256',
name: ''
},{
type: 'address',
name: ''
}]
}, ['123', '0x0000000000000000000000000000000000000045']);
returns
0x
58de5f3c // function signature
000000000000000000000000000000000000000000000000000000000000007b // 1st argument
0000000000000000000000000000000000000000000000000000000000000045 // 2nd argument