> For the complete documentation index, see [llms.txt](https://emeditweb.gitbook.io/pulsar-stellar-sdk/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://emeditweb.gitbook.io/pulsar-stellar-sdk/concepts/wire-faithful-vs-call-oriented.md).

# Wire-faithful vs call-oriented

A Soroban event has two honest representations, and the SDK does not pick one for you. Understanding the split is the difference between reading events correctly and reading them almost correctly.

## What a DecodedEvent reports

A `DecodedEvent` is wire-faithful. It reports what the ledger actually holds:

* **`name` is the leading topic Symbol, exactly as emitted.** It is lowercase, because that is how the contract emits it. It is not the Rust struct name.
* **Topics stay separate from data.** A Soroban event splits its fields into indexed topics and an unindexed data payload. `DecodedEvent` keeps that split, because the topics are what you filter on.
* **The raw XDR rides alongside the decoded form.** `rawTopics` and `rawData` carry the base64 XDR, so anyone can check the decoding rather than trust it.

## What a generated binding describes

A binding generated from a contract is call-oriented. It describes the event the way the contract author wrote it:

* The name is the Rust struct name, capitalized. `Transfer`, not `transfer`.
* Topics and data are folded together into one `data` object, because from the author's side they were one struct.

Neither view is wrong. They answer different questions. The wire view answers "what is on the ledger." The binding view answers "what did the contract mean."

## Bridging the two, on purpose

The SDK ships a family of helpers that convert a wire `DecodedEvent` into the binding shape: `asInitializeEvent`, `asDepositEvent`, `asWithdrawEvent`, `asTransferEvent`, `asAdminChangeEvent`, and `asEmitCustomEvent`. Each returns the typed binding shape, or null when the event is not that type.

The bridge is opt-in and never implicit. `DecodedEvent` stays faithful to the wire, and a consumer who wants the binding's shape asks for it. This is deliberate: an automatic conversion would hide exactly the divergence that matters.

The clearest example is the name. The wire topic is `transfer`, the binding is `Transfer`. Matching a binding name against `DecodedEvent.name` silently never fires, because the case differs. A hand-rolled bridge gets this wrong and produces a handler that compiles, runs, and matches nothing. The `as*Event` helpers match the wire symbol, so they fire.

```ts
import { asTransferEvent } from '@pulsar-stellar/sdk';

for (const event of page.items) {
  const transfer = asTransferEvent(event);
  if (transfer === null) continue; // not a transfer, or the wrong shape
  const { from, to, amount } = transfer.data;
}
```

The helpers check the topic count as well as the name, so an event carrying the right symbol with the wrong arity does not match. That is what a contract emitting its own `transfer` with a different shape looks like.

## The showcase events

The reference contract emits six event types. This table is the wire contract: the symbol, the topics in order, and the data payload.

| Wire symbol    | Binding name  | Topics (in order)           | Data                  |
| -------------- | ------------- | --------------------------- | --------------------- |
| `initialize`   | `Initialize`  | `initialize`                | `admin` (address)     |
| `deposit`      | `Deposit`     | `deposit`, `from`           | `amount` (i128)       |
| `withdraw`     | `Withdraw`    | `withdraw`, `to`            | `amount` (i128)       |
| `transfer`     | `Transfer`    | `transfer`, `from`, `to`    | `amount` (i128)       |
| `admin_change` | `AdminChange` | `admin_change`, `new_admin` | `old_admin` (address) |
| `custom`       | `EmitCustom`  | `custom`, `tag`             | `payload` (bytes)     |

Three things in that table are easy to get wrong.

**Transfer topic order is `from` then `to`, fixed by SEP-41.** Reversing them produces a transfer that reads as valid and points the wrong way. No type can catch it, so the SDK pins the order with a test.

**AdminChange is asymmetric on purpose.** The incoming admin, `new_admin`, is a topic, so you can filter for the moment an address gained control. The outgoing admin, `old_admin`, is the data payload.

**EmitCustom emits the symbol `custom`, not `emit_custom`.** The Rust struct is named `EmitCustom`, but the contract pins the wire symbol to `custom` in its event annotation. Naming the wire symbol in the annotation decouples it from the Rust name, so renaming the struct cannot move the wire contract. The second topic, `tag`, is chosen at runtime, so its value varies per call while its position does not.

One binding-shape detail: `asEmitCustomEvent` returns `payload` as a `Uint8Array`, not a Node `Buffer`. A `Buffer` would push a polyfill onto every browser consumer for one field of one event. If you are handing the value to a generated binding that expects `Buffer`, write `Buffer.from(payload)`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://emeditweb.gitbook.io/pulsar-stellar-sdk/concepts/wire-faithful-vs-call-oriented.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `build a script that syncs our docs to a CMS` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
