YieldStream is a multi-tenant, high-performance Merkle distributor smart contract engineered for the Stellar Soroban ecosystem. It enables protocols, yield aggregators, DAOs, and projects to distribute rewards, token incentives, retroactive yield, and airdrops to thousands of recipients efficiently using cryptographic inclusion proofs.
Status: deployed and lifecycle-verified on testnet. Not externally audited — see SECURITY.md. Unclaimed funds sweep back to the creator; the open issues on fund-safety paths are tracked in the backlog.
- Multi-Tenant Architecture: Any project or tenant can create independent distribution campaigns with customized token addresses, Merkle roots, allocation budgets, and expiration deadlines on a single deployed contract.
- Cryptographic Security & RFC 6962 Compliance:
- Domain separation tags:
0x00prefix for leaves,0x01prefix for internal nodes to prevent second-preimage / leaf-node ambiguity attacks. - Sorted sibling pairs (
min(a, b) || max(a, b)): Eliminates proof malleability and avoids needing left/right proof direction flags.
- Domain separation tags:
- State & TTL Optimization:
- Instance storage for global counters and administrative authority.
- Persistent storage for distribution metadata and claimed leaf records.
- Automatic TTL extensions on every interaction (
extend_ttl) guaranteeing state longevity.
- Capital Safety & Sweeping:
- Creator cancellation: Creators can cancel an active campaign if needed.
- Clawback & Sweep: After expiration or cancellation, unclaimed tokens can be swept back to a designated treasury address.
- Deterministic Test Vectors: Validated with verifiable JSON Merkle test vectors in
test-vectors/merkle_v1.json.
yieldstream-contract/
├── Cargo.toml # Cargo workspace configuration
├── rust-toolchain.toml # Pinned Rust toolchain and WASM targets
├── scripts/
│ └── deploy.sh # Automated deployment and setup script
├── docs/
│ ├── ISSUE_BACKLOG.md # Contributor issue backlog
│ └── UPGRADING.md # Contract upgradability runbook & trust analysis
├── test-vectors/
│ └── merkle_v1.json # Canonical test vectors with proofs
├── packages/sdk/ # @yieldstream/sdk TypeScript client & Merkle tooling
└── contracts/distributor/
├── Cargo.toml # Distributor contract manifest
└── src/
├── lib.rs # Contract entrypoints and public interface
├── types.rs # Data structures (Distribution, DataKey, Status)
├── errors.rs # ContractError error codes
├── storage.rs # Instance and persistent storage helpers + TTL
├── merkle.rs # Domain-separated Merkle proof verification
├── events.rs # Structured contract lifecycle events
└── test/
├── mod.rs # Test harness and tree generator
├── create.rs # Creation and multi-tenant test suite
├── claim.rs # Claim verification and double-claim suite
├── cancel_sweep.rs # Cancellation and treasury sweep suite
└── vectors.rs # Merkle vector conformance test suite
Leaves commit to the distribution ID, unique index, recipient address, and token amount:
To prevent proof manipulation, sibling pairs are sorted lexicographically:
| Function | Access | Description |
|---|---|---|
initialize(admin) |
Admin Auth | Sets the initial contract administrator. |
create_distribution(creator, token, merkle_root, total_amount, num_recipients, end_time) |
Creator Auth | Creates and funds a new distribution campaign. |
claim(distribution_id, index, recipient, amount, proof) |
Recipient Auth | Verifies proof and transfers tokens to recipient. |
cancel(distribution_id) |
Creator Auth | Cancels active distribution, halting new claims. |
sweep(distribution_id, to) |
Creator Auth | Sweeps remaining unclaimed tokens if expired or cancelled. |
get_distribution(distribution_id) |
Read-only | Returns distribution details and current status. |
is_claimed(distribution_id, index) |
Read-only | Checks if a leaf index has already been claimed. |
get_version() |
Read-only | Returns current contract code version. |
get_admin() |
Read-only | Returns current contract administrator address. |
upgrade(new_wasm_hash) |
Admin Auth | Upgrades contract WASM bytecode with version tracking (see docs/UPGRADING.md). |
compute_leaf(distribution_id, index, recipient, amount) |
Pure Helper | Computes leaf hash according to contract format. |
verify_proof(proof, root, leaf) |
Pure Helper | Verifies Merkle inclusion against root. |
| Network | Contract |
|---|---|
| Testnet | CC25WDHZ7SQC2UMZJHIPYM2U5ROYFXVDZMP3THMIL3IJY6HOCGGX2FPG |
| Mainnet | planned — see issue discussion |
Deployed demo campaigns cover the full lifecycle: escrow, proof-based claims, double-claim rejection, completion, cancel → sweep refund.
- Rust (1.84+)
- WASM target:
rustup target add wasm32v1-none - Stellar CLI (v22+)
cargo teststellar contract buildOptimized WASM will be output at:
target/wasm32v1-none/release/yieldstream_distributor.wasm
./scripts/deploy.sh --network testnet --source <IDENTITY>- Protocol documentation site — leaf/node format, full function reference, storage and TTL policy
- TypeScript SDK (
@yieldstream/sdk) — typed client, Merkle tree generator, and Freighter tx builders - Contributing guide
- Code of conduct
- Security policy
- Issue backlog
- Open issues — pick one and ask to be assigned
| Owner / lead | @CHASE3020 |
| Triage | Applications and PRs answered within 48h, review within 5 days |
| Security | Private disclosure |
Part of the YieldStream org — see also
yieldstream-sdk and
yieldstream-app.
Dual-licensed at the recipient's option under either the MIT License or the Apache License 2.0.