Transferring TRX in smart contracts
Transfer TRX from inside a Solidity contract using transfer(), send(), or call().
Prerequisites
A smart contract holding TRX can send TRX to any address by calling one of Solidity's built-in address member functions. The common options are transfer(), send(), and call(). Choose between them based on how much Energy the recipient needs and whether failure should revert immediately.
Three transfer methods
transfer()
transfer()payable(receiver).transfer(amount);transfer() forwards a fixed 2,300 Energy stipend to the recipient. If the recipient rejects the transfer or execution fails, transfer() automatically reverts the whole transaction. For most simple user-initiated transfers, this is the easiest default for keeping state consistent.
send()
send()bool success = payable(receiver).send(amount);
require(success);send() also forwards only 2,300 Energy, but it does not automatically revert on failure. It returns false. If you use send(), always check the return value; otherwise, later state updates may continue even though the transfer failed.
call()
call()(bool success, ) = payable(receiver).call{value: amount}("");
require(success);call{value: ...}("") forwards the remaining available Energy by default. Use it when the recipient contract legitimately needs to run more logic in receive() or fallback(). It also does not automatically revert, so you must check success explicitly.
For the full semantic comparison, refer to the Solidity documentation on address members.
Example: safe TRX transfer
The contract below exposes an owner-only safeTransferTRX function. It validates the recipient, amount, and contract balance before transferring TRX, and reverts before the balance changes if a check fails.
pragma solidity 0.8.0;
contract SimpleTransfer {
address public owner;
// Allow the contract to receive 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;
}
// Safely transfer a specified amount of TRX to a given address.
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() reverts the transaction automatically if the recipient rejects.
recipient.transfer(amount);
emit TRXTransferred(recipient, amount);
}
// Return the current TRX balance held by the contract.
function getBalance() public view returns (uint256) {
return address(this).balance;
}
}Development notes
- The
receive()andfallback()functions must be markedpayablefor the contract to receive and hold TRX. onlyOwnerrestricts transfers to the account that deployed the contract. Production contracts can instead use role-based access control or withdrawal rules tied to application state.- Reject the zero address before transferring to prevent an irreversible loss of funds.
- Run
requirechecks before the transfer. If a check fails, the transaction reverts before any state change. transfer()emits no event on its own. Emit an application-level event, such asTRXTransferred, when indexers or explorers need to track the movement.
Related resources
- Writing & compiling Solidity — Solidity basics on TRON
- FeeLimit & Energy cost — paying for contract execution
- Solidity documentation on address members — official Solidity reference
Updated 4 days ago