Skip to main content

call

1.call是与其他合约交互的低级函数。

当您只是通过调用该函数发送 Ether 时,建议使用此方法fallback。

然而,这不是调用现有函数的推荐方法。

不推荐低级调用的几个原因

  • 恢复不会冒泡
  • 类型检查被绕过
  • 省略函数存在检查

call is a low level function to interact with other contracts.

This is the recommended method to use when you're just sending Ether via calling the fallback function.

However it is not the recommend way to call existing functions.

Few reasons why low-level call is not recommended Reverts are not bubbled up Type checks are bypassed Function existence checks are omitted

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

contract Receiver {
event Received(address caller, uint amount, string message);

fallback() external payable {
emit Received(msg.sender, msg.value, "Fallback was called");
}

function foo(string memory _message, uint _x) public payable returns (uint) {
emit Received(msg.sender, msg.value, _message);

return _x + 1;
}
}

contract Caller {
event Response(bool success, bytes data);

// Let's imagine that contract Caller does not have the source code for the
// contract Receiver, but we do know the address of contract Receiver and the function to call.
function testCallFoo(address payable _addr) public payable {
// You can send ether and specify a custom gas amount
(bool success, bytes memory data) = _addr.call{value: msg.value, gas: 5000}(
abi.encodeWithSignature("foo(string,uint256)", "call foo", 123)
);

emit Response(success, data);
}

// Calling a function that does not exist triggers the fallback function.
function testCallDoesNotExist(address payable _addr) public payable {
(bool success, bytes memory data) = _addr.call{value: msg.value}(
abi.encodeWithSignature("doesNotExist()")
);

emit Response(success, data);
}
}

委托调用

delegatecall是一个类似于call的低级函数。

当合约A执行delegatecall到contract时B,B的代码被执行

与合同A的存储,msg.sender和msg.value。

delegatecall is a low level function similar to call.

When contract A executes delegatecall to contract B, B's code is executed

with contract A's storage, msg.sender and msg.value.

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

// NOTE: Deploy this contract first
contract B {
// NOTE: storage layout must be the same as contract A
uint public num;
address public sender;
uint public value;

function setVars(uint _num) public payable {
num = _num;
sender = msg.sender;
value = msg.value;
}
}

contract A {
uint public num;
address public sender;
uint public value;

function setVars(address _contract, uint _num) public payable {
// A's storage is set, B is not modified.
(bool success, bytes memory data) = _contract.delegatecall(
abi.encodeWithSignature("setVars(uint256)", _num)
);
}
}