Skip to content

Latest commit

 

History

History
107 lines (94 loc) · 3.59 KB

File metadata and controls

107 lines (94 loc) · 3.59 KB

选择器

当我们调用合约时,本质上是向该合约发送了一段calldata,可以在input(输入)中看到此次交易的calldata 发送calldata的前4个字节是selector(函数选择器),后面32个字节是输入的参数,其实calldata就是告诉合约,我要 调用哪个函数,以及参数是什么

msg.data

msg.data = method id + 32个字节的参数

method id,selector

method id 是函数签名哈希值的前4个字节

函数签名

函数签名 = 函数名(逗号分割的参数类型)

基础类型参数

只需要计算bytes4(keccak256("函数名(参数类型1,参数类型2,...)))

  // elementary(基础)类型参数selector
  // 输入:param1: 1,param2: 0
  // elementaryParamSelector(uint256,bool) : 0x3ec37834
  function elementaryParamSelector(uint256 param1, bool param2) external returns(bytes4 selectorWithElementaryParam){
    emit SelectorEvent(this.elementaryParamSelector.selector);
    return bytes4(keccak256("elementaryParamSelector(uint256,bool)"));
  }

固定长度类型参数

  // fixed size(固定长度)类型参数selector
  // 输入: param1: [1,2,3]
  // fixedSizeParamSelector(uint256[3]) : 0xead6b8bd
  function fixedSizeParamSelector(uint256[3] memory param1) external returns(bytes4 selectorWithFixedSizeParam){
    emit SelectorEvent(this.fixedSizeParamSelector.selector);
    return bytes4(keccak256("fixedSizeParamSelector(uint256[3])"));
  }

可变长度类型参数

  // non-fixed size(可变长度)类型参数selector
  // 输入: param1: [1,2,3], param2: "abc"
  // nonFixedSizeParamSelector(uint256[],string) : 0xf0ca01de
  function nonFixedSizeParamSelector(uint256[] memory param1,string memory param2) external returns(bytes4 selectorWithNonFixedSizeParam){
    emit SelectorEvent(this.nonFixedSizeParamSelector.selector);
    return bytes4(keccak256("nonFixedSizeParamSelector(uint256[],string)"));
  }

映射参数类型

contract DemoContract {
  // empty contract
}

contract Selector{
  // Struct User
  struct User {
    uint256 uid;
    bytes name;
  }
  // Enum School
  enum School { SCHOOL1, SCHOOL2, SCHOOL3 }
  ...
  // mapping(映射)类型参数selector
  // 输入:demo: 0x9D7f74d0C41E726EC95884E0e97Fa6129e3b5E99, user: [1, "0xa0b1"], count: [1,2,3], mySchool: 1
  // mappingParamSelector(address,(uint256,bytes),uint256[],uint8) : 0xe355b0ce
  function mappingParamSelector(DemoContract demo, User memory user, uint256[] memory count, School mySchool) external returns(bytes4 selectorWithMappingParam){
    emit SelectorEvent(this.mappingParamSelector.selector);
    return bytes4(keccak256("mappingParamSelector(address,(uint256,bytes),uint256[],uint8)"));
  }
  ...
}

使用selector

// 使用selector来调用函数
function callWithSignature() external{
...
    // 调用elementaryParamSelector函数
    (bool success1, bytes memory data1) = address(this).call(abi.encodeWithSelector(0x3ec37834, 1, 0));
...
}

Try Catch

语法

try externalContract.f(){
    // 成功
}catch{
    // 失败
}

try externalContract.f() returns(returnType){
    // call成功的情况下 运行一些代码
} catch Error(string memory /*reason*/) {
    // 捕获revert("reasonString") 和 require(false, "reasonString")
} catch Panic(uint /*errorCode*/) {
    // 捕获Panic导致的错误 例如assert失败 溢出 除零 数组访问越界
} catch (bytes memory /*lowLevelData*/) {
    // 如果发生了revert且上面2个异常类型匹配都失败了 会进入该分支
    // 例如revert() require(false) revert自定义类型的error
}