前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Solidity:接收 ETH

Solidity:接收 ETH

作者头像
孟斯特
发布2024-05-28 20:43:54
840
发布2024-05-28 20:43:54
举报
文章被收录于专栏:code人生code人生

payable

在Solidity中,payable是一个函数修饰符,它允许函数接收Ether(以太币)。如果一个函数被标记为payable,那么你可以在调用该函数时附带一定数量的Ether。如果一个函数没有被标记为payable,那么你不能在调用该函数时发送Ether,否则交易将被拒绝。

以下是一个使用payable函数修饰符的示例:

代码语言:javascript
复制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

contract PayableExample {
    address payable public owner;

    // 合约初始化时可以接收ETH
    constructor() payable {
        owner = payable(msg.sender);
    }

    // 查询合约所有者账户下的余额
    function getBalance() public view returns (uint256) {
        return owner.balance;
    }

    // 函数用于向此合约存入Ether。
    // 调用此函数并附带一些Ether。
    // 此合约的余额将自动更新。
    function deposit1() public payable {}

    // 调用此函数并附带一些Ether。
    // 由于此函数不是可支付的,函数将抛出错误。
    // transact to PayableExample.deposit2 errored: Error occurred: revert.

    // revert
    //     The transaction has been reverted to the initial state.
    // Note: The called function should be payable if you send value and the value you send should be less than your current balance.
    // You may want to cautiously increase the gas limit if the transaction went out of gas.
    function deposit2() public {}

    // 将余额全部发送给合约所有者
    function withdraw() public {
        // 获取存储在此合约中的Ether数量
        uint256 amount = address(this).balance;

        // 将所有Ether发送给所有者
        (bool success, ) = owner.call{value: amount}("");
        require(success, "Failed to send Ether");
    }
}

在上面的合约中展示了如何在Solidity中使用payable关键字来接收和发送Ether。

1.owner:这是一个公开的可支付地址,它被设置为合约的创建者(也就是部署合约的地址)。

2.constructor:这是一个构造函数,它在合约部署时运行。这个构造函数是可支付的,这意味着你可以在部署合约时向它发送Ether。构造函数将合约的创建者设置为所有者。

3.getBalance:这个函数返回合约所有者的余额。

4.deposit1:这是一个可支付函数,这意味着你可以在调用这个函数时向它发送Ether。发送的Ether将被添加到合约的余额中。

5.deposit2:这个函数不是可支付的,这意味着你不能在调用这个函数时发送Ether。如果你试图这样做,将会抛出错误。

6.withdraw:这个函数将合约的全部余额发送给所有者。如果发送失败,它将抛出一个错误。

注意,payable函数修饰符只影响函数是否可以接收Ether,它不影响函数的其他行为。也就是说,一个payable函数可以做任何其他函数可以做的事情,包括修改合约的状态。

另外,payable函数修饰符也可以用于receivefallback函数。receive函数在合约接收Ether时被调用,fallback函数在调用了不存在的函数时被调用。这两个函数都必须被标记为payable,否则合约不能接收Ether。

receive

在Solidity中,receive函数是一种特殊的函数,用于处理发送到合约的Ether转账。这个函数在合约收到普通Ether转账时被调用,它不能有参数,也不能返回任何值。

receive函数必须被声明为external payable,并且一个合约只能有一个receive函数。如果合约没有定义receive函数,但是定义了fallback函数,那么在收到Ether转账时,fallback函数会被调用。

以下是一个receive函数的例子:

代码语言:javascript
复制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

contract MyContract {
    // Event to emit when Ether is received
    event Received(address sender, uint amount);

    // Function to receive Ether. msg.data must be empty
    receive() external payable {
        // Emit the Received event when Ether is received
        emit Received(msg.sender, msg.value);
    }
}

在这个例子中,当向这个合约发送Ether时,receive函数会被调用,并且触发一个Received事件,事件中包含了发送者的地址和发送的Ether的数量。注意,receive函数被声明为external payable,并且没有任何参数或返回值。

fallback

fallback是一种特殊的函数,当以下情况发生时会被执行:

•调用了不存在的函数,或者•直接向合约发送了Ether,但是没有receive()函数,或者msg.data不为空

当通过transfersend调用时,fallback函数的Gas限制为2300。这个限制是为了防止被调用的合约执行复杂的操作,可能会耗费更多的gas。

此外,fallback函数可以接受一个bytes calldata参数,并且可以返回bytes memory

代码语言:javascript
复制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

// 函数调用关系: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, ()));
    }
}

receive or fallback?

既然receivefallback都可以接收ETH,那什么时候调用receive?什么时候调用fallback

在Solidity中,当你发送Ether时,会根据msg.data是否为空以及receive()函数是否存在来决定是调用receive()函数还是fallback()函数。

以下是详细的判断流程:

1.首先,检查msg.data是否为空。2.如果msg.data为空,那么就会检查receive()函数是否存在。•如果receive()函数存在,那么就会调用receive()函数。•如果receive()函数不存在,那么就会调用fallback()函数。3.如果msg.data不为空,那么就会直接调用fallback()函数。

这种设计是为了在不同的情况下提供更大的灵活性。例如,你可能希望在没有任何数据的情况下(即msg.data为空)执行一种操作(通过receive()函数),而在有数据的情况下执行另一种操作(通过fallback()函数)。

声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)[1]进行许可,使用时请注明出处。 Author: mengbin[2] blog: mengbin[3] Github: mengbin92[4] cnblogs: 恋水无意[5] 腾讯云开发者社区:孟斯特[6]

References

[1] 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0): https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh [2] mengbin: mengbin1992@outlook.com [3] mengbin: https://mengbin.top [4] mengbin92: https://mengbin92.github.io/ [5] 恋水无意: https://www.cnblogs.com/lianshuiwuyi/ [6] 孟斯特: https://cloud.tencent.com/developer/user/6649301

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-05-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 孟斯特 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • payable
  • receive
  • fallback
  • receive or fallback?
    • References
    相关产品与服务
    云开发 CloudBase
    云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档