Blog

Developer Guide

Stellar Smart Contract Events Explained for Soroban Developers

Events are your primary observability tool for Soroban smart contracts. When your contract does something important — a transfer, a state change, an error condition — it should emit an event. This guide covers how to emit events in your contract, query them via the RPC, and use them for monitoring and debugging.

What Are Soroban Events

Soroban events are structured data emitted during contract execution. They are stored in the ledger metadata and queryable via the Stellar RPC getEvents method.

Each event has:

  • Contract ID: Which contract emitted it
  • Topics: An array of values used for filtering (up to 4 topics)
  • Data: The event payload (arbitrary XDR-encoded data)
  • Ledger: Which ledger the event was emitted in
  • Type: contract (from your code), system (from the runtime), or diagnostic
  • Emitting Events in Rust

    In your Soroban contract:

    use soroban_sdk::{contractimpl, Env, Symbol, Address, symbol_short};
    
    #[contractimpl]
    impl MyContract {
        pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
            // ... transfer logic ...
    
            // Emit event
            env.events().publish(
                (symbol_short!("transfer"), from.clone(), to.clone()),
                amount,
            );
        }
    }

    The topics tuple is what consumers use to filter events. Put the event type first, then the key identifiers.

    Querying Events via RPC

    Use the getEvents method to query contract events:

    {
      "jsonrpc": "2.0",
      "id": 1,
      "method": "getEvents",
      "params": {
        "startLedger": 61000000,
        "filters": [{
          "type": "contract",
          "contractIds": ["CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC"],
          "topics": [["AAAADwAAAAh0cmFuc2Zlcg==", "*", "*"]]
        }],
        "pagination": {
          "limit": 100
        }
      }
    }

    Filter Options

    FilterDescription
    `type``contract`, `system`, or `diagnostic`
    `contractIds`Array of contract IDs to filter by
    `topics`Array of topic filters (`*` for wildcard)
    `startLedger`Start of the ledger range

    Topic Matching

    Topics are XDR-encoded. Use wildcards for flexible matching:

  • ["*"] — Match any first topic
  • ["transfer", "*", "*"] — Match transfer events from any account to any account
  • ["transfer", "GABC...", "*"] — Match transfers from a specific account
  • Event Types to Emit

    Standard Events

    EventTopicsDataWhen
    transfer(transfer, from, to)amountAsset moved
    approve(approve, owner, spender)amountAllowance set
    mint(mint, to)amountNew tokens created
    burn(burn, from)amountTokens destroyed

    Custom Events

    EventTopicsDataWhen
    config_change(config, key)new_valueSettings updated
    error(error, code)messageError condition
    deposit(deposit, user)amount, assetFunds deposited
    withdrawal(withdrawal, user)amount, assetFunds withdrawn

    Monitoring Events in Production

    Polling Pattern

    async function pollEvents(contractId, startLedger, onEvent) {
      let cursor = startLedger;
    
      setInterval(async () => {
        const res = await fetch(RPC_URL, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            jsonrpc: '2.0', id: 1,
            method: 'getEvents',
            params: {
              startLedger: cursor,
              filters: [{ type: 'contract', contractIds: [contractId], topics: [['*']] }],
              pagination: { limit: 100 },
            },
          }),
        });
        const data = await res.json();
        const events = data.result?.events || [];
    
        for (const event of events) {
          onEvent(event);
          cursor = event.ledger + 1;
        }
      }, 5000);
    }

    What to Alert On

    ConditionAlert Level
    No events in 30 minutes (normally active contract)Warning
    Error eventsCritical
    Unexpected event topicWarning
    Large transfer event (whale movement)Info
    Event volume spike (2x normal)Info

    Debugging with Events

    Events are invaluable for debugging production issues:

  • Missing events: If an operation should have emitted an event but didn't, the transaction likely failed
  • Event ordering: Events are emitted in the order they occur during execution
  • Diagnostic events: Enable diagnostic events during simulation for detailed execution traces
  • System events: Monitor system events for TTL extensions, storage changes, and resource usage
  • Tools

    LumenQuery provides tools for working with Soroban events:

  • [Smart Contract Explorer](/contracts): Event stream with decoded topics and data
  • [Soroban RPC](/docs/contracts): Direct access to getEvents for programmatic monitoring

  • *Monitor your Soroban contract events with LumenQuery. Decoded event streams, storage viewer, and call history — start free.*