在阅读了Solidity v0.6.0文档后,我仍然不理解fallback
函数的含义。我读到它被分为两个功能:fallback () external payable
和receive () external payable
。他们是匿名的,不接受任何参数,绝大多数情况下,receive () external payable
是用来接收资金的。你能不能用我的代码的例子来解释一下,这些函数的一些用例,以便理解它们的所有功能,否则一切都是在真空中,但我明白这是一个重要的概念?甚至receive () external payable
函数的含义也不清楚,其中我调用buyToken ()
方法,如果我直接调用Remix
中的the buyToken ()
,为什么需要它,绕过receive () external payable
,因为她不可见和匿名。
pragma solidity ^0.7.0;
// SPDX-License-Identifier: MIT
contract BuyToken {
mapping(address => uint256) public balances;
address payable wallet;
event Purchase(
address indexed buyer,
uint256 amount
);
constructor(address payable _wallet) {
wallet = _wallet;
}
fallback() external payable {
}
receive() external payable {
buyToken();
}
function buyToken() public payable {
balances[msg.sender] += 1;
wallet.transfer(msg.value);
emit Purchase(msg.sender, 1);
}
}
当发送者将ETH发送到您的合约地址并且没有指定任何功能(即tx的data
字段为空)时,receive()
将被执行。
由于receive()
只调用buyToken()
,它产生的动作集就好像用户直接执行buyToken()
一样。
但是其他契约可以对receive()
函数进行不同的使用。一个简单的银行合同的例子:
pragma solidity ^0.8;
contract MyContract {
mapping (address => uint256) public balances;
receive() external payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint256 _amount) external {
require(_amount <= balances[msg.sender], 'Insufficient balance');
balances[msg.sender] -= _amount;
payable(msg.sender).transfer(_amount);
}
}
或者一个时间锁:
pragma solidity ^0.8;
contract MyContract {
uint256 public constant unlockAfter = 1640995200; // 2022-01-01
receive() external payable {
// anyone can send funds to this contract
}
function withdraw() external {
require(msg.sender == address(0x123), 'Not authorized');
require(block.timestamp >= unlockAfter, 'Not unlocked yet');
payable(msg.sender).transfer(address(this).balance);
}
}
当函数签名(data
字段的前4个字节)与任何现有函数不匹配时使用fallback()
函数。
pragma solidity ^0.8;
contract MyContract {
function foo() external {
// executed when the `data` field starts with `0xc2985578`, the signature of `foo()`
}
fallback() external {
// executed when the `data` field is empty or starts with an unknown function signature
}
}
我不确定你的代码示例,但它是这样的:
回退函数-我认为这是一个很好的解释。因此,如果没有标记应付,如果合同收到无数据的纯以太币,它将抛出异常。
应收账款-这篇文章很好地解释了外部。所以拨打外部电话比拨打公共电话花费更少。只有在您的示例中,才有意义将buyToken()从"public"external"帮助"。就我所知,从外部调用public没有任何好处。
回退函数由Ethereum Virtual Machine (EVM)
自动调用,这就是为什么它们被标记为external
。因为它不能显式调用,所以气体不能显式地发送给这个函数。相反,EVM为该功能提供了2,300 gas的固定津贴。如果gas成本超过2300,就会抛出异常。在部署契约之前测试回退函数的气体消耗是很重要的
contract Fallback {
fallback () external payable {
}
}
- 没有参数和
return
数据。每次ether被接收时,它都会被执行。如果合同以接收以太为目的,则要求在合同内实施;否则,将抛出一个异常并返回ether。
更新在pragma solidity ^0.8.12;
之后,fallback
可以接收参数并有一个return
语句
如果您调用合约中不存在的函数,您的合约将回落到
fallback()
。它将调用fallback
如果合同期望收到否则,则必须使用
payable
修饰符声明回退函数。另一个用例是代理契约,它将传入的请求路由到可升级的目标契约。代理合约中的回退函数实际上调用了目标合约的函数。
function _fallback() internal virtual { _beforeFallback(); // calling the target function code _delegate(_implementation()); }
收到()
fallback
函数在多个条件下被调用,这使得为每个条件编写代码变得困难。这就是添加receive
的原因。receive
只有在合约接收到以太币时才会被调用,所以fallback
只有在没有函数签名的情况下才会被执行在合约中实现。