Decentralized ROSCA (Rotating Savings and Credit Association) on Ethereum. Traditional community savings re-imagined for Web3.
A group savings system where members contribute periodically and take turns receiving the pool. Known globally as Tandas 🇲🇽, Susu 🌍, Kameti 🇵🇰, Hui 🇨🇳, Chit Fund 🇮🇳.
- 🔐 Trustless: Smart contracts ensure fair distribution
- 🌐 Global: Permissionless participation
- 🔍 Transparent: On-chain verification
- 🤝 Decentralized: No intermediaries
Note: This is a test implementation. Deploying and interacting with the contract on mainnet will incur gas fees for all operations (deployment, registration, pool distribution).
- Smart Contracts: Solidity 0.8.x
- Development Framework: Hardhat 👷
- Security: Slither Analyzer 🐍
- Deployment: Hardhat Ignition 👷
- Network: Ethereum (Compatible with all EVM networks)
- Web Interface: "Vibe coding" based on Lovable 🪄
-
Setup
- ROSCA Creator (Admin):
- Set participant count & total pool amount
- Pays initial contribution
- ROSCA Creator (Admin):
-
Participation
- Participants join an existing ROSCA contract
- Each participant contributes an equal amount
-
Rounds
- Each round has one designated recipient
- All participants must contribute before pool distribution
- Recipients rotate in order of registration
- Contract manages contribution tracking and distribution
- ✅ Fixed number of participants
- ✅ Equal contribution amounts
- ✅ Automatic recipient rotation
- ✅ Contribution tracking
- ✅ Secure pool distribution
- ✅ View functions for contract status
-
Prerequisites
npm install
-
Compile Contracts
npx hardhat compile
-
Run Tests
npx hardhat test
-
Start a local Hardhat node (in a separate terminal):
npx hardhat node
-
Deploy the contract using the existing Ignition module:
npx hardhat ignition deploy ignition/modules/RoscaModule.ts --network localhost
Note the deployed contract address from the output.
-
Start the Hardhat console:
npx hardhat console --network localhost
-
Example interactions:
// Import parseEther from viem const { parseEther } = await import('viem') // Get contract instance const rosca = await hre.viem.getContractAt("ROSCA", "DEPLOYED_CONTRACT_ADDRESS") // Check contract state await rosca.read.totalParticipants() await rosca.read.currentRound() await rosca.read.contributionAmount() // Check status await rosca.read.getCurrentRoundStatus() // Get test accounts const [owner, participant1, participant2, participant3] = await hre.viem.getWalletClients() // Register participants (each requires 1 ETH) // First participant (owner is already registered during deployment) await rosca.write.registerParticipant({ account: participant1.account, value: parseEther("1") }) // Check status await rosca.read.getCurrentRoundStatus() // Second participant await rosca.write.registerParticipant({ account: participant2.account, value: parseEther("1") }) // Check status await rosca.read.getCurrentRoundStatus() // Third participant await rosca.write.registerParticipant({ account: participant3.account, value: parseEther("1") }) // Check status await rosca.read.getCurrentRoundStatus() // Distribute pool (only by current round recipient) await rosca.write.distributePool()
Note: Replace DEPLOYED_CONTRACT_ADDRESS with the actual address from deployment.
- Make sure Slither is installed
pip3 install slither-analyzer
- Run Slither
slither .
- Usage Guide - Guide for Smart contract interaction
- Web Interface - Web interface (Coming Soon)
This project is licensed under the MIT License - see the LICENSE file for details.