TVM Differences

The TRON Virtual Machine (TVM) is EVM-compatible, but it is not identical. A handful of differences are silent footguns: code that compiles and looks correct on Ethereum can produce the wrong address, accept unintended assets, or misvalue amounts on TRON. This page highlights the divergences that matter when building with OpenZeppelin Contracts for TRON and how the library handles each one. It is a summary — each adaptation is documented in detail in the affected contract's NatSpec.

Most standards are also renamed to their TRON identifiers (ERC20TRC20, ERC165TRC165, EIP712TIP712, and so on). See the Overview for the full TRON ↔ Ethereum mapping.

Summary

AreaTVM behaviourWhat this library does
CREATE2 address derivationPreimage uses a 0x41 prefix (TIP-26), not 0xffCreate2 and Clones predict addresses with the TRON prefix so predict-then-deploy flows resolve to the real address.
P256 secp256r1 precompileSpecified for the TVM by TIP-7951 at address 0x100, but not yet active on mainnetP256.verify performs the verification entirely in Solidity and does not depend on the precompile.
EIP-7702Delegation is not supported on the TVMOnly the SignerEIP7702 signer helper is ported; there is no working delegation flow.
ERC-4337TRON has no native bundler / EntryPointThe ERC-4337 account-abstraction contracts are not included.
TRX decimalsTRX has 6 decimals, not 18 — so a 1 ether literal evaluates to 10¹² TRXGuidance and examples use SUN-denominated literals; avoid ether / gwei literals.
USDT-TRON transferReturns false even on a successful transferSafeTRC20.safeTransferChecked verifies the caller's balance delta (the sender's debit) instead of trusting the return value, and the library uses it by default.
TIP-712 / address formatAddresses are 21-byte, 0x41-prefixed; off-chain SDKs sign over the 21-byte formNatSpec advisories on the contracts whose typed-data or address handling crosses the signing boundary.
Divergent precompilesAddresses 0x03 / 0x09 / 0x0A are shadowed or repurposed (TIP-43, TIP-60); real RIPEMD-160 lives at 0x20003The library never hard-codes calls to these addresses.
Native TRC-10 assetsA TRON account can hold TRC-10 tokens alongside TRX; moving them needs the token-aware CALLTOKEN callOut of scope for the library; see Native TRC-10 assets below.
Resource modelExecution is metered in energy + bandwidth, not gas; tx.gasprice returns the committee-set energy priceNo change required — the library does not depend on EVM gas-forwarding rules.
SELFDESTRUCT (TIP-6780)Matches EIP-6780 semantics, which strengthens _disableInitializers on the TVMDocumented via NatSpec; no behaviour is weakened.
Block cadence~3 second blocks, versus Ethereum's ~12 secondsPrefer timestamp-based (EIP-6372) mode for time-bounded Governor windows rather than block counts.

OpenZeppelin Contracts reads block.chainid dynamically, so TIP-712 domain separators are automatically correct for whichever TRON network you deploy to.

Native TRC-10 assets

This library works with contract-based tokens: TRC-20, TRC-721, TRC-1155 and the other TRC standards. Native TRC-10 assets, which a TRON account can hold alongside TRX, are outside its scope. Moving a TRC-10 requires the TVM's token-aware call — address.transferToken(amount, id), compiling to CALLTOKEN. Every value-bearing path here uses an ordinary call, which carries TRX only. A TRC-10 credited to a contract built on this library therefore stays with that contract, and no supplied path forwards or withdraws it. This includes the governance executors: Governor.relay, Governor.execute and TimelockController.execute/executeBatch accept TRX through value, and their proposal and operation hashes bind targets, TRX values and calldata, with no field for a token identifier or amount. Hold assets that contracts need to move as TRC-20 — either natively or by wrapping the TRC-10.

Addresses inside bytes payloads

Addresses embedded inside bytes payloads MUST use the 20-byte EVM form. During execution the TVM represents every address as the low 20 bytes, so msg.sender, address(this), and address-typed arguments are identical to the EVM. The 21-byte 0x41-prefixed and Base58Check (T…) forms that TRON tooling (TronWeb, node APIs) works with are off-chain encodings only — they never appear on-chain. When an address is carried inside a bytes argument — an ERC-7930 interoperable address, a crosschain bridge message, an ERC-7913 signer (verifier || key), or any packed calldata — it must be the raw 20-byte value. The 21-byte form is rejected where the format is self-describing (InteroperableAddress.parseEvmV1 and BridgeFungible revert on a non-20-byte address) and would otherwise be silently mis-parsed into the wrong address. Strip the 0x41 prefix at the encoding boundary (e.g. in your TronWeb integration) before placing an address in a bytes payload.

Learn more