Skip to content

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

 
 

Repository files navigation

Stellar Stream Hive — Frontend

A Next.js frontend for Stellar Stream Hive: employers create real-time payment streams to employees on Stellar, and recipients watch their balance accrue by the second and withdraw whenever they want. Built as part of an open-source Stellar Development Foundation grant application.

Related repositories

Repo Purpose
stellar-stream-hive-contract Soroban smart contracts (Stream, Vault, Registry)
stellar-stream-hive-api Indexer/registry API used for stats and stream listings
stellar-stream-hive-frontend (this repo) Next.js web app

The signature feature: LiveBalance

The core of the product is watching a recipient's withdrawable balance tick upward in real time. hooks/useLiveBalance.ts mirrors the on-chain streaming formula client-side using BigInt math (never floating point, always floored — the UI must never show more than the contract would actually let you withdraw):

elapsed        = min(current_ledger, end_ledger) - start_ledger
total_duration = end_ledger - start_ledger
streamed       = floor(total_amount * elapsed / total_duration)
withdrawable   = streamed - withdrawn

It estimates the current ledger between chain reads using Stellar's ~5s average ledger close time, ticks once per second for a smooth counter, and re-syncs with the Soroban RPC endpoint every 30 seconds to correct for drift. Actual withdrawals always re-fetch the real on-chain amount before submitting — the ticking estimate is a UI affordance, never the source of truth for a transaction.

Tech stack

Getting started

npm install
cp .env.example .env.local   # then fill in values, see below
npm run dev

Open http://localhost:3000.

Environment variables

See .env.example for the full, documented list. In short:

  • NEXT_PUBLIC_STREAM_CONTRACT_ID, NEXT_PUBLIC_VAULT_CONTRACT_ID, NEXT_PUBLIC_REGISTRY_CONTRACT_ID — Soroban contract IDs. .env.example ships with the testnet deployment from 2026-10-12 (recorded in the contracts repo's DEPLOYMENTS.md), so cp .env.example .env.local gives a working testnet setup. A redeploy creates new ids; update these from scripts/deploy.sh's output. On any other network leave them blank and contract-calling features show a clear "not yet configured" state rather than failing silently.
  • NEXT_PUBLIC_STELLAR_NETWORK, NEXT_PUBLIC_STELLAR_NETWORK_PASSPHRASE, NEXT_PUBLIC_SOROBAN_RPC_URL, NEXT_PUBLIC_HORIZON_URL — network configuration, defaulted to Stellar testnet.
  • NEXT_PUBLIC_API_BASE_URL — base URL for the indexer API (stellar-stream-hive-api), used for platform-wide stats and listing streams by sender/recipient. If unset, the app shows a graceful empty/loading state rather than fabricating numbers.

Project structure

app/
  page.tsx                    Landing page (hero, no-wallet live demo, platform stats)
  streams/new/page.tsx        Create a stream
  streams/[id]/page.tsx       Stream detail (timeline, live balance, withdraw/cancel)
  sending/page.tsx            Streams the connected wallet is sending
  receiving/page.tsx          Streams the connected wallet is receiving
components/
  wallet/                     Freighter connect button, network indicator
  stream/                     LiveBalance, StreamCard, timeline, withdraw/cancel, etc.
  create/                     Create-stream form fields and live preview
  landing/                    Landing-page-only sections (demo, stats)
  layout/                     Nav bar, footer
  ui/                         Generic primitives (spinner, empty/error states, copy button)
hooks/
  useWallet.ts                Freighter connection state
  useLiveBalance.ts           The per-second ticking balance hook
  useStream.ts / useStreams.ts  Data loading for one stream / lists of streams
lib/
  contracts.ts                Soroban contract call helpers (create/withdraw/cancel)
  freighter.ts                Freighter API wrapper with normalized error handling
  stellar.ts                  Network config, RPC client, address validation
  streaming.ts                Client-side streamed-amount math (mirrors the contract)
  format.ts                   BigInt <-> decimal string formatting, address shortening
  api.ts                      Indexer API client
types/index.ts                 Shared domain types

Verifying the build

npm run build

This runs a full TypeScript + Next.js production build and must succeed with no type errors.

Contributing

See CONTRIBUTING.md.

License

MIT

Testing

npm run lint        # ESLint (next/core-web-vitals)
npm run typecheck   # tsc --noEmit, strict mode
npm test            # Vitest unit tests (watch mode: npm run test:watch)
npm run build       # production build

All four run in CI on every push and pull request (.github/workflows/ci.yml).

The unit tests target the logic where a mistake would cost someone money or show them a wrong balance, and run without a browser, wallet or network:

Module What is covered
lib/streaming.ts The accrual formula against the contract's own test vectors: flooring, multiply-before-divide, cliff, monotonicity, BigInt precision beyond Number.MAX_SAFE_INTEGER, ledger/time estimation
lib/format.ts Decimal parsing and formatting round-trips, truncation instead of rounding, address and explorer URL helpers
lib/streamMapping.ts Mapping the indexer API's and the contract's responses into the app's Stream type
lib/streamList.ts Status filters and CSV export (including spreadsheet-formula neutralisation)

Backend compatibility

The frontend talks to two backends, and lib/streamMapping.ts is the one place that knows their wire formats:

  • Indexer API (NEXT_PUBLIC_API_BASE_URL): GET /stats, GET /ready, GET /streams/:id, GET /senders/:address, GET /recipients/:address. List endpoints are paginated (200 per page); the client follows X-Total-Count until every page is loaded. Amounts arrive as decimal strings and are kept as strings until they are converted to BigInt for display.
  • Stream contract (NEXT_PUBLIC_STREAM_CONTRACT_ID): create_stream, withdraw(recipient, stream_id, amount), cancel_stream(sender, stream_id), withdrawable_amount and get_stream. Argument order matters here — Soroban passes arguments positionally — and is pinned in lib/contracts.ts.

Stream lists

/sending and /receiving can be filtered by status (all / live / completed / cancelled) and exported to CSV. The export contains exactly the streams currently shown, with amounts as human-readable decimals.

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages