Overview
Soroban contracts emit events that are indexed by Stellar's RPC node and queryable via getEvents. These events are the primary mechanism for off-chain systems to react to on-chain state changes — but they arrive as raw ScVal XDR and require SDK decoding to be meaningful. No tooling exists to query, decode, filter, and replay Soroban contract events visually. A developer building an indexer or a UI on top of a Soroban contract needs to see exactly which events their contract emits, with decoded values, without writing a script.
What needs to be built
apps/api/src/modules/contracts/events.service.ts
-
GET /contracts/events?contractId=<id>&startLedger=<n>&limit=<n>:
- Calls
sorobanRpc.getEvents({ startLedger, filters: [{ type: 'contract', contractIds: [contractId] }] })
- For each event: decodes
topic[] and value from ScVal XDR into typed human-readable values
- Returns:
{ events: [{ ledger, txHash, contractId, type, topics: DecodedScVal[], value: DecodedScVal, raw: string }] }
DecodedScVal = { type: string, value: string | number | object, raw: string } — handles all 15 ScVal types including nested Map and Vec
-
POST /contracts/events/filter — accepts a filter spec and a list of events; applies client-side filters without a new Horizon call:
- Filter types:
topic_contains, value_type_is, value_equals, ledger_range
- Returns the filtered subset with matching criteria highlighted per event
-
POST /contracts/events/replay — accepts a list of event payloads; re-submits them to a user-specified webhook URL with HMAC signature — used for testing indexers against historical events
apps/web/src/app/contracts/events/
-
Contract ID input + Start Ledger input + Limit selector (10 / 50 / 200)
-
"Fetch Events" button — calls the events endpoint
-
Event list — each event as a card: ledger number, tx hash (truncated + copy), event type badge (contract | system | diagnostic); topics rendered as typed chips; value rendered inline with type annotation; "Expand Raw XDR" accordion
-
Filter bar above the list: topic contains, value type selector, ledger range inputs — applied client-side instantly
-
"Replay to Webhook" button — opens a modal to enter a webhook URL + HMAC secret; replays all currently-visible events
Acceptance criteria
Overview
Soroban contracts emit events that are indexed by Stellar's RPC node and queryable via
getEvents. These events are the primary mechanism for off-chain systems to react to on-chain state changes — but they arrive as rawScValXDR and require SDK decoding to be meaningful. No tooling exists to query, decode, filter, and replay Soroban contract events visually. A developer building an indexer or a UI on top of a Soroban contract needs to see exactly which events their contract emits, with decoded values, without writing a script.What needs to be built
apps/api/src/modules/contracts/events.service.tsGET /contracts/events?contractId=<id>&startLedger=<n>&limit=<n>:sorobanRpc.getEvents({ startLedger, filters: [{ type: 'contract', contractIds: [contractId] }] })topic[]andvaluefromScValXDR into typed human-readable values{ events: [{ ledger, txHash, contractId, type, topics: DecodedScVal[], value: DecodedScVal, raw: string }] }DecodedScVal={ type: string, value: string | number | object, raw: string }— handles all 15 ScVal types including nestedMapandVecPOST /contracts/events/filter— accepts a filter spec and a list of events; applies client-side filters without a new Horizon call:topic_contains,value_type_is,value_equals,ledger_rangePOST /contracts/events/replay— accepts a list of event payloads; re-submits them to a user-specified webhook URL with HMAC signature — used for testing indexers against historical eventsapps/web/src/app/contracts/events/Contract ID input + Start Ledger input + Limit selector (10 / 50 / 200)
"Fetch Events" button — calls the events endpoint
Event list — each event as a card: ledger number, tx hash (truncated + copy), event type badge (
contract|system|diagnostic); topics rendered as typed chips; value rendered inline with type annotation; "Expand Raw XDR" accordionFilter bar above the list: topic contains, value type selector, ledger range inputs — applied client-side instantly
"Replay to Webhook" button — opens a modal to enter a webhook URL + HMAC secret; replays all currently-visible events
Acceptance criteria
ScValtypes decode without errors — validated against a contract that emits one event of each type in a test transactionMap<Symbol, I128>value decodes to a readable{ key: value }structure — not raw bytesSymbol("transfer")correctly narrows the event list to only transfer events for the loaded contractX-SaviTools-SignatureHMAC header — verified by a test receiver endpoint