23-03-02

First Post:

Last Update:

2023-03-02

call与fallback

fallback函数被调用的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
Which function is called, fallback() or receive()?

send Ether
|
msg.data is empty?
/ \
yes no
/ \
receive() exists? fallback()
/ \
yes no
/ \
receive() fallback()
  • 函数名称不存在

Receive函数没有 function 关键字,没有参数也没有返回值,且必须是 external 可见性(允许外部合约调用)并具有 payable 可支付属性。

转账的时候会先调用receive,没有receive的时候会调用fallback

address可以唯一标识一个合约,某种意义上来说,address就是合约

接收及发送以太币(send、transfer、call)

How to send Ether?

如何发送以太币?

You can send Ether to other contracts by

你可以通过以下方式发送以太币给其它合约

  • transfer (2300 gas, throws error)
  • send (2300 gas, returns bool)
  • call (forward all gas or set gas, returns bool)

How to receive Ether?

如何接收以太币?

A contract receiving Ether must have at least one of the functions below

接收以太币的合约必须拥有至少一个以下函数:

  • receive() external payable
  • fallback() external payable

receive() is called if is empty, otherwise is called.msg.datafallback()

当receive()是空的的时候会被调用,否则msg.data会调用fallback()

Which method should you use?

call in combination with re-entrancy guard is the recommended method to use after December 2019.

call函数是2019年12月份之后被推荐使用的,它结合了重入防御机制

Guard against re-entrancy by

通过以下方式防止重入

  • making all state changes before calling other contracts / 在调用其他合约之前先做完所有状态的改变

  • using re-entrancy guard modifier / 使用防重入修饰符

call能省一些gas(详见-> 视频

如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract ReceiveEther {

// Function to receive Ether. msg.data must be empty
receive() external payable {}

// Fallback function is called when msg.data is not empty
fallback() external payable {}

function getBalance() public view returns (uint) {
return address(this).balance;
}
}

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");
}
}