Skip to content

Repository files navigation

streampay-contracts

Soroban smart contracts for StreamPay — continuous payment streaming on the Stellar network.

Overview

This repo contains the on-chain logic for creating, starting, stopping, and settling payment streams. Contracts are written in Rust using the Soroban SDK.

Contract interface

  • create_stream(payer, recipient, rate_per_second, initial_balance, recipient_can_stop) — Create a new stream (payer must auth). Set recipient_can_stop = true to allow the recipient to also stop the stream; defaults to false (payer-only).
  • start_stream(stream_id) — Start an existing stream.
  • stop_stream(stream_id, stopper) — Stop an active stream. stopper must be the payer (always allowed) or the recipient (only when recipient_can_stop was set at creation). stopper must authorise the call.
  • settle_stream(stream_id) — Compute and deduct streamed amount since last settlement; returns amount.
  • batch_settle(stream_ids) — Settle multiple streams in a single call; returns one settled amount per input id.
  • archive_stream(stream_id) — Remove a fully-settled, inactive stream from storage (payer must auth).
  • get_stream_info(stream_id) — Read stream metadata (payer, recipient, rate, balance, timestamps, active, recipient_can_stop).
  • version() — Returns the contract version as a u32 (no auth required).

Batch settlement semantics

  • batch_settle is all-or-nothing. If any stream id is missing or any item panics, the entire invocation reverts and no settlement updates are committed.
  • Inactive streams settle to 0, matching settle_stream.
  • The contract caps each batch at 25 stream ids to keep Soroban resource usage predictable. Off-chain indexers and payroll processors should chunk larger workloads into multiple transactions.

Storage Model

Streams are stored in Soroban persistent storage with per-stream TTL management. Each stream is an independent ledger entry that can expire independently. The contract instance storage holds only the next_id counter.

See docs/factory-pattern.md for the full design rationale and future factory pattern graduation path.

Version encoding

The on-chain version uses a packed u32 scheme: major * 1_000_000 + minor * 1_000 + patch.

Semver u32
0.1.0 1 000
1.0.0 1 000 000
1.2.3 1 002 003

When releasing, update both Cargo.toml version and the VERSION const in src/lib.rs.

Prerequisites

Note: this crate uses soroban-sdk version 22.0 (see Cargo.toml).

Building, testing and deploying (copy-paste)

  1. Build optimized WASM (recommended via Docker builder included):
# Build with local toolchain (WASM output in target/)
cargo build --release --target wasm32-unknown-unknown

# OR use deterministic Docker builder (produces streampay_contracts.wasm)
docker build -f docker/Dockerfile.build -t streampay-wasm .
docker run --rm -v "$(pwd)":/work streampay-wasm
  1. Run unit tests locally:
cargo test
  1. Deploy to Futurenet/Testnet using soroban CLI (example):
# install soroban CLI if not installed
curl -sSf https://soroban.stellar.org/install.sh | bash

# set the network (futurenet/testnet)
soroban config set network futurenet

# upload contract and get contract id (example paths)
soroban contract publish --wasm target/wasm32-unknown-unknown/release/streampay_contracts.wasm

# note the contract id printed by the publish command
  1. Example invocation (replace <CONTRACT_ID> and addresses):
# create_stream(payer, recipient, rate_per_second, initial_balance)
soroban contract invoke --wasm target/wasm32-unknown-unknown/release/streampay_contracts.wasm \
   --id <CONTRACT_ID> --fn create_stream --args <PAYER_ADDRESS> <RECIPIENT_ADDRESS> 100 10000

# start_stream(stream_id)
soroban contract invoke --id <CONTRACT_ID> --fn start_stream --args 1

Notes

  • The exact soroban CLI flags depend on the CLI version; consult soroban --help.
  • For deterministic WASM builds in CI, use the provided docker/Dockerfile.build which pins the Rust toolchain.
  • Ensure the soroban-sdk version in Cargo.toml is compatible with your soroban CLI and network.

Setup for contributors

  1. Clone and enter the repo

    git clone <repo-url>
    cd streampay-contracts
  2. Install Rust

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    rustup component add rustfmt
  3. Verify setup

    cargo fmt --all -- --check
    cargo build
    cargo test

Scripts

Command Description
cargo build Build the contract
cargo test Run unit tests
cargo fmt Format code
cargo fmt --all -- --check Check formatting (CI)

CI/CD

On every push/PR to main, GitHub Actions runs:

  • Format check: cargo fmt --all -- --check
  • Build: cargo build
  • Tests: cargo test

Ensure all three pass before merging.

Releases

Tagged releases follow semver. Each release includes an optimized WASM artifact and SHA-256 checksum.

See docs/RELEASE.md for the full release process, including how to verify WASM builds.

Project structure

streampay-contracts/
├── src/
│   └── lib.rs                        # Contract and tests
├── docker/
│   └── Dockerfile.build              # Deterministic WASM builder
├── .github/workflows/
│   ├── ci.yml                        # Format, build, test
│   └── release.yml                   # Tagged release workflow
├── docs/
│   └── RELEASE.md                    # Release process guide
├── cliff.toml                        # Changelog generator config
├── rust-toolchain.toml               # Pinned Rust version
├── Cargo.toml
├── CHANGELOG.md
└── README.md

License

MIT

Documentation

Doc Description
docs/timestamp-accrual.md Ledger timestamp assumptions: validator behavior, coarse granularity, accrual edge cases, off-chain UX rounding
SECURITY.md Security policy and responsible disclosure
CONTRIBUTING.md Contribution guidelines
CHANGELOG.md Release history

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages