面试官:Solidity-Call, Delegatecall,Staticcall 区别说一下

731 阅读2分钟

最近在面试的过程中,被面试官问到一个问题:Call, DelegateCall, StaticCall区别。

1. Call

推荐的方式,但是容易发生重入攻击

contract Called {

  uint public number;

  function increment() public {
    number++;
  }
  
  function increment2(uint _increment) public returns (uint) {
  number = number + _increment;
  return number;
}
}
contract Caller {

address public called = 0xd9145CCE52D386f254917e481eB44e9943F39138; 
    
function callCalled() public returns(bool, bytes memory) {
        
    (bool success,bytes memory data) = called.call(abi.encodeWithSignature("increment()"));
    
    return (success, data);
}

}


function callCalled2() public returns(bool, bytes memory) {
// 带参数的函数签名
  (bool success,bytes memory data) = called.call(abi.encodeWithSignature("increment(uint256)",2));
  return (success, data);
}

Call 的参数payload 是函数签名,四个字节

返回bool, value

返回值可以使用:

 uint decoded = abi.decode(data, (uint256)); 

进行解码。

Call 的另一个重要的用法

发送ether

address.call{value: 1 ether, gas: 10000}("")

2. Staticcall

和Call 相似,但是不允许改变变量状态。

上面这段代码会报错,原因是更改了变量的状态。

(, bytes memory data) = called.staticcall(abi.encodeWithSignature("number()"));

这种调用view 或者public变量就是合法的。

3. detegatecall

contract Called {

  uint public number;

  function setNumber(uint _number) public {
    number = _number;
  }
}

contract Caller {

  uint public number;
  address public called = 0xd9145CCE52D386f254917e481eB44e9943F39138;
  
  function callSetNumber(uint _number) public {
    called.delegatecall(abi.encodeWithSignature("setNumber(uint256)",_number));
  }
}

contract Caller2 {

  address public called = 0xd9145CCE52D386f254917e481eB44e9943F39138;
  uint public number;
  
  function callSetNumber(uint _number) public {
    called.delegatecall(abi.encodeWithSignature("setNumber(uint256)",_number));
  }
}

Caller 合约在调用的时候,会更改Caller 中的number。并且number变量是可以不声明的。

delegatecall 返回两个值bool, value。

需要注意的是:

在上述的函数中我们在caller中声明了number和called合约中的变量是一个位置。也就是同一个slot(0号位置)。如果改变位置,那么调用callSetNumber方法将会同样修改slot 为0的位置。

也就是Caller2 展示的那样。

个人网站

ChainDeveloper