# Accessing Ledger Transition: Soroban Events

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:

```rust
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 [this](https://github.com/xycloo/zephyr-examples/blob/master/zephyr-blend-mainnet-dashboard/src/lib.rs) 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](https://docs.mercurydata.app/zephyr-full-customization/learn/broken-reference) 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:&#x20;

```rust
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.&#x20;

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.&#x20;

## `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.&#x20;

```rust
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
        }
}
```

We are performing the same task as before, but directly accessing the vent fields. See the complete example [here](https://github.com/xycloo/zephyr-examples/blob/master/zephyr-soroban-types/src/lib.rs).&#x20;

## `env.reader().ledger_sequence()`

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

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