如需获取本内容的最新版本,请参见 Cyfrin.io 的Fallback(代码示例)
fallback函数是一种特殊函数,在以下情况下会被执行:
- 调用了不存在的函数时
- 以太币被直接发送到合约但
receive()函数不存在 或msg.data不为空时
为了更好地理解 Solidity 在什么情况下会调用 receive 或 fallback 函数,请参考下面的流程图:
scss
send Ether
|
msg.data is empty?
/ \
yes no
| |
receive() exists? fallback()
/ \
yes no
| |
receive() fallback()
当通过transfer或send调用时,fallback函数有2300的gas限制。
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
contract Fallback {
event Log(string func, uint256 gas);
// 回退函数必须声明为外部函数。
fallback() external payable {
// 发送 / 转账(向该回退函数转发2300 gas)
// 调用(转发这些所有gas)
emit Log("fallback", gasleft());
}
// Receive 是 fallback 的一种变体,当 msg.data 为空时触发
receive() external payable {
emit Log("receive", gasleft());
}
// 用于检查该合约余额的辅助函数
function getBalance() public view returns (uint256) {
return address(this).balance;
}
}
contract SendToFallback {
function transferToFallback(address payable _to) public payable {
_to.transfer(msg.value);
}
function callFallback(address payable _to) public payable {
(bool sent,) = _to.call{value: msg.value}("");
require(sent, "以太币发送失败");
}
}
Remix Lite 尝试一下

fallback 操作可选择性地接受 bytes 作为输入和输出
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
// TestFallbackInputOutput -> FallbackInputOutput -> Counter
contract FallbackInputOutput {
address immutable target;
constructor(address _target) {
target = _target;
}
fallback(bytes calldata data) external payable returns (bytes memory) {
(bool ok, bytes memory res) = target.call{value: msg.value}(data);
require(ok, "call failed");
return res;
}
}
contract Counter {
uint256 public count;
function get() external view returns (uint256) {
return count;
}
function inc() external returns (uint256) {
count += 1;
return count;
}
}
contract TestFallbackInputOutput {
event Log(bytes res);
function test(address _fallback, bytes calldata data) external {
(bool ok, bytes memory res) = _fallback.call(data);
require(ok, "call failed");
emit Log(res);
}
function getTestData() external pure returns (bytes memory, bytes memory) {
return
(abi.encodeCall(Counter.get, ()), abi.encodeCall(Counter.inc, ()));
}
}
Remix Lite 尝试一下

END