接收eth回调函数receive和fallback函数都是合约中用来接收以太币(ETH)并且在没有匹配到其他函数时执行的特殊函数receive()只用于处理接收eth。当合约接收到一个纯ETH转账(没有任何数据或调用信息)时,且合约中没有调用其他函数,receive函数会被调用一个
receive
和fallback
函数都是合约中用来接收以太币(ETH)并且在没有匹配到其他函数时执行的特殊函数
只用于处理接收eth。当合约接收到一个纯ETH转账(没有任何数据或调用信息)时,且合约中没有调用其他函数,receive
函数会被调用
一个合约最多一个receive()函数
不需要函数声明,声明必须包含external,payable
receive不要执行太多的逻辑,防止超出gas的限制
比如别人用send 和 transfer,来发送eth,gas不能超过2300
否则会报错
没有名字、没有参数、不能返回任何值的特殊函数。
// 定义事件
event Received(address Sender, uint Value);
// 接收ETH时释放Received事件
receive() external payable {
emit Received(msg.sender, msg.value);
}
msg.sender
,msg.value
和msg.data
**只是发送ETH而不包含任何数据,且合约中定义了receive
函数,那么将会调用receive
函数。如果发送ETH时调用了一个不存在的函数,或者发送ETH同时包含了数据,那么将会调用fallback
函数。如果合约中既没有receive
也没有fallback
函数,合约将拒绝纯ETH转账。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MyContract {
// 事件声明,用于记录fallback函数被调用的信息
event FallbackCalled(address sender, uint value, bytes data);
// fallback函数定义
fallback() external payable {
// 触发事件,记录函数调用的详细信息
emit FallbackCalled(msg.sender, msg.value, msg.data);
}
}
接收eth如果msg.data为空,则调用receive,如果此时无receive,则调用fallback。
有数据则直接调用fallback。
msg.value:发送的以太币数量。
msg.sender:调用者的地址。
msg.data:调用数据
msg.data
包含调用数据(call data),即调用合约时传递的完整数据(包括函数签名和参数)。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MsgDataExample {
event LogData(bytes data);
// 一个简单的函数,带有一个参数
function exampleFunction(uint256 x) public {
// 触发事件,记录msg.data
emit LogData(msg.data);
}
}
函数签名: exampleFunction(uint256)
的函数签名是 exampleFunction(uint256)
。
函数选择器: 这个函数签名的前4个字节是通过对签名进行 keccak256
哈希并取前4个字节得到的:
bytes4 selector = bytes4(keccak256("exampleFunction(uint256)"));
对于 exampleFunction(uint256)
,假设计算得出的选择器是 0x7c600ae6
。
调用数据: 当调用 exampleFunction
时,假设传递的参数为 12345
,完整的调用数据为:
0x7c600ae6 0000000000000000000000000000000000000000000000000000000000003039
其中:
0x7c600ae6
是函数选择器。0000000000000000000000000000000000000000000000000000000000003039
是参数 12345
的编码(以32字节对齐)。调用 exampleFunction(12345)
时,事件 LogData
会记录 msg.data
的值:
emit LogData(msg.data);
此时,记录的 msg.data
将是:
0x7c600ae60000000000000000000000000000000000000000000000000000000000003039
这个数据包括:
0x7c600ae6
。12345
的编码。function transfereth(address payable _to,uint256 _value) external payable{
_to.transfer(_value);
}
特点:
revert
(回滚交易)error failed_send();
function senteth(address payable _to,uint256 _value) external payable{
bool success=_to.send(_value);
if(!success){
revert failed_send();
}
}
特点:
error call_failed();
function calleth(address payable _to,uint256 _value) external payable{
(bool success,)=_to.calleth{value:_value}("");
if(!success){
revert call_failed();
}
}
用法:发送地址 . call{value:发送eth的数量}
特点:
gas
限制,可以支持对方合约fallback()
或receive()
函数实现复杂逻辑revert
bool
):这个返回值表示调用是否成功。如果调用成功执行,它会返回 true
;如果调用失败,比如因为调用的函数不存在或者调用用尽了gas,它会返回 false
。bytes memory data
):这个返回值包含了被调用函数的返回数据。如果调用的是一个合约函数,这个数据就是函数执行后返回的任何输出值。例如,如果你使用 call
来调用另一个合约中的一个函数,该函数返回一个 uint256
和一个 address
,data
将包含这两个值的紧密打包编码在Solidity中,payable
是一个修饰符,它可以用于函数和地址。它的用途取决于它修饰的是函数还是地址:
修饰函数:当 payable
修饰一个函数时,它指示这个函数可以接收以太币(ETH)。如果调用一个非 payable
函数并发送ETH,交易会被拒绝。
修饰地址:当 payable
修饰一个地址时,它表示这个地址可以接收和发送ETH。在Solidity中,地址分为两种类型:address
和 address payable
。只有 address payable
类型的地址才能接收ETH,并且可以使用 transfer
或 send
方法发送ETH。
例如,想让 exampleFunction
接收ETH,需要这样写:
function exampleFunction(uint256 x) public payable {
// 函数现在可以接收ETH
emit LogData(msg.data);
}
同样,想让合约的某个地址类型变量能够接收ETH,需要声明它为 address payable
:
address payable public recipient;
这样,recipient
就可以接收ETH,并且合约内的函数可以使用 recipient.transfer(amount)
或 recipient.send(amount)
来发送ETH。如果没有将地址声明为 payable
类型,那么将无法向该地址发送ETH。
在以太坊中,每个交易都需要消耗一定量的 gas,以支付网络进行计算和存储的成本。Gas 是一个衡量以太坊网络计算工作量的单位,每个操作都有一个固定的 gas 消耗量,例如加法消耗3 gas,存储操作消耗更多。
当提到“gas 限制 2300”时,通常是在谈论向合约地址发送以太币时默认分配的 gas 量。在以太坊中,当你发送以太币(但不附带任何数据或调用任何函数)时,交易会附带一个 2300 gas 的限制。这个数值是为了足够支付日志事件(例如,Transfer
事件)的记录成本,但通常不足以执行任何更复杂的操作。
这个限制是为了防止在简单的 ETH 转账中意外执行复杂的合约代码,这可能会消耗更多的 gas。如果合约需要在接收以太币时执行更复杂的逻辑,那么发送者需要手动提高 gas 限制,以确保交易有足够的 gas 完成。
这个 2300 gas 限制是一个“最小单位”或者说是一个安全的最低限度,确保了在发送ETH时至少能完成最简单的操作,如记录一个事件。然而,这个数值并不是说每个交易都必须消耗 2300 gas,实际的消耗量取决于执行的具体操作。如果交易中没有执行任何代码,实际消耗的 gas 可能会更少。如果需要执行更多操作,则必须指定更高的 gas 限制。
在错误的处理的时候,我们可能会使用 require, assert ,revert检查语句的条件,当条件未满足的时候中断合约的执行/
error配合着revert使用,用法如下
// Solidity 0.7 or earlier
function restrictedAction() public {
require(msg.sender == owner, "Not the owner");
// ...执行操作
}
// Solidity 0.8.4 or later with custom error
error NotOwner();
function restrictedAction() public {
if (msg.sender != owner) {
revert NotOwner();
}
// ...执行操作
}
当使用 error
并通过 revert
触发时,合约执行会立即停止,并且回滚所有状态变更和未花费的gas(除了用于触发错误的gas)。这与传统的 require
语句相似,但 error
允许你定义一个无需字符串描述的错误类型。
接收合约完整的基本功能
pragma solidity ^0.8.0;
contract re_eth{
event receive_eth(uint256 value,uint256 gas);
function getbalance() view public returns (uint256){
return address(this).balance;
}
receive() external payable {
emit receive_eth(msg.value,gasleft());
}
}
gas limit
,这是你愿意为这笔交易支付的最大gas量,同时你也会指定一个gas price
,这是你愿意为每单位gas支付的价格。gasleft()
函数来获取当前交易中剩余的gas量。这意味着你可以知道到目前为止已经消耗了多少gas,还剩下多少gas可以使用。gas limit
,交易会被回退(revert),状态还原为交易之前的状态,但gas仍然会被消耗完。如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!