如何在 Solidity 中将地址列表或其他函数作为字节传递?

How to pass list of addresses or another function as bytes in Solidity?

在Uniswap智能合约中有这个方法:

function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data)

我想将其称为作为数据或其他函数的传递地址。

function uniswapV2Call('0x233', 1, 0, ['0x33','0x44'])

function uniswapV2Call('0x233', 1, 0, anotherfunction)

有办法吗?

来自另一个合约的链上调用

您可以使用 abi.encodeabi.encodePacked 将数据 encode 添加到 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 保留每个参数的 leading/trailing(取决于数据类型)零,而 abi.encodePacked 修剪它们。

因此 encodePackedencodepassFunctionCall 示例中的组合 returns

0x
58de5f3c // function signature
000000000000000000000000000000000000000000000000000000000000007b // 1st argument
0000000000000000000000000000000000000000000000000000000000000045 // 2nd argument

如果你只 encoded 所有参数,它会为 bytes4 类型留下尾随零,在这种情况下你不希望这样,因为收件人会读 (hex) "64 zeros" 而不是 (hex)"7b" 作为第一个参数,另一个参数也不正确,并且 (hex)"45" 将被忽略。

0x
58de5f3c00000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000007b
0000000000000000000000000000000000000000000000000000000000000045

// same data, just differently formatted for readability

0x
58de5f3c // function signature
0000000000000000000000000000000000000000000000000000000000000000 // 1st argument
0000000000000000000000000000000000000000000000000000007b00000000 // 2nd argument
00000000000000000000000000000000000000000000000000000045 // ignored

链下生成 bytes 参数。

你可以使用web3.eth.abi.encodeParameter()来编码地址数组

const data = web3.eth.abi.encodeParameter('address[2]', ['0x0000000000000000000000000000000000000033','0x0000000000000000000000000000000000000044']);

returns

0x
0000000000000000000000000000000000000000000000000000000000000033
0000000000000000000000000000000000000000000000000000000000000044

或者您可以使用 encodeFunctionCall() 为函数调用获取 bytes

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