This project implements a Soroban smart contract for streaming payment channels on the Stellar network. The contract allows a payer to deposit XLM and stream it to a recipient at a defined rate (e.g., 1 XLM per hour). The recipient can claim the streamed amount at any time.
flowchart LR
user[User browser] --> frontend[Next.js frontend]
frontend --> wallet[Freighter wallet]
wallet --> frontend
frontend --> backend[Express backend API]
backend --> horizon[Stellar Horizon]
frontend --> horizon
frontend --> soroban[Soroban RPC]
soroban --> contract[MicroPayContract]
contract --> stellar[Stellar testnet/mainnet]
horizon --> stellar
backend -. tips, usernames, analytics, webhooks .-> frontend
wallet -. signs XDR .-> stellar
- Frontend builds payment, tip, receipt, trustline, trade, and account-management flows, then asks Freighter to sign Stellar transaction XDR.
- Freighter owns user keys and returns signed XDR; private keys never pass through the app.
- Backend API handles account, payment-history, federation, SEP-0010 auth, creator-tip, analytics, Turrets, and webhook endpoints.
- Horizon serves account balances, payment history, fee stats, transaction submission, and network data.
- Soroban RPC and
MicroPayContractrecord on-chain tips and receipt metadata through contract invocations.
- Stream Creation: Open payment streams with custom rates and deposits
- Claim Payments: Recipients can claim available funds at any time
- Top-up Streams: Add more funds to existing streams
- Close Streams: Payers can close streams and receive refunds for unstreamed portions
- Rate-based Streaming: Payments are calculated based on ledger progression
pub struct Stream {
pub payer: Address, // Address of the payer
pub recipient: Address, // Address of the recipient
pub rate_per_ledger: i128, // Amount streamed per ledger (in stroops)
pub deposited: i128, // Total amount deposited (in stroops)
pub claimed: i128, // Total amount claimed (in stroops)
pub start_ledger: u32, // Ledger number when stream started
}- Creates a new payment stream
- Returns the stream ID
- Transfers initial deposit from payer to contract
- Claims all unclaimed streamed XLM up to current ledger
- Only the designated recipient can claim
- Returns the amount claimed
- Adds more funds to an existing stream
- Only the original payer can top up
- Extends the stream duration
- Stops the stream and refunds unstreamed portion
- Only the original payer can close
- Returns the refund amount
- Returns stream information for querying
- Calculates claimable amount without claiming
- Authorization: Only recipients can claim, only payers can close/top-up
- Rate Validation: Rates must be positive
- Deposit Validation: Deposits must be positive
- Overflow Protection: Uses checked arithmetic operations
- Access Control: Proper authentication checks for all operations
elapsed_ledgers = current_ledger - start_ledger
total_streamed = rate_per_ledger * elapsed_ledgers
claimable = total_streamed - claimed
actual_claim = min(claimable, deposited - claimed)
elapsed_ledgers = current_ledger - start_ledger
total_streamed = rate_per_ledger * elapsed_ledgers
refundable = deposited - max(total_streamed, claimed)
let stream_id = StellarMicroPay::open_stream(
&env,
payer_address,
recipient_address,
1000, // 0.00001 XLM per ledger
1000000 // 0.01 XLM deposit
);let claimed = StellarMicroPay::claim_stream(
&env,
stream_id,
recipient_address
);StellarMicroPay::top_up_stream(
&env,
stream_id,
payer_address,
500000 // Additional 0.005 XLM
);let refund = StellarMicroPay::close_stream(
&env,
stream_id,
payer_address
);The contract includes comprehensive tests covering:
- Stream creation and basic operations
- Claim calculations at various ledger offsets
- Multiple claims over time
- Deposit limits and overflow handling
- Top-up functionality
- Close and refund calculations
- Authorization and validation
- Error conditions
- Install Rust and Soroban SDK
- Clone this repository
- Build the contract:
cargo build --release --target wasm32-unknown-unknown - Deploy to Stellar testnet/mainnet
- Initialize contract with required parameters
New contributors need a funded Stellar testnet account before they can sign and test app flows locally.
- Install the Freighter browser extension from
https://freighter.app/. - Open Freighter and create a new wallet, or import an existing development wallet.
- Save the recovery phrase somewhere secure. Do not use a production wallet for local testing.
- In Freighter, switch the network to Testnet.
- Copy the public key for the active testnet account.
- Fund the account with Friendbot:
- In the app, connect Freighter and use the Friendbot funding action shown for unfunded testnet accounts.
- Or open
https://friendbot.stellar.org/?addr=<PUBLIC_KEY>after replacing<PUBLIC_KEY>with your copied testnet public key. - Or run
stellar keys fund <identity-name> --network testnetif you are using Stellar CLI identities.
- Confirm funding by refreshing the dashboard or checking the account on Stellar Laboratory testnet explorer.
- Use that funded account for local payments, contract invocations, and end-to-end tests that require wallet signing.
✅ cargo test passes for all streaming tests
✅ Claim amount calculated correctly at any ledger offset
✅ Top-up increases the stream duration
✅ Close refunds the correct unclaimed amount
✅ Only the recipient can claim, only the payer can close
- Contract Size: Optimized for minimal deployment costs
- Gas Efficiency: Efficient storage and computation patterns
- Security: Comprehensive input validation and access controls
- Compliance: Follows Soroban best practices and standards
This project is open source and available under the MIT License.
How to Contribute
• Fork the repository.
• Clone your fork to your local machine.
• Create a new branch for your task.
git checkout -b feature/your-task-name
• Make your changes.
• Commit clearly.
git commit -m "Add: short description"
• Push your branch.
git push origin feature/your-task-name
• Open a Pull Request.