接收ETH
Solidity支持两种特殊的回调函数,receive()和fallback(),他们主要在两种情况下被使用:
- 接收ETH
- 调用合约中不存在的函数
payable函数
函数+payable:能够接收主币。
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
contract Payable {
// 接收eth主币
function deposit() external payable {}
// 获取余额
function getBalance() external view returns(uint) {
return address(this).balance;
}
}
receive函数
receive()只用于处理接收ETH。一个合约最多有一个receive()函数,声明方式与一般函数不一样,不需要function关键字:receive() external payable { … }。receive()函数不能有任何的参数,不能返回任何值,必须包含external和payable。
receive() external payable {}
fallback函数
fallback()函数会在调用合约不存在的函数时被触发。可用于接收ETH,也可以用于代理合约proxy contract。fallback()声明时不需要function关键字,必须由external修饰,一般也会用payable修饰,用于接收ETH:fallback() external payable { … }。
fallback() external payable {}
receive和fallback的区别
fallback函数与receive的区别是:Receive函数只在合约转账时调用,而Fallback函数除了可以在合约转账时调用外,在合约没有函数匹配或需要向合约发送附加数据时,也调用Fallback函数。
receive和fallback都能够用于接收ETH,他们触发的规则如下:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
contract FallBack{
event Log(string func, address sender, uint value, bytes data);
fallback() external payable {
emit Log("fallback", msg.sender, msg.value, msg.data);
}
receive() external payable {
emit Log("receive", msg.sender, msg.value, "");
}
function getBalance() external view returns(uint) {
return address(this).balance;
}
}
发送ETH
Solidity有三种方法向其他合约发送ETH,他们是:transfer(),send()和call(),其中call()是被鼓励的用法。
transfer:用法是接收方地址.transfer(发送ETH数额),没有返回值。transfer()的gas限制是2300,足够用于转账,但对方合约的fallback()或receive()函数不能实现太复杂的逻辑。transfer()如果转账失败,会自动revert(回滚交易)。
send:用法是接收方地址.send(发送ETH数额)。send()的gas限制是2300,足够用于转账,但对方合约的fallback()或receive()函数不能实现太复杂的逻辑。send()如果转账失败,不会revert。send()的返回值是bool,代表着转账成功或失败,需要额外代码处理一下。
call:用法是接收方地址.call{value: 发送ETH数额}(“”)。call()没有gas限制,可以支持对方合约fallback()或receive()函数实现复杂逻辑。call()如果转账失败,不会revert。call()的返回值是(bool, data),其中bool代表着转账成功或失败,需要额外代码处理一下。
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
contract SendEth{
constructor() payable {}
receive() external payable{}
function sendByTransfer(address payable _to, uint amount) external payable {
_to.transfer(amount);
}
function sendBySend(address payable _to, uint amount) external payable {
bool ok = _to.send(amount);
require(ok, "send failed");
}
function sendByCall(address payable _to, uint amount) external payable {
(bool ok,) = _to.call{value: amount}("");
require(ok, "call failed");
}
}