底层调用,函数选择器生成

底层调用

在 Solidity 中底层调用分为三个:call, delegatecall,staticcall,在 Solidity 中,使用这些底层调用都需要传递函数选择器,而函数选择器是函数签名的keccak256哈希值的前4个字节,要生成函数选择器,这时候就需要使用到abi编码进制转换

函数选择器生成

主要应用 abi 编码中的 abi.encodeWithSignature()bytes4强制类型转换,来生成函数选择器

详细的 abi 编码请看文章abi编码解码详解

关于进制转换:

高位整数转换到低位整数舍弃高位(eg:uint32 a = 0x12345678 => uint16 b = uint16(a) => b == 0x5678)

低位整数转换到高位整数高位补零(eg:uint16 a = 0x1234 => uint32 b = uint32(a) => a == 0x00001234 ,并且 a == b)

高位字节转换到低位字节舍弃低位(eg:bytes2 a = 0x1234 => bytes1 b = bytes1(a) => b == 0x12)

低位字节转换到高位字节低位补零(eg:bytes1 a = 0x12 => bytes2 b = bytes2(a) => b == 0x1200,并且 a[0] ==b[0] )

详细的进制转换请看文章:Solidity类型转换相关

// create selector
bytes4 selectorA = bytes4(abi.encodeWithSignature("getValue(address,uint256)"))
bytes4 selectorB = bytes4(abi.encodeWithSignature("getValue()"))

使用abi.encodeWithSignature()bytes4()生成函数选择器时要注意

  • 如果函数签名没有参数,也依然要写()
  • 传递函数签名时,两个参数只用,隔开,不要在两个参数中间添加空格,这样生成的函数选择器与实际的函数选择器不一样

使用 Foundry 内置的 chisel 试验一下计算函数选择器:

image-20231122181457680

上图中,下面的是真实的函数选择器,可以发现,生成函数选择器时,两个参数之间不能加上空格

image-20231122181550816

上图中,上面的是真实的函数选择器,可以发现,生成函数选择器时,如果函数没有参数,也是需要传递()