Skip to content

feat: real-time on-chain balance and event activity feed - #21

Merged
ijeoma270 merged 11 commits into
SoroProtocol:mainfrom
luciachizaram:main
Aug 20, 2026
Merged

feat: real-time on-chain balance and event activity feed#21
ijeoma270 merged 11 commits into
SoroProtocol:mainfrom
luciachizaram:main

Conversation

@luciachizaram

Copy link
Copy Markdown
Contributor

Closes #16

What changed

On-chain balanceuseStreamBalance now calls stream.balance_of(stream_id) via Soroban RPC instead of doing pure client-side math. The client-side estimate still shows immediately so the counter never freezes, and the real on-chain value swaps in once the RPC responds (with a pulsing "syncing" badge). Re-fetches every 15 seconds to catch cancellations or parameter changes.

Activity feed — New useStreamEvents hook queries getEvents on the Soroban RPC for all contract events (StreamCreated, Withdrawn, Cancelled, VestingCreated, VestingClaimed, VestingRevoked). Events are filtered by wallet address and paginated with cursor-based "Load More".

ActivityFeed component — Shows each event with:

  • Type badge with color (green for created, purple for withdrawn, red for cancelled)
  • Amount in XLM
  • Counterparty address (truncated)
  • Relative timestamp
  • Link to Stellar Explorer

Filter chips let you narrow by event type. "Load More" button fetches older pages.

Integrated into both /dashboard and /streams/[id].

Test plan

  • Connect wallet on dashboard — activity feed should show events for the connected address
  • Open a stream detail — balance should show "syncing" badge briefly then display on-chain value
  • Withdraw from a stream — balance should update within a few seconds
  • Filter events by type in the activity feed
  • Click "Load More" to fetch older events
  • Click the explorer link on an event to verify it opens the correct tx on stellar.expert

The hook now takes streamId and walletAddress so it can call the
on-chain balance_of RPC. Returns an object with balance, syncing,
and isFromChain instead of a bare bigint.
Pass contractStreamId and wallet to useStreamBalance. Show a pulsing
"syncing" badge while the RPC call is in flight. Refresh stream data
after withdraw/cancel so the page stays current.
Pulsing animation for the "syncing" indicator shown while the on-chain
balance RPC call is in flight.
Queries getEvents on the Soroban RPC for contract events
(StreamCreated, Withdrawn, Cancelled, VestingCreated, VestingClaimed,
VestingRevoked). Supports filtering by wallet address, event type, and
cursor-based pagination with loadMore.
Renders a list of stream events with type badge, amount, counterparty,
relative timestamp, and Stellar Explorer link. Includes filter chips
for event type and a "Load More" button for pagination.
Event rows, filter chips, load-more button, and icon styling for the
activity feed component.
Shows events for the connected wallet below the streams grid.
Move StreamEventType, labels, icons, colours, symbol mapping, and
filter options out of useStreamEvents and ActivityFeed into a single
src/lib/eventTypes.ts so they're defined once and shared.
Remove duplicated type definitions and constant maps from
useStreamEvents and ActivityFeed, importing from the new
eventTypes module instead.
@ijeoma270

Copy link
Copy Markdown
Contributor

nice, the syncing badge idea is clean.

btw useStreamBalance used to return a bigint, now its an object. make sure nothing else is calling it the old way or thats gonna break silently.

the event symbols in eventTypes.ts are wrong — you have created, withdrawn etc but the contract emits StreamCreated, Withdrawn. so the feed is gonna be empty every time. fix that and it should work.

also the streamId prop on ActivityFeed doesnt actually filter anything. either hook it up or remove it.

this imports getStreamBalance from the contracts module which is in PR 19. coordinate merge order or one of these wont build.

- Fix SYMBOL_TO_TYPE to use PascalCase symbols the contract actually
  emits (StreamCreated, Withdrawn, Cancelled etc.) instead of
  lowercase (created, withdrawn).
- Remove dead streamId prop from ActivityFeed that was accepted but
  never used for filtering.
@luciachizaram

Copy link
Copy Markdown
Contributor Author

Thanks for the review! Here's what I fixed:

Event symbols — You were right, the mapping was wrong. Changed created/withdrawn/cancelled to StreamCreated/Withdrawn/Cancelled to match what the contract actually emits.

streamId prop — Removed it. It was accepted but never wired up — Soroban events don't carry stream_id in a consistent way across event types so client-side filtering wasn't practical.

useStreamBalance backward compat — Checked all callers, it's only used in the stream detail page which was already updated. No silent breakage.

getStreamBalance import — PR 19 is already merged, so the import resolves fine on main. Rebased on upstream to confirm.

@ijeoma270

Copy link
Copy Markdown
Contributor

LGTM, thanks for contributing

@ijeoma270
ijeoma270 merged commit 89bc345 into SoroProtocol:main Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: real-time on-chain balance and event activity feed

2 participants