Solidity 学习 -练气期(九)

接收ETH

Solidity 支持两种特殊的回调函数,分别是receive()和 fallback()
(1)接收ETH使用recieve
(2)处理合约中不存在的函数调用,或者用于代理合约使用fallback
⚠️:Solidity 版本0.6.x之前,语法只有fallback()函数,既在接收用户发送ETH的时候,也在被调用函数签名没有匹配到的时候调用。
0.6.x之后,Solidity讲fallback拆分成receive()和 fallback()

接收 ETH的回调函数receive()

receive() 函数是在合约收到ETH转账时被调用的函数。一个合约最多有一个receive函数。声明方式不需要function关键字:
receive() external payable {...}
不能有任何参数
不能返回任何值
必须声明关键字external 和 payable

⚠️:receive 最好不要执行太多的逻辑,因为如果其他合约send和transfer方法发送ETH的话gas费用被限制在2300,太复杂会触发Out of Gas报错;如果call 发送ETH,就可以自己自定义gas 执行更复杂的逻辑
有些恶意合约,会在receive函数潜入恶意消耗gas的内容或者执行故意失败的代码,导致一些包含退款和转账逻辑的合约不能正常工作。因此包含这些逻辑的时候,一定注意这些情况。

    event receivedCalled(address Sender,uint Value);

    receive() external payable {
        emit receivedCalled(msg.sender, msg.value);
    }

回退函数fallback()

在调用合约不存在的函数时被触发。可用于接收ETH,也可以用于代理合约。声明也不用function关键字。必须声明external,一搬同时声明payable:
fallback() external payable {...}

    event fallbackCalled(address Sender,uint Value, bytes Data);

    fallback() external payable {
        emit fallbackCalled(msg.sender, msg.value, msg.data);
    }

两种回调函数区别


image.png

发送ETH

Solidity 有三种方法向其他合约发送ETH:transfer()、send()、和call()。其中call()是当前推荐的

接收ETH 的合约

部署一个接收ETH的合约ReceiveETH。
Log事件,用于在日志中记录收到的ETH数量和gas的剩余量。
包含receive()函数,收到其他合约转入出发,并释放log事件
查询余额的getBalance()函数

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

contract ReceiveETH {
    event Log(uint amount, uint gas);

    receive() external payable {
        emit Log(msg.value, gasleft());
    }

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

发送ETH 的合约

发送ETH的合约SendETH,在其中实现payable的构造函数和receive()回调函数,我们能偶在部署适合部署后想合约转账

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

contract SendETH {
    constructor() payable {}
    receive() external payable {}
    function transferETH(address payable _to,uint amount) external payable {
        _to.transfer(amount);
    }

    error SendFailed();

    function sendETH(address payable _to,uint amount)external payable {
        bool success = _to.send(amount);
        if(!success) {
            revert SendFailed();
        }
    }

    error CallFailed();

    function callETH(address payable _to,uint amount)external payable {
        (bool success,) = _to.call{value: amount}("");
        if(!success) {
            revert CallFailed();
        }
    }

}
  1. 使用 transfer()发送ETH
    transfer用法:_Address.transfer(amount);
    _Address 是接收方地址,amount是发送ETH的数量
    注意⚠️:
    (1)transfer()的gas限制是2300,用于转账时足够的,但对于合约的receive()函数或者fallback()函数不能实现太复杂的逻辑
    (2)transfer()如果转账失败,会自动revert(会滚交易)。

测试:填入前面ReceiveETH的合约地址和金额,调用transferETH()发送ETH。测试amount 给10
在调用时,我们Account中value 默认0 ,不够交易所以交易失败了revert
修改value为10,再次调用交易成功。

  1. 使用send()发送ETH
    send()函数的用法:_bool = _Address.send(amount)
    _Address 是接收方地址,amount是发送ETH的数量
    注意⚠️:
    (1)send()的gas限制是2300,用于转账时足够的,但对于合约的receive()函数或者fallback()函数不能实现太复杂的逻辑
    (2)如果转账失败,不会自动会滚
    (3)send()函数会返回一个布尔值,代表转账成功或者失败。可使用这个值进行额外的处理。
    测试:步骤如上
  2. 使用call() 发送ETH
    call的函数用法:
    (_bool,_data) = _Address.call{value: amount}(_bytes);
    _Address 是接收方地址,amount是发送ETH的数量
    {value:amount}是Solidity的特殊用法,位于函数和参数之间,用于置顶一些交易信息。call()函数带了一个bytes类型参数用于发送额外的二进制数据。
    注意⚠️:
    (1)call()没有gas限制,可以支持对方合约的fallback()或者receive()函数实现复杂逻辑
    (2)call()如果失败,不会自动会滚
    (3)call()有两个返回值,第一个返回值_bool是布尔类型,代表转账成功或者失败,可以使用这个返回值进行额外处理
    第二个返回值_data为对方的消息数据
    测试:步骤如上
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容