Mercury Documentation
  • Get Started with Mercury
    • Pricing
    • Endpoints
    • Authentication
  • The Definitive Guide to Understanding The Mercury's Stack Vision
  • Retroshades
    • Introduction to Retroshades
    • Get Started
      • Importing the Retroshades SDK
      • Writing and Emitting Retroshades
      • Deploying to Mercury Retroshades
      • Querying Retroshades
  • Zephyr: Full Customization
    • Introduction
    • General concepts
      • Zephyr Programs
      • Accessing the Ledger: Contract Entries
      • Accessing the Ledger Meta: Contract Events
      • Database Interactions
      • Create Custom Callable APIs: Serverless Functions
      • Catchups
      • Using Soroban inside Zephyr
    • Quickstart
    • Learn
      • Introduction to Mercury's Cloud and the Zephyr Stack
      • Get Started: Set Up and Manage the Project
        • Create the Project
        • Writing the Program
        • Local Testing
        • Deploy
        • Data catchups/backfill
        • Monitor Execution
        • Querying
      • Database Interactions
        • Zephyr.toml: Define the Tables Structure
        • Understanding Database Interactions
        • Database Operations
      • Accessing the Ledger
      • Accessing Ledger Transition: Soroban Events
      • Working with Contract Custom Types
      • Working with Soroban SDK Types
      • Web Requests, Automation and Alerts.
      • Zephyr.toml Extensions: Indexes And Dashboard
      • Reading From Indexes/External Tables
      • Custom APIs - Serverless Functions
        • General Concepts
        • Custom RPC-alike Endpoints
        • Querying APIs for Composable Data
      • Data Catchups/Backfill
      • Custom Dashboards
        • Creating the Dashboard
        • Plotting: Simple
        • Complex Plotting
    • Support
  • Mercury "Classic"
    • Subscriptions
      • API Definition
    • Queries
      • Contract Events
      • Contract Data Entry Updates
      • Stellar Operations, Balances, and Account Objects
  • TUTORIALS
    • Zephyr
      • Self-hosting Zephyr
      • No-RPC Dapp
      • Indexing a DeFi liquidity pool (Blend)
      • Building a Secure DeFi Real-Time Bot Through Smart Accounts
      • Monitoring Large Deposits with Zephyr and Sending Web Alerts
    • Mercury Classic
      • Index and query contract events
Powered by GitBook
On this page
  • env.reader().soroban_events()
  • Working with Events
  • env.reader().pretty().soroban_events()
  • env.reader().ledger_sequence()
  1. Zephyr: Full Customization
  2. Learn

Accessing Ledger Transition: Soroban Events

Learn how you can retrieve and use Contract Events in your program.

PreviousAccessing the LedgerNextWorking with Contract Custom Types

Last updated 10 months ago

We now know how to access the current state of the ledger with entries, let's learn how to retrieve the contract events that are emitted during the ledger transition. To do that you can use some Zephyr functions that will return an iterator over the requested events. We want these functions to be called for each new close and therefore inside the on_close() function. The method we will use to access all ledger transitions is env.reader().

env.reader().soroban_events()

This function lets you access all newly emitted events. While there is a simpler method to perform this operation, which will be explained next, we will start here to provide a clearer understanding of the events' structure (we will work now with XDR data). These functions can also be used to filter the returned events, as demonstrated below:

let events: Vec<ContractEvent> = env.reader().soroban_events().into_iter().filter(|x| {
        pools.contains(&address_from_string(&env, x.contract_id.clone()))
    }).collect();

To fully understand the code above, jump to example, but for now, it is sufficient to know that for each event returned by the function (x), if its contract id is present in a pools vector, we're collecting it in a Vec. Note here that x.contract_id is returned as a Option<Hash>, and we need to convert it into a Soroban Address. More about the address_from_string() function in the work with data section.

Working with Events

To better understand the structure of events, how to access them, and use them in your program let's see the continuation of the example above:

for t_event in events {
        let contract_address = address_from_string(&env, t_event.contract_id);   // as before, we transform the contract id into an address
        let ContractEventBody::V0(event) = t_event.body;   // accessing the event body
        
        let action: Symbol = env.from_scval(&event.topics[0]);   // turning the first topic (ScVal) into a Soroban Symbol.
        if action == Symbol::new(env.soroban(), "supply") {
            // your_logic
        } else if {
            // other_logic
        }
}

Now you should have a clearer view of the structure of the returned events: we have the contract_id and the body with the topics and data.

Here we can also observe how we can perform some logic based on the events (in this case on the first topic). This is only an example of all that can be done in Zephyr with the retrieved data, but the framework for accessing events will be similar to this one.

env.reader().pretty().soroban_events()

There is a similar way of retrieving events with Zephyr which is more straightforward and is suggested for ease of use unless you don't want to work directly with XDR structures, as in the previous case. This method is env.reader().pretty().soroban_events(), and allows you to perform the same tasks but with less work on the user side.

for event in env.reader().pretty().soroban_events() {
        let action: Symbol = env.from_scval(&event.topics[0]);
        // easily perform comparisons with SDK types.
        if action == Symbol::new(&env.soroban(), "glyph_mint") {
                // do something
        }
}

env.reader().ledger_sequence()

This method returns the latest ledger number, which is the one that results from the last transition:

let sequence: u32 = env.reader().ledger_sequence();

We are performing the same task as before, but directly accessing the vent fields. See the complete example .

this
here