A library for secure smart contract development on TRON. A port of OpenZeppelin Contracts to the TRON Virtual Machine (TVM), adapted to TRON's standards (TIPs / TRCs) and to the ways the TVM differs from the EVM.
Warning
This project is under active development. Contract names, APIs, and behavior may still change. Do not use in production without an independent security review.
@openzeppelin/tron-contracts is based on OpenZeppelin Contracts — versions match upstream by major and minor (see Versioning) — and keeps its battle-tested implementations, while:
- Renaming the standards that TRON publishes under its own identifiers — for example
ERC20→TRC20,ERC165→TRC165,EIP712→TIP712— and dual-citing both the TRON (TIP / TRC) and Ethereum (EIP / ERC) specifications in the documentation. - Adapting the implementations where the TVM diverges from the EVM (e.g.
CREATE2address derivation, theblock.chainidused in EIP-712 domain separators, the TRC-721 receiver hook, and tokens such as TRON USDT whosetransferreturnsfalseon success).
Where TRON only publishes a signing or utility spec (rather than a renamable contract standard), the contract keeps its descriptive name (e.g. ECDSA, MessageHashUtils, P256) and simply references the relevant TIP.
Versions track OpenZeppelin Contracts by major and minor: each @openzeppelin/tron-contracts minor ports the feature set of the same-numbered upstream release, and new upstream features arrive only with a new matching minor. Patch numbers are independent — each library patches on its own schedule, so a given patch number does not refer to the same-numbered upstream patch (for example, this library may release a 5.6.0 while OpenZeppelin Contracts is already at 5.6.1). Upstream fixes that affect ported code are backported regardless of which upstream release carried them.
npm install @openzeppelin/tron-contracts// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {TRC20} from "@openzeppelin/tron-contracts/token/TRC20/TRC20.sol";
contract MyToken is TRC20 {
constructor() TRC20("MyToken", "MTK") {
_mint(msg.sender, 1000 * 10 ** decimals());
}
}The TVM is EVM-compatible, but TRON standardizes many interfaces under its own TIP (TRON Improvement Proposal) and TRC numbers. This library references the TRON standard and dual-cites the Ethereum equivalent where one exists.
| Domain | TRON | Ethereum | Contracts |
|---|---|---|---|
| Fungible token | TRC-20 | ERC-20 | TRC20 (+ extensions) |
| Non-fungible token | TRC-721 | ERC-721 | TRC721 (+ extensions) |
| Multi-token | TRC-1155 | ERC-1155 | TRC1155 (+ extensions) |
| Tokenized vault | TRC-4626 | ERC-4626 | TRC4626 |
| Permit (gasless approval) | TIP-2612 | ERC-2612 | TRC20Permit, ITRC20Permit |
| Interface introspection | TRC-165 | ERC-165 | TRC165, TRC165Checker, ITRC165 |
| Proxy storage slots | TRC-1967 | ERC-1967 | TRC1967Proxy, TRC1967Utils, ITRC1967 |
| Meta-transactions | TRC-2771 | ERC-2771 | TRC2771Context, TRC2771Forwarder |
| Contract signature validation | TRC-1271 | ERC-1271 | ITRC1271, SignatureChecker |
| Typed structured data | TIP-712 | EIP-712 | TIP712 |
| Domain | TRON | Ethereum | Contracts |
|---|---|---|---|
Signed data (0x19 prefix) |
TIP-191 | ERC-191 | MessageHashUtils |
| ECDSA signature encoding | TIP-120 | — | ECDSA |
| secp256r1 (P256) precompile | TIP-7951 | EIP-7951 / RIP-7212 | P256 |
| Namespaced storage layout | TIP-7201 | ERC-7201 | Initializable, SlotDerivation |
CREATE2 address derivation |
TIP-26 | EIP-1014 | Create2, Clones |
Note
Several of these carry TVM-specific behavior documented in the affected contract's NatSpec — for example: the TIP-712 domain separator masks chainId to its low four bytes (the value TRON exposes via eth_chainId); CREATE2 derives addresses with a 0x41 prefix; and TRON USDT's transfer returns false even on a successful transfer, which SafeTRC20.safeTransferChecked handles by verifying the caller's balance delta (the sender's debit).
This port adapts non-obvious differences between the TVM and the EVM, including CREATE2 / plain CREATE address derivation, the block.chainid value used in TIP-712 domain separators, the TRC-721 receiver-hook magic value, and the handling of tokens that return false on a successful transfer. Each adaptation is documented in the affected contract's NatSpec.
This library works with contract-based tokens: TRC-20, TRC-721, TRC-1155 and the other TRC standards listed above. 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.
Important
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.
Please report any security issues responsibly via the security policy rather than opening a public issue.
OpenZeppelin Contracts for TRON is released under the MIT License.