Context
contracts/escrow/src/lib.rs emits initialized, released, refunded, and cancelled events. SorobanInvokeTool can invoke functions but cannot subscribe to events. A dedicated event listener would allow the agent to react to on-chain escrow state changes autonomously.
Technical Requirements
- Create
backend/tools/ContractEventListener.ts with listen(contractId: string, eventTypes: string[], onEvent: (event: SorobanRpc.Api.EventResponse) => void): () => void
- Use
sorobanServer.getEvents({ filters: [{ type: "contract", contractIds: [contractId] }], ... }) for polling (Soroban RPC does not have a WebSocket stream)
- Poll every
config.RETRY_DELAY_MS * 2 milliseconds
- Return a
stopListening function that cancels the polling interval
- Add tests mocking
sorobanServer.getEvents and asserting callbacks are fired
Definition of Done
ContractEventListener exists
listen returns a cleanup function
- ≥ 3 tests pass
Context
contracts/escrow/src/lib.rsemitsinitialized,released,refunded, andcancelledevents.SorobanInvokeToolcan invoke functions but cannot subscribe to events. A dedicated event listener would allow the agent to react to on-chain escrow state changes autonomously.Technical Requirements
backend/tools/ContractEventListener.tswithlisten(contractId: string, eventTypes: string[], onEvent: (event: SorobanRpc.Api.EventResponse) => void): () => voidsorobanServer.getEvents({ filters: [{ type: "contract", contractIds: [contractId] }], ... })for polling (Soroban RPC does not have a WebSocket stream)config.RETRY_DELAY_MS * 2millisecondsstopListeningfunction that cancels the polling intervalsorobanServer.getEventsand asserting callbacks are firedDefinition of Done
ContractEventListenerexistslistenreturns a cleanup function