智能合约中的 TRX 转账

使用 transfer()、send() 或 call() 在 Solidity 合约内部转账 TRX。

📘

前置阅读

持有 TRX 的智能合约能通过 Solidity 内置的地址成员函数向任意目标地址发送 TRX。常用选项有 transfer()、send() 和 call();选择哪一个,主要取决于接收方需要多少 Energy,以及失败时是否应立即回滚。

三种转账方式

transfer()

payable(receiver).transfer(amount);

transfer() 固定向接收方转发 2,300 Energy。接收方拒收或执行失败时,transfer() 会自动 revert 整笔交易。对大多数用户发起的简单转账来说,这是更容易保持状态一致的默认选择。

send()

bool success = payable(receiver).send(amount);
require(success);

send() 也只转发 2,300 Energy,但失败时不会自动回滚,只返回 false。如果使用 send(),必须检查返回值;否则转账失败后,后续状态更新仍可能继续执行。

call()

(bool success, ) = payable(receiver).call{value: amount}("");
require(success);

call{value: ...}("") 默认转发剩余可用 Energy,适用于接收方合约确实需要在 receive() 或 fallback() 中执行更多逻辑的场景。它同样不会自动回滚,必须显式检查 success。

关于地址成员函数的完整语义,请参阅 Solidity 官方文档关于地址类型成员的章节。


示例:安全 TRX 转账

下面的合约提供一个仅限 owner 调用的 safeTransferTRX 函数:先检查接收方、转账金额和合约余额,再用 transfer() 发送 TRX。任何检查失败都会在状态变更前 revert。

pragma solidity 0.8.0;

contract SimpleTransfer {
    address public owner;

    // 允许合约接收 TRX
    receive() external payable {}
    fallback() external payable {}

    event TRXTransferred(address indexed recipient, uint256 amount);

    modifier onlyOwner() {
        require(msg.sender == owner, "Caller is not the owner.");
        _;
    }

    constructor() {
        owner = msg.sender;
    }

    /**
     * @dev 将指定数量的 TRX 转账给指定地址。
     * @param recipient 接收方地址。
     * @param amount 转账金额 (单位为 sun)。
     */
    function safeTransferTRX(address payable recipient, uint256 amount) external onlyOwner {
        require(recipient != address(0), "Recipient cannot be the zero address.");
        require(amount > 0, "Amount must be greater than zero.");
        require(address(this).balance >= amount, "Insufficient TRX balance in contract.");

        // transfer() 在接收方拒绝或执行失败时自动回滚交易。
        recipient.transfer(amount);

        emit TRXTransferred(recipient, amount);
    }

    /**
     * @dev 返回合约当前持有的 TRX 余额。
     */
    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
}

开发要点

  • 通过 TVM 调用向合约发送 TRX 时,对应的 receive() 或 fallback() 必须标记为 payable。当前主网也允许通过系统 TransferContract 直接向合约地址转入 TRX;该路径只增加合约的 TRX 余额,不执行这两个回调。
  • onlyOwner 限制只有部署该合约的账户可以转出合约持有的 TRX。实际项目也可以改用角色权限或与业务状态绑定的提款规则。
  • 转账前拒绝零地址,避免不可恢复地销毁资金。
  • require 应在转账前执行。检查失败时,交易会在状态变更前回滚。
  • Solidity transfer() 本身不会发出应用业务事件。需要追踪该调用时,应手动发出事件,例如 TRXTransferred;如需完整统计合约入账,还要同时处理不执行回调的系统转账。

相关资源