注:学习笔记,仅供参考,如有错误,烦请指正
如何发送ETH币?
您可以通过以下方式将以太币发送到其它合约
- transfer(2300 gas,抛出错误)
- send(2300 gas,返回布尔bool值)
- call(转发所有gas或设置gas,返回布尔值)
您应该使用哪种方法?
call 2019年12月后推荐与重入防护相结合使用的方法。
通过以下方式防止重新进入
- 在调用其它合约之前进行所有状态更改
- 使用重入保护修饰符
call 是 address 类型的低级成员函数,它用来与其他合约交互。它的返回值为 (bool, data),分别对应 call 是否成功以及目标函数的返回值。
call 是 solidity 官方推荐的通过触发 fallback 或 receive 函数发送 ETH 的方法。不推荐用 call 来调用另一个合约,因为当你调用不安全合约的函数时,你就把主动权交给了它。推荐的方法仍是声明合约变量后调用函数,当我们不知道对方合约的源代码或 ABI,就没法生成合约变量;这时,我们仍可以通过 call 调用对方合约的函数。
call的使用规则
call的使用规则如下:
目标合约地址.call(二进制编码);
其中二进制编码利用结构化编码函数 abi.encodeWithSignature获得:
abi.encodeWithSignature("函数签名",逗号分隔的具体参数)
函数签名为”函数名(逗号分隔的参数类型)”。例如 abi.encodeWithSignature(“f(uint256,address)”, _x, _addr)。
另外 call 在调用合约时可以指定交易发送的 ETH 数额和 gas:
目标合约地址.call{value:发送ETH数额,gas:gas数额}(二进制编码);
发送ETH (transfer,send,call)代码演示
contract SendEther {
function sendViaTransfer(address payable _to) public payable {
// This function is no longer recommended for sending Ether.
_to.transfer(msg.value);
}
function sendViaSend(address payable _to) public payable {
// Send returns a boolean value indicating success or failure.
// This function is not recommended for sending Ether.
bool sent = _to.send(msg.value);
require(sent, "Failed to send Ether");
}
function sendViaCall(address payable _to) public payable {
// Call returns a boolean value indicating success or failure.
// This is the current recommended method to use.
(bool sent, bytes memory data) = _to.call{value: msg.value}("");
require(sent, "Failed to send Ether");
}
参考资料:
[1] Solidity极简入门|第二十二讲:Call,律动,https://www.theblockbeats.info/news/31680
[2] 发送eth (transfer, send, call),登链社区,https://learnblockchain.cn/article/3738