【Solidity】开发心得 receive payable 里面尽量避免写代码,以免其他合约调用transfer 不成功

加密社

最近调试一段solidity代码,本来想测试在收款的时候,记录一个receive 和发出一个log,哪个消耗gas更大

我创建了两个智能合约:一个是TestTransfer,另一个是TransferCount。在TestTransfer合约中,我定义了一个叫做sendOut的函数,这个函数的作用是从TestTransferTransferCount合约转账。

我在测试过程中遇到了以下情况:

  1. 当我试图从TestTransfer合约向TransferCount合约转账时,总是失败。
  2. 但是,当我直接向TransferCount合约转账时,却能够成功。
  3. 之后我把TransferCount合约里的receive()函数中的代码注释掉了,再试了一次第一步的操作,这次竟然成功了。

问题出在哪里呢?

实际上,问题可能在于TransferCount合约中的receive()函数。当我从TestTransfer合约调用transfer()TransferCount转账时,如果TransferCountreceive()函数执行了一些消耗gas的操作,并且这些操作超过了transfer()方法内默认提供的2300 gas限制,那么整个转账过程就会失败。

解决这个问题的办法就是简化receive()函数,让它尽可能地少做事情,或者干脆不执行任何操作。这样一来,即使transfer()方法提供的gas有限,也不会因为gas不够而导致转账失败。

总结来说,为了确保transfer()能够成功,应该避免在receive()函数中写入过多的逻辑或操作。

// 指定Solidity版本大于0.8.0
pragma solidity >0.8.0 ;

// 这个合约用来接收Ether,并记录接收次数
contract TransferCount {
    // 公开变量,记录fallback函数被调用的次数
    uint public fallbackCount = 0;
    // 公开变量,记录receive函数被调用的次数
    uint public receiveCount = 0;

    // 可支付的构造函数
    constructor() payable {
        // 构造函数体为空
    }

    // 允许外部向合约发送Ether
    function deposit() payable external {
        // 函数体为空
    }

    // 接收Ether时自动调用此函数(如果交易数据为空)
    receive() external payable {
        // 增加接收次数
        receiveCount ++;
        // 注意:在此处增加代码可能导致其他合约调用address.transfer时由于gas不足而失败
    }

    // 当合约接收到带有数据负载的Ether时调用此函数
    fallback() external payable {
        // 增加fallback函数被调用的次数
        fallbackCount ++;
    }
}

// 这个合约用来测试向TransferCount合约转账的行为
contract TestTransfer{
    // 记录fallback函数被调用的次数
    uint public fallbackCount = 0;
    // 记录receive函数被调用的次数
    uint public receiveCount = 0;
    // 存储可支付地址,用于接收Ether
    address payable public tc;

    // 接收Ether时自动调用此函数(如果交易数据为空)
    receive() external payable {
        // 增加接收次数
        receiveCount ++;
    }

    // 当合约接收到带有数据负载的Ether时调用此函数
    fallback() external payable {
        // 增加fallback函数被调用的次数
        fallbackCount ++;
    }

    // 构造函数,初始化可支付地址
    constructor(address payable addr) payable {
        // 设置可支付地址
        tc = addr;
    }

    // 转账函数,从本合约向指定地址转账
    function sendOut(uint amount ) external{
        // 确保有足够的余额进行转账
        require(amount  <= address(this).balance, "insufficient balance");
        // 向指定地址转账
        payable(tc).transfer(amount);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

加密社

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值