Skip to content

Latest commit

 

History

History
70 lines (45 loc) · 2.51 KB

函数选择器.md

File metadata and controls

70 lines (45 loc) · 2.51 KB

函数选择器

当一个函数被调用时,calldata 的前 4 个字节指定调用哪个函数。

这 4 个字节称为函数选择器。

举个例子,下面这段代码。 它使用 call 在地址 addr 的合约上执行转账。 addr.call(abi.encodeWithSignature("transfer(address,uint256)", 0xSomeAddress, 123))

abi.encodeWithSignature(....) 返回的前 4 个字节是函数选择器。

如果在代码中预先计算并内联函数选择器,也许可以节省少量气体?

以下是函数选择器的计算方式。

代码实现

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

contract FunctionSelector {
    /*
    "transfer(address,uint256)"
    0xa9059cbb
    "transferFrom(address,address,uint256)"
    0x23b872dd
    */
    function getSelector(string calldata _func) external pure returns (bytes4) {
        return bytes4(keccak256(bytes(_func)));
    }
}

在上面的示例中,我们定义了一个名为 FunctionSelector 的合约。该合约包含两个函数:

  • foo() 函数返回当前函数选择器(即 this.foo.selector)。
  • bar(bytes memory _data) 函数将 _data 参数解码为 bytes4 值,并将其作为返回值返回。

解释

函数选择器

在 Solidity 中,每个函数都有一个唯一的函数选择器(function selector)。函数选择器是函数名称和参数类型的哈希值。在智能合约内部,可以使用函数选择器来调用其他合约的函数。

在示例中,我们使用 this.foo.selector 返回 foo() 函数的函数选择器。

abi.decode()

abi.decode() 是 Solidity 中的一个特殊函数,用于将字节数组解码为给定的类型。在示例中,我们使用 abi.decode()_data 参数解码为 bytes4 类型。

return abi.decode(_data[:4], (bytes4));

在上面的示例中,我们使用 _data[:4] 将字节数组的前四个字节作为输入,并将其解码为 bytes4 类型。该函数的第二个参数指定解码结果的类型。

运行示例

使用 Remix 或其他 Solidity 集成开发环境编译和部署合约。在部署后,您可以调用 foo() 函数并获取当前函数选择器:

0x8f4a7106

将此值传递给 bar(bytes memory _data) 函数,它将返回相同的函数选择器。

总结

Solidity 的函数选择器是函数名称和参数类型的哈希值。使用函数选择器,智能合约可以方便地调用其他合约的函数。abi.decode() 函数可将字节数组解码为给定的类型。