Skip to content

About

Streaming payments for Stellar — create continuous, per-second payroll, vesting, and subscription streams on Soroban.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

 
 

Repository files navigation

⚡ StreamPay

Continuous, per-second payment streams for the Stellar network — Sablier-style money flow, native to Soroban.

CI License: Apache-2.0 rustfmt + clippy

A payroll line that pays by the second. A vesting schedule your team can watch tick. A subscription that cancels itself the moment funding stops — with every unearned token refunded.

StreamPay is a Soroban smart contract that locks a deposit and releases it linearly over time to a recipient. The recipient withdraws accrued funds whenever they like; the sender can top up mid-stream or cancel, splitting the remaining funds fairly: earned tokens to the recipient, unearned tokens back to the sender. Similar in spirit to Sablier on Ethereum, designed from scratch for Stellar's ledger model.

Why

  • Payroll: pay contractors or DAO contributors by the second instead of by invoice — they can withdraw as they earn, with zero counterparty risk on accrued funds.
  • Vesting: lock team/investor tokens in a transparent, immutable schedule.
  • Subscriptions & escrow: fund a stream; when it runs dry, service stops. Cancelling returns what wasn't earned.

Everything is on-chain and trust-minimized: no admin key, no upgrade path, funds only ever move per the stream rules.

How streams accrue

 deposit ─────────────── locked in the contract ──────────────▶
 ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
             │ linear per-second release, floor division
 time ────── start_time ────────────────────── end_time ─────▶

 streamed(t) = deposit × elapsed / duration   (u128 checked, floored)
 available   = streamed − withdrawn           ; 0 before start_time
 on cancel : recipient ← available,  sender ← deposit − streamed

A stream is a half-open window [start_time, end_time). At any ledger timestamp the contract computes deposit × elapsed / duration with checked math (products widened to u128, results floored to whole token units and capped at the deposit). Every edge case you can think of — withdrawing before start, after end, cancelling a never-started stream, topping up after end — is covered by a unit test (see contracts/streaming-payments/src/test.rs).

Architecture overview

/frontend (Next.js + Freighter)         /docs/ARCHITECTURE.md
        │  sign & submit txs                   │ design deep-dive
        ▼                                      ▼
┌─────────────────────────────────────────────────────────────┐
│                  StreamingPayments (Soroban)                 │
│                                                              │
│  create_stream ─┐   withdraw ─┐   top_up ─┐   cancel_stream  │
│                 │             │            │        │        │
│            ┌────┴─────────────┴────────────┴────────┴────┐   │
│            │  Stream { sender, recipient, token,         │   │
│            │            deposit, withdrawn, start_time,  │   │
│            │            end_time, cancelable, status }   │   │
│            │  persistent storage + TTL extension         │   │
│            └──────────────────┬──────────────────────────┘   │
└───────────────────────────────┼──────────────────────────────┘
                                ▼
                     SAC / standard token interface

Deep dive (storage model, checked math, reentrancy, TTL strategy, design decisions): docs/ARCHITECTURE.md.

Contract API

Function Caller Moves tokens Emits
create_stream(sender, recipient, token, deposit, start, end, cancelable) → u64 anyone (sender auth required) pulls deposit in StreamCreated
withdraw(stream_id, amount) recipient pays out ≤ accrued Withdrawn
withdraw_max(stream_id) → i128 recipient pays out all accrued, atomically Withdrawn
cancel_stream(caller, stream_id) sender; recipient iff cancelable pro-rata split, atomic StreamCancelled
top_up(stream_id, amount) sender pulls added funds StreamToppedUp
get_stream(stream_id) → Stream — (read-only) — —
available(stream_id) → i128 — (read-only) — —
recipient_streams(address, offset, limit) → Vec<u64> — (read-only) — —
sender_streams(address, offset, limit) → Vec<u64> — (read-only) — —

recipient_streams / sender_streams are on-chain discovery indexes: append-only, creation-ordered stream-id lists per address, paginated (limit clamped to MAX_PAGE_SIZE = 50). Terminal streams keep their ids — read each stream's status for lifecycle state.

Creating a stream requires a prior token approval: token.approve(sender, <contract id>, deposit, exp). All failures return typed StreamError codes (no panics) — see contracts/streaming-payments/src/errors.rs.

Getting started (clean machine)

Prerequisites:

  1. Rust ≥ 1.85 (contract workspace uses edition 2021 with a conservative MSRV; soroban-sdk 27 sets the floor): https://rustup.rs
  2. Stellar CLI (for deploy + Wasm build): cargo install stellar-cli --locked
  3. Node.js ≥ 20 (frontend only): https://nodejs.org

Build and test the contract:

cargo test -p streampay-contract        # unit + property tests (see CI badge)
cargo fmt --all -- --check              # formatting gate
cargo clippy --all-targets -- -D warnings
stellar contract build                  # Wasm → target/wasm32v1-none/release/*.wasm
cargo deny check                        # supply chain (advisories, licenses, bans)

Fuzz the accrual math (nightly, optional):

cd fuzz && cargo +nightly fuzz run streamed_at -- -max_total_time=60

Live testnet demo in one command: ./scripts/deploy_testnet.sh deploys the contract, mints a demo token, and opens a 1-hour stream — full walkthrough in docs/DEMO.md.

Run the frontend:

cd frontend
cp .env.example .env.local    # set NEXT_PUBLIC_STREAMING_CONTRACT_ID
npm install
npm run dev                   # http://localhost:3000

Deploy to testnet:

stellar keys generate deployer --network testnet --fund
stellar contract deploy \
  --wasm target/wasm32v1-none/release/streampay_contract.wasm \
  --source deployer --network testnet

Repo layout

contracts/streaming-payments/   the contract (lib.rs, stream.rs, errors.rs, events.rs, test.rs)
frontend/                       minimal Next.js UI (Freighter wallet)
fuzz/                           cargo-fuzz harness for the accrual math (own workspace)
scripts/deploy_testnet.sh       one-command testnet demo
docs/ARCHITECTURE.md            design deep-dive
docs/DEMO.md                    verified testnet walkthrough
docs/GOOD_FIRST_ISSUES.md       ready-to-file contributor tickets
.github/workflows/ci.yml        test + fmt + clippy + coverage + wasm + lint/build/audit + supply chain
.github/workflows/release.yml   tag-driven Wasm release with SHA-256 digests
.github/workflows/fuzz.yml      scheduled fuzz sessions (non-blocking)
CHANGELOG.md                    release history (Keep a Changelog)

Roadmap

  • v0.1 — core contract: create / withdraw / cancel / top-up, tests, CI ✅
  • v0.2 — ✅ on-chain address indexes (recipient_streams / sender_streams), ✅ withdraw_max, ✅ frontend discovery + persistence, event indexer service, pause_stream (good first issue)
  • v0.3 — ✅ fuzzing in CI (cargo-fuzz on the rate math, scheduled), multi-token batch stream creation
  • v0.4 — full web UI polish (accrual charts), ✅ testnet demo script
  • v1.0 — external audit, mainnet deployment guide

Feature requests live in .github/ISSUE_TEMPLATE/ — good first issues are tagged good first issue and documented in docs/GOOD_FIRST_ISSUES.md.

Contributing

PRs welcome! Start with CONTRIBUTING.md — it covers conventions, branch/PR process, and how to run the tests locally. Every PR runs the full test suite, fmt, clippy (-D warnings), and the frontend build in CI.

Funding & sustainability

StreamPay is community-funded:

  • GrantFox — bounties on good-first-issues and roadmap features. Install the GrantFox GitHub App on your fork to earn while contributing.
  • Drips — list StreamPay as a dependency to split funding to upstream projects it builds on.

License

Apache-2.0

About

Streaming payments for Stellar — create continuous, per-second payroll, vesting, and subscription streams on Soroban.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages