详情参考: 合约 — Solidity develop 文档
fallback函数是合约中的一个未命名函数,没有参数且没有返回值。
fallback执行条件:
- 如果在一个合约的调用中,没有其他函数与给定的函数标识符匹配时(或没有提供调用数据),fallback函数会被执行;
- 当合约收到以太币时,fallback函数会被执行。
以下针对2种执行方式进行示例展示,源码也可以参见:smartcontract/Fallback at main · tracyzhang1998/smartcontract · GitHub
如果在一个合约的调用中,没有其他函数与给定的函数标识符匹配时(或没有提供调用数据),fallback函数会被执行
- // SPDX-License-Identifier: MIT
- pragma solidity ^0.8.7;
-
- //基合约实现
- contract TestFallback {
- string message;
-
- //构造函数,初始化状态变量message
- constructor() {
- message = "hello";
- }
-
- fallback() external {
- message = "fallback";
- }
-
- //调用此合约中不存在的函数
- function testFallback() external returns (bytes memory) {
-
- // 调用不存在的函数getMsgNew()
- bytes memory method = abi.encodeWithSignature("getMsgNew()");
- (bool success, bytes memory returnData) = address(this).call(method);
-
- require(success, "get fail");
- return returnData;
- }
-
- //调用此合约中已存在函数,但是没有传递参数
- function testFallbackWithNoParam() external returns (bytes memory) {
-
- // 调用已存在的函数setMsg(),未传递参数
- bytes memory method = abi.encodeWithSignature("setMsg()");
- (bool success, bytes memory returnData) = address(this).call(method);
-
- require(success, "set fail");
- return returnData;
- }
-
- function getMsg() external view returns (string memory) {
- return message;
- }
-
- function setMsg(string memory _message) external {
- message = _message;
- }
- }
0、部署合约,调用getMsg函数查看状态变量初始值为"hello"
1、调用函数testFallback,调用一个不存在的函数
2、调用getMsg函数查看状态变量已修改fallback函数中设置的"fallback"了

1、调用setMsg函数设置状态变量初始值为"hello"
2、调用函数testFallbackWithNoParam,调用一个已存在的函数但没传递参数
3、调用getMsg函数查看状态变量已修改fallback函数中设置的"fallback"了

当合约收到以太币时,fallback函数会被执行,为了接收以太币,fallback 函数必须标记为 payable。 如果不存在这样的函数,则合约不能通过常规交易接收以太币。
- // SPDX-License-Identifier: MIT
- pragma solidity ^0.8.7;
-
- // 包含fallback函数的合约,合约账户能够接收到其它合约转的以太币
- contract TestFallback {
- string message;
-
- //构造函数,初始化状态变量message,同时可向合约账户存款
- constructor() payable {
- message = "hello";
- }
-
- //回退函数,能够为此合约账户接收以太币
- fallback() external payable {
- }
-
- //存款,若部署时忘记存款,可直接调用此函数向合约账户存款
- function deposit() external payable {
- }
-
- //发送以太
- function sendEther(address _addr) external {
- bool result = payable(_addr).send(2);
- require(result, "send fail");
- }
-
- //查看合约账户余额
- function getContractBalance() external view returns (uint256) {
- return address(this).balance;
- }
- }
-
-
- // 不包含fallback函数的合约
- contract TestWithoutFallback {
-
- //构造函数,初始化时可向合约账户存款
- constructor() payable{
- }
-
- //存款,若部署时忘记存款,可直接调用此函数向合约账户存款
- function deposit() external payable {
- }
-
- //发送以太
- function sendEther(address _addr) external returns (bool) {
- bool result = payable(_addr).send(2);
- return result;
- }
-
- //查看合约账户余额
- function getContractBalance() external view returns (uint256) {
- return address(this).balance;
- }
- }
部署时可直接向合约转20Wei,若部署时忘记转,则可使用合约中的deposit存款函数向合约转20Wei,如下图所示:

- 调用未含fallback合约(TestWithoutFallback)中的发送以太函数sendEther,参数为含fallback合约(TestFallback)地址,转2Wei;
- 查看TestWithoutFallback合约账户余额,发现少了2Wei,当前为18Wei了,证明转账成功;
- 查看TestFallback合约账户余额,发现多了2Wei,当前为22Wei,证明接收成功,合约账户能够接收以太,是因为合约中含有fallback函数(且为payable)。

使用含fallback合约函数向未含fabllback合约发送以太,发现转账失败,报错了(如下图所示),即没有fallback函数的合约不能接收以币。官网文档解释如下:
一个没有定义 fallback 函数的合约,直接接收以太币(没有函数调用,即使用
send或transfer)会抛出一个异常, 并返还以太币(在 Solidity v0.4.0 之前行为会有所不同)。所以如果你想让你的合约接收以太币,必须实现 fallback 函数。

在测试时,想通过查看状态变量message看是否发生调用fallback,在fallback函数中对message状态变量修改值,如下所示:
fallback() external payable {
message = "fallback";
}
测试使用未含fallback合约函数向有fabllback合约发送以太,如上面测试结果应该转账成功,但是此时转账会失败,如下图所示:

最终去除了fallback函数中设置message状态变量,函数体未包含任何内容,转账成功,与第(1)步测试结果相同。
fallback() external payable {
}