Skip to content

cyberdocs120/stellar-rosca

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

11 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Stellar ROSCA

Status License Stellar Rust Node Next.js

Decentralized savings circles (ROSCAs) built on Stellar and Soroban.

Overview β€’ Features β€’ Quick Start β€’ API β€’ Smart Contract β€’ Contributing β€’ Roadmap


πŸ“‹ Table of Contents


🌍 Overview

Stellar ROSCA is a decentralized implementation of the Rotating Savings and Credit Association β€” a group savings model where members contribute a fixed amount each cycle and one member receives the entire pool, rotating until everyone has been paid out.

Known as Chamas in Kenya, Susus in West Africa, and Tontines across the diaspora, ROSCAs are a vital financial tool for millions of people worldwide. Traditional ROSCAs rely on trust and physical proximity. This project puts the logic on-chain.

Why Stellar ROSCA?

  • πŸ”’ Trustless β€” contribution rules and payout logic enforced by a Soroban smart contract, not a person
  • 🏦 Multisig treasury β€” group funds held in a Stellar multisig account; no single member can drain it
  • 🌐 Globally accessible β€” anyone with a Stellar wallet can participate
  • ⚑ Fast and cheap β€” Stellar settles in ~5 seconds at a fraction of a cent per transaction
  • πŸ“– Transparent β€” every contribution and payout is an immutable on-chain record

✨ Features

Smart Contract

  • βœ… Create ROSCA groups with configurable members, contribution amount, and cycle length
  • βœ… Deterministic recipient queue shuffled at group creation
  • βœ… Per-cycle contribution tracking with duplicate prevention
  • βœ… Token escrow β€” funds held in contract until payout is triggered
  • βœ… Automated payout to next recipient when all members have contributed
  • βœ… Cycle advancement and group completion detection
  • βœ… On-chain events for every state change

Backend API

  • βœ… Group creation with Stellar multisig treasury provisioning
  • βœ… Contribution submission β€” builds and signs Stellar payment transactions
  • βœ… All-contributed detection per cycle
  • βœ… RESTful JSON API with proper error codes

Frontend (in progress)

  • 🚧 Group dashboard
  • 🚧 Contribution tracking UI
  • 🚧 Cycle progress visualization
  • 🚧 Wallet integration

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  Frontend (Next.js / React)                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚  β”‚  Group Card  β”‚  β”‚Cycle Progressβ”‚  β”‚  Dashboard   β”‚      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  Backend API (Node.js / Express)             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚  β”‚ Group Routes β”‚  β”‚ Contribution β”‚  β”‚Stellar Clientβ”‚      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  Stellar Network (Soroban)                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚              ROSCA Contract (Rust)                   β”‚   β”‚
β”‚  β”‚  - create_group()       - trigger_payout()           β”‚   β”‚
β”‚  β”‚  - contribute()         - get_group_status()         β”‚   β”‚
β”‚  β”‚  - get_current_recipient()                           β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Contribution + Payout Flow

Member 1        Member 2        Member 3        Backend         Contract
   β”‚               β”‚               β”‚               β”‚               β”‚
   β”œβ”€POST /contribute──────────────►               β”‚               β”‚
   β”‚               β”‚               β”‚  recordContribution()         β”‚
   β”‚               β”‚               β”‚               β”œβ”€token.transferβ–Ί
   β”‚               β”‚               β”‚               ◄─Contrib event──
   ◄─{ txHash, allContributed: false }──────────────               β”‚
   β”‚               β”‚               β”‚               β”‚               β”‚
   β”‚               β”œβ”€POST /contribute──────────────►               β”‚
   β”‚               β”‚               β”‚               β”œβ”€token.transferβ–Ί
   β”‚               β”‚               β”‚               ◄─Contrib event──
   β”‚               ◄─{ txHash, allContributed: false }──────────────
   β”‚               β”‚               β”‚               β”‚               β”‚
   β”‚               β”‚               β”œβ”€POST /contribute──────────────►
   β”‚               β”‚               β”‚               β”œβ”€token.transferβ–Ί
   β”‚               β”‚               β”‚               ◄─AllCtrb event──
   β”‚               β”‚               ◄─{ txHash, allContributed: true }
   β”‚               β”‚               β”‚               β”‚               β”‚
   β”‚               β”‚               β”‚  POST /payout β”‚               β”‚
   β”‚               β”‚               β”‚               β”œβ”€trigger_payoutβ–Ί
   β”‚               β”‚               β”‚               β”‚  verify + pay β”‚
   β”‚               β”‚               β”‚               ◄─Payout event───
   β”‚               β”‚               β”‚               β”‚  cycle++      β”‚

πŸ› οΈ Tech Stack

Smart Contract

Technology Version Purpose
Rust 2021 Contract language
Soroban SDK 20.0.0 Stellar smart contract framework

Backend

Technology Version Purpose
Node.js 18+ Runtime
Express 4.19 HTTP framework
@stellar/stellar-sdk 11.3 Stellar network interaction
Jest 29 Testing

Frontend

Technology Version Purpose
Next.js 14 React framework
React 18 UI
TailwindCSS 3.4 Styling

πŸš€ Quick Start

Prerequisites: Node.js 18+ Β· Rust Β· Stellar CLI

1. Clone and configure

git clone https://github.com/cybermax4200/stellar-rosca.git
cd stellar-rosca
cp backend/.env.example backend/.env
# Edit backend/.env β€” set STELLAR_NETWORK, HORIZON_URL, etc.

2. Install dependencies

cd backend && npm install && cd ..
cd frontend && npm install && cd ..

3. Start the backend

cd backend && npm run dev

Verify it's running:

curl http://localhost:3000/health
# { "status": "ok", "network": "testnet" }

4. Start the frontend (optional)

cd frontend && npm run dev
# http://localhost:3001

πŸ“ Project Structure

stellar-rosca/
β”œβ”€β”€ contracts/
β”‚   └── rosca/
β”‚       β”œβ”€β”€ src/
β”‚       β”‚   └── lib.rs          # Contract logic β€” create_group, contribute, trigger_payout
β”‚       └── Cargo.toml
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ index.js            # Express server entry point
β”‚   β”‚   β”œβ”€β”€ group.js            # Group creation + in-memory store
β”‚   β”‚   β”œβ”€β”€ contribution.js     # Contribution recording + Stellar tx submission
β”‚   β”‚   β”œβ”€β”€ stellar.js          # Horizon client, multisig account helpers
β”‚   β”‚   └── routes/
β”‚   β”‚       └── groups.js       # REST route handlers
β”‚   β”œβ”€β”€ tests/
β”‚   β”‚   β”œβ”€β”€ group.test.js
β”‚   β”‚   └── contribution.test.js
β”‚   └── package.json
β”œβ”€β”€ frontend/
β”‚   β”œβ”€β”€ components/             # React components
β”‚   β”œβ”€β”€ pages/                  # Next.js pages
β”‚   └── styles/
β”œβ”€β”€ docs/
β”‚   β”œβ”€β”€ architecture.md         # Full system design + security model
β”‚   └── api.md                  # Complete API reference
β”œβ”€β”€ .github/
β”‚   └── ISSUE_TEMPLATE/
β”‚       β”œβ”€β”€ bug_report.md
β”‚       └── feature_request.md
└── CONTRIBUTING.md

πŸ“œ Smart Contract

The rosca Soroban contract is the on-chain source of truth. It handles authorization, token escrow, and payout logic. Written in Rust, compiled to WASM.

Contract Functions

create_group

Creates a new ROSCA group and shuffles the recipient queue.

pub fn create_group(
    env: Env,
    admin: Address,       // group administrator
    token: Address,       // token contract for contributions
    members: Vec<Address>,
    contribution_amount: i128,
    cycle_duration_days: u32,
) -> u32                  // returns group_id

contribute

Transfers tokens from a member to the contract escrow and records the contribution.

pub fn contribute(
    env: Env,
    group_id: u32,
    member: Address,
    amount: i128,
)

trigger_payout

Verifies all members have contributed, transfers the full pot to the next recipient, and advances the cycle.

pub fn trigger_payout(env: Env, group_id: u32)

get_current_recipient

Returns the address of the member scheduled to receive the payout this cycle.

pub fn get_current_recipient(env: Env, group_id: u32) -> Address

get_group_status

Returns the full group state.

pub fn get_group_status(env: Env, group_id: u32) -> Group

Error Codes

Code Error Description
GroupNotFound Group does not exist in storage
NotAMember Caller is not a member of the group
AlreadyContributed Member has already contributed this cycle
NotAllContributed Payout attempted before all members contributed
GroupCompleted All cycles have finished

Events

Topic Data Emitted when
(GroupCrtd, group_id) (admin, group_id) Group created
(Contrib, group_id) (member, cycle, amount) Member contributes
(AllCtrb, group_id) (group_id, cycle) All members contributed
(Payout, group_id) (recipient, cycle, amount) Payout sent

Build and Deploy

# Build
cd contracts/rosca
stellar contract build

# Deploy to testnet
stellar contract deploy \
  --wasm target/wasm32v1-none/release/rosca.wasm \
  --source <YOUR_SECRET_KEY> \
  --network testnet

The command prints the contract ID β€” save it in backend/.env as CONTRACT_ID.


πŸ“‘ API Reference

Base URL: http://localhost:3000/api Β· All amounts in stroops (1 XLM = 10,000,000 stroops)

Method Endpoint Status Description
GET /health βœ… Live Server health check
POST /groups/create βœ… Live Create group + multisig treasury
POST /groups/:id/contribute βœ… Live Submit member contribution
GET /groups/:id/status 🚧 Stub Get group state
POST /groups/:id/payout 🚧 Stub Trigger cycle payout
GET /groups/:id/members 🚧 Stub List group members

Full docs with typed request/response bodies and curl examples: docs/api.md

Quick Examples

Create a group

curl -X POST http://localhost:3000/api/groups/create \
  -H "Content-Type: application/json" \
  -d '{
    "adminSecret": "SADMIN...",
    "members": ["GMEMBER1...", "GMEMBER2...", "GMEMBER3..."],
    "contributionAmount": 10000000,
    "cycleDurationDays": 7
  }'

Contribute

curl -X POST http://localhost:3000/api/groups/<id>/contribute \
  -H "Content-Type: application/json" \
  -d '{ "memberSecret": "SMEMBER...", "amount": 10000000 }'

πŸ§ͺ Testing

# Backend β€” Jest with mocked Stellar SDK
cd backend && npm test

# Contract β€” Rust
cd contracts/rosca && cargo test

Current: 8 passing tests across group creation and contribution flows.


🚒 Deployment

See CONTRIBUTING.md for the full deploy walkthrough. Quick reference:

cd contracts/rosca
stellar contract build
stellar contract deploy \
  --wasm target/wasm32v1-none/release/rosca.wasm \
  --source <YOUR_SECRET_KEY> \
  --network testnet

For frontend deployment, run npm run build inside /frontend and deploy the .next output to Vercel or any Node-compatible host.


🀝 Contributing

Contributions are welcome. See CONTRIBUTING.md for full setup, test, and deploy instructions.

How to contribute

  1. Fork the repo
  2. Create a branch: git checkout -b feature/your-feature
  3. Make your changes and write tests
  4. Ensure everything passes: npm test / cargo test
  5. Commit using Conventional Commits: feat: add your feature
  6. Open a PR referencing the relevant issue: Closes #42

Branch naming

Type Pattern
Feature feature/short-description
Bug fix fix/short-description
Docs docs/short-description

Good First Issues


πŸ—ΊοΈ Roadmap

Phase 1 β€” Smart Contract Core βœ…

  • create_group, contribute, trigger_payout
  • Token escrow and multisig treasury
  • On-chain events

Phase 2 β€” Backend API βœ…

  • Group creation endpoint
  • Contribution endpoint with Stellar tx submission
  • Jest test suite with mocked SDK

Phase 3 β€” Frontend Dashboard (in progress)

  • Group management UI
  • Contribution tracking and cycle progress
  • Wallet integration

Phase 4 β€” Persistence

  • Replace in-memory store with PostgreSQL or MongoDB
  • Transaction history and audit log

Phase 5 β€” Mainnet

  • Security audit
  • Mainnet deployment
  • Verifiable randomness for recipient queue (Pyth Entropy)

❓ FAQ

What is a ROSCA? A group savings model where members contribute a fixed amount each cycle and one member receives the full pool, rotating until everyone has been paid out.

Do I need to write code to use this? To run a group today you interact via the API or frontend. No Rust or Solidity knowledge needed.

Which network is supported? Stellar testnet for development. Mainnet deployment is planned for Phase 5 after a security audit.

What happens if a member doesn't contribute? The contract blocks the payout until all members have contributed. A deadline + slash mechanism is planned for Phase 4.

Why is the recipient queue not truly random? True randomness isn't available on-chain β€” every validator must reproduce the same result. The queue is shuffled using a deterministic LCG seeded from the ledger timestamp. A production deployment will use a verifiable randomness oracle.

Where are group funds held? In the Soroban contract as escrow until trigger_payout is called. The multisig treasury account adds a second layer β€” no single member can move funds unilaterally.


πŸ“„ License

MIT

About

A decentralized Rotating Savings and Credit Association (ROSCA) protocol built on the Stellar network. Empowering global communities with trustless, automated savings circles using Soroban smart contracts

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors