Event log

Define and emit events from TRON smart contracts; read and decode them off-chain through transaction logs.

📘

Prerequisites

The event log is one of the most important features of the TRON Virtual Machine. Events let a contract emit specific binary data, which is recorded in the transaction's TransactionInfo. Event logs help developers confirm contract state changes, build off-chain indexers, and trigger UI updates without polling contract state. This page covers how to define events, how the TVM stores them, and how to decode an event log off-chain.

Defining and emitting events

In Solidity, declare an event with the event keyword and emit one with emit. Events can have any number of parameters; up to 3 of them can be marked indexed to make them searchable.

The TRC-20 Transfer event is the canonical example:

contract ExampleContractWithEvent {
    event Transfer(address indexed from, address indexed to, uint256 value);

    constructor() payable {}

    function contractTransfer(address payable toAddress, uint256 amount) public {
        toAddress.transfer(amount);
        emit Transfer(msg.sender, toAddress, amount);
    }
}
  • event Transfer(...) declares an event with three parameters: from (sender), to (recipient), and value (amount).
  • emit Transfer(msg.sender, toAddress, amount) writes the event to the log when the transfer succeeds.
📘

Naming convention

Solidity convention is to capitalize event names (Transfer) so they're distinguishable from the corresponding function names (transfer). The TVM does not enforce this — the convention is purely for readability.

How events are stored in TransactionInfo

The TVM uses the LOG opcode family to record event data. Logs appear in the log field of the transaction's TransactionInfo (retrievable via wallet/gettransactioninfobyid):

{
    "id": "88c66d08f15b983183c7f7d23e3fafec0320bcc837d67957a8bda58d04ca53e1",
    "log": [
        {
            "address": "a614f803b6fd780986a42c78ec9c7f77e6ded13c",
            "topics": [
                "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
                "00000000000000000000000079309abcff2cf531070ca9222a1f72c4a5136874",
                "00000000000000000000000081b64b1c09d448d25c9eeb3ee3b8f3348a694c96"
            ],
            "data": "00000000000000000000000000000000000000000000000000000000b2d05e00"
        }
    ]
}

Each log entry has three parts:

FieldWhat it contains
addressthe contract that emitted the event. To match the EVM format, TRON returns this without the 0x41 prefix — prepend 41 and Base58-encode it to get the TRON address
topicsthe event signature hash plus all indexed parameters. Stored separately so off-chain indexers can do prefix-scan filtering efficiently
datanon-indexed parameters, ABI-encoded

The split between topics and data exists because blockchain storage engines (LevelDB, RocksDB) optimize for prefix-scan queries. By placing indexed parameters in topics, off-chain indexers can quickly find "all Transfer events to address X" without reading the full event payload.

Decoding a log entry

To decode a log entry, you need the event's ABI. The ABI for the Transfer event above:

{
    "anonymous": false,
    "inputs": [
        {"indexed": true,  "name": "from",  "type": "address"},
        {"indexed": true,  "name": "to",    "type": "address"},
        {"indexed": false, "name": "value", "type": "uint256"}
    ],
    "name": "Transfer",
    "type": "event"
}

Walk through the log:

  • topics[0] = ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef — the event signature hash. Computed as keccak256("Transfer(address,address,uint256)"). Compare this against the hash of your event signature to confirm the entry is a Transfer event. You can compute the hash with tronweb.sha3. The signature string must contain no spaces — "Transfer(address, address, uint256)" (with spaces) would produce a different hash.
  • topics[1] = first indexed parameter, from. TRON addresses are stored with the 0x41 prefix stripped — take the last 40 hex chars, prepend 41, and Base58-encode to get the TRON address.
  • topics[2] = second indexed parameter, to. Same decoding as topics[1].
  • data = non-indexed parameters concatenated. Here there's only one (value), encoded as a 32-byte big-endian uint256. 0xb2d05e00 decodes to 3,000,000,000 in decimal.

If you have multiple non-indexed parameters, they are concatenated in declaration order following the ABI spec. See Parameter encoding and decoding for the full rules.

📘

Anonymous events

If the event is declared anonymous, topics[0] is omitted and indexed parameters start at topics[0]. Anonymous events save the 32-byte signature hash and can have up to 4 indexed parameters (instead of 3).

Patterns for off-chain consumption

Off-chain consumers of events fall into two main categories:

Polling for past events

Query past events through wallet/gettransactioninfobyid (single transaction) or by scanning blocks with wallet/getblockbynum and pulling logs from each transaction. This works for occasional queries but is inefficient for live monitoring.

Subscribing to live events

For live event streams, use TRON's event server endpoints (or a third-party indexer like TronGrid). TronWeb provides:

tronWeb.contract().at(contractAddress)
  .Transfer()
  .watch((err, event) => {
    if (err) return console.error(err);
    console.log('Transfer:', event);
  });

Subscriptions return events as they appear on-chain. For high-volume contracts (USDT, popular DEXes), use a dedicated event indexer rather than a public RPC.


Related resources