The TRON Virtual Machine (TVM) provides a high-performance, EVM-compatible environment for deploying Solidity smart contracts. While sharing much of the Ethereum toolchain, this guide highlights critical TVM-specific behaviors, including millisecond timestamp handling and updated self-destruct logic, to ensure safe and optimized deployments.
Historically, the selfdestruct opcode was disabled on TRON. However, following the approval of TRON Governance Proposal No. 106 (April 2026), the behavior now aligns with Ethereum (EIP-6780) to improve TVM compatibility:
A contract will only be deleted if selfdestruct is executed within the same transaction that created the contract.
If executed in any subsequent transaction, only the TRX asset transfer occurs, and the contract code remains on-chain.
The Energy cost for calling selfdestruct has been adjusted to 5000.
Support for TSTORE, TLOAD (EIP-1153), and MCOPY (EIP-5656) was added to the TVM as part of the GreatVoyage-v4.8.0 (Kant) upgrade (June 2025). This ensures developers can port contracts utilizing Ethereum’s Cancun/Dencun upgrades without modification.
TRON addresses are 21 bytes internally (Ethereum addresses are 20 bytes). The ABI encoding pads to 32 bytes as on EVM, so ABI-encoded contract calls work correctly. However, if you are doing raw byte manipulation of addresses (e.g., in assembly), account for the 21-byte size.
On Ethereum, block.coinbase is the miner/validator address. On TVM, it is the Super Representative address that produced the current block. Do not use block.coinbase as a source of randomness — it is predictable and manipulable by SRs.
The CREATE opcode derives a contract address differently on TRON than on Ethereum. If you are deploying contracts that depend on deterministic CREATE addresses computed off-chain, recalculate them for the TRON address derivation scheme. CREATE2 with an explicit salt works correctly for deterministic addresses.
On Ethereum, address.transfer(amount) has a fixed 2,300 gas stipend. On TVM, this call uses Energy. Reentrancy patterns that relied on the 2,300 gas limit for safety may behave differently. Use the checks-effects-interactions pattern regardless.
TronBox supports Solidity up to 0.8.x. Use pragma ^0.8.0 or pin to a specific version. Solidity 0.8 includes built-in overflow checks, which removes the need for SafeMath.
version.sol
// Task: Specify the Solidity compiler version for TVM.
TRC-20 is functionally identical to ERC-20. The full function signature reference, event definitions, and known mainnet contract addresses are in Token Standards. Below is a complete, deployable minimal TRC-20 with TVM-specific notes inline.
SimpleTRC20.sol
// Task: This code defines a minimal TRC-20 token contract.
A standard OpenZeppelin ERC-20 also deploys correctly on TRON as a TRC-20. Review only two things before deploying: every block.timestamp comparison (multiply thresholds by 1000) and how you handle selfdestruct (as deletion behavior has been updated).
Every opcode costs Energy. Writing gas-efficient Solidity for Ethereum produces Energy-efficient contracts on TRON as well — the principles are the same. (For Web2 developers: Optimizing gas usage is like optimizing expensive database queries. On traditional servers, bad queries just slow things down; on blockchains, they directly cost your users real money).
Verifying your contract source code on TRONSCAN allows users and other developers to read your logic, inspect the ABI, and interact directly through the explorer.
Verification steps
Navigate to your contract address on tronscan.org
Click the Contract tab
Click Verify and Publish
Select the compiler version used by TronBox (must match exactly)
Paste your Solidity source code
Submit — TRONSCAN compiles and verifies the bytecode matches on-chain
For multi-file projects, use the Standard JSON Input method, which accepts the full compiler input including all imported files. TronBox’s build/contracts/*.json output contains the compiler input needed.
For a full breakdown of how Energy and Bandwidth work, the Dynamic Energy Model multiplier, and how to implement fee delegation so your DApp subsidises user costs, see Fee Model & Delegation.
Every transaction that calls a contract specifies a fee limit — the maximum TRX the sender is willing to burn if Energy runs out. If the contract execution exceeds the available Energy and the fee limit is reached, the transaction reverts and the fee limit is partially consumed.
In tronweb, set the fee limit per call:
sdk_call.js
// Task: Specify a fee limit to protect against infinite loops/high costs.
awaitcontract.someMethod().send({
feeLimit: 1_000_000_000, // 1,000 TRX maximum
shouldPollResponse: true,
});
Set the fee limit generously during development and tighten it after you know the actual Energy cost from TRONSCAN transaction history.
All time-based logic must use milliseconds, not seconds. Audit every block.timestamp comparison in migrated contracts.
SELFDESTRUCT behavior
Be aware of the new SELFDESTRUCT behavior (Proposal 106): contracts are no longer deleted unless destroyed in their creation transaction. Adjust your upgrade and cleanup logic accordingly.
Off-chain address computation
If your deployment scripts compute contract addresses off-chain (for CREATE factories), recalculate using TRON’s address derivation scheme.
Energy underestimation
Always test Energy consumption on Nile before mainnet. Underestimating fee limits causes reverts at the worst possible moment.