Skip to content

Latest commit

 

History

History
101 lines (74 loc) · 3.82 KB

File metadata and controls

101 lines (74 loc) · 3.82 KB

接收ETH

两种特殊的回调函数receive()fallback(),他们主要在两种情况下被使用:

  1. 接收ETH
  2. 处理合约中不存在的函数调用(代理合约proxy contract)

接收ETH函数 receive

在合约收到ETH转账时被调用的函数。一个合约最多有一个receive()函数,不需要function关键字:receive() external payable { ... }receive()函数不能有任何的参数,不能返回任何值,必须包含externalpayable

注:receive()最好不要执行太多的逻辑因为如果别人用sendtransfer方法发送ETH的话,gas会限制在2300receive()太复杂可能会触发Out of Gas报错;如果用call就可以自定义gas执行更复杂的逻辑

回退函数 fallback

fallback()函数会在调用合约不存在的函数时被触发。可用于接收ETH,也可以用于代理合约proxy contract

receive和fallback的区别

receivefallback都能够用于接收ETH,他们触发的规则如下:

触发fallback() 还是 receive()?
           接收ETH
              |
         msg.data是空?
            /  \
          是    否
          /      \
receive()存在?   fallback()
        / \
       是  否
      /     \
receive()   fallback()

简单来说,合约接收ETH时,msg.data为空且存在receive()时,会触发receive()msg.data不为空或不存在receive()时,会触发fallback(),此时fallback()必须为payable

receive()payable fallback()均不存在的时候,向合约直接发送ETH将会报错(你仍可以通过带有payable的函数向合约发送ETH)。

发送ETH

有三种方法向其他合约发送ETHtransfer()send()call(),其中call()是被鼓励的用法(因为)transfer()send()都有限制2300gas,call()没有gas限制。

transfer

  • 用法是接收方地址.transfer(发送ETH数额)
  • transfer()gas限制是2300,足够用于转账,但对方合约的fallback()receive()函数不能实现太复杂的逻辑。
  • transfer()如果转账失败,会自动revert(回滚交易)。
// 用transfer()发送ETH
function transferETH(address payable _to, uint256 amount) external payable{
    _to.transfer(amount);
}

send

  • 用法是接收方地址.send(发送ETH数额)
  • send()gas限制是2300,足够用于转账,但对方合约的fallback()receive()函数不能实现太复杂的逻辑。
  • send()如果转账失败,不会revert
  • send()的返回值是bool,代表着转账成功或失败,需要额外代码处理一下。
error SendFailed(); // 用send发送ETH失败error

// send()发送ETH
function sendETH(address payable _to, uint256 amount) external payable{
    // 处理下send的返回值,如果失败,revert交易并发送error
    bool success = _to.send(amount);
    if(!success){
        revert SendFailed();
    }
}

call

  • 用法是接收方地址.call{value: 发送ETH数额}("")
  • call()没有gas限制,可以支持对方合约fallback()receive()函数实现复杂逻辑。
  • call()如果转账失败,不会revert
  • call()的返回值是(bool, bytes),其中bool代表着转账成功或失败,需要额外代码处理一下。
error CallFailed(); // 用call发送ETH失败error

// call()发送ETH
function callETH(address payable _to, uint256 amount) external payable{
    // 处理下call的返回值,如果失败,revert交易并发送error
    (bool success,) = _to.call{value: amount}("");
    if(!success){
        revert CallFailed();
    }
}

总结: transfer,send,call区别:

  • transfer和send都有2300gas限制,call没有限制(推荐使用)
  • send和call 如果转账失败都需要手动 revert,transfer不用