A decentralized aid disbursement platform enabling NGOs to distribute funds to beneficiaries with verifiable, on-chain conditions β powered by the Stellar network and Soroban smart contracts.
- Overview
- Problem Statement
- Solution
- System Architecture
- Key Features
- Tech Stack
- Project Structure
- Getting Started
- Smart Contracts (Soroban)
- Stellar Primitives Used
- API Reference
- Wallet Integration
- Off-Ramp (Mobile Money)
- Security Model
- Audit Trail
- Testing
- Deployment
- Roadmap
- Contributing
- License
AidChain is an open-source platform that enables NGOs and humanitarian organizations to disburse conditional cash transfers (CCTs) to beneficiaries using the Stellar blockchain. Aid funds are locked in escrow and released only when real-world conditions β such as school attendance, health checkups, or job training completion β are verified and recorded on-chain.
Every transaction is transparent, auditable, and settled in seconds at near-zero cost.
Traditional aid distribution systems suffer from:
- Leakage & corruption β Funds are siphoned before reaching intended recipients
- Lack of accountability β Donors cannot verify how or whether funds were used
- High intermediary fees β Banks and remittance providers consume 5β15% of transfers
- Exclusion of the unbanked β ~1.4 billion adults globally lack bank accounts
- No conditionality enforcement β Cash grants lack programmatic controls to drive behavior change (school enrollment, vaccinations, etc.)
AidChain solves these problems by:
- Escrow-first disbursement β Funds are locked on-chain and only released when conditions are met
- Verifiable conditions β Field officers or oracles write condition fulfillment proofs on-chain via Soroban contracts
- Transparent audit trail β Every fund movement is recorded immutably on the Stellar ledger
- Near-zero fees β Stellar transactions cost ~$0.00001, compared to 5β15% for wire transfers
- Mobile-first wallets β Beneficiaries access funds via lightweight wallets, including feature phone support
- Local off-ramps β Integration with mobile money providers (M-Pesa, MTN MoMo) for local cash-out
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β NGO Dashboard β
β (Create programs, fund escrow, view reports) β
ββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
ββββββββββΌβββββββββ
β Backend API β
β (Node.js/Expressβ
ββββββββββ¬βββββββββ
β
ββββββββββββββββββββΌβββββββββββββββββββ
β β β
ββββββββββΌβββββββββ βββββββββΌββββββββ βββββββββΌββββββββ
β Stellar Network β β Soroban β β PostgreSQL β
β β β Contracts β β (off-chain β
β β’ Claimable Bal β β β β records) β
β β’ USDC transfersβ β β’ Oracle β βββββββββββββββββ
β β’ Multisig acct β β β’ Escrow β
ββββββββββ¬βββββββββ βββββββββ¬ββββββββ
β β
ββββββββββββββββββββ
β
ββββββββββββΌβββββββββββ
β Beneficiary Wallet β
β (Freighter / LOBSTRβ
β / Custodial PIN) β
ββββββββββββ¬βββββββββββ
β
ββββββββββββΌβββββββββββ
β Mobile Money β
β Off-Ramp (SEP-24) β
β M-Pesa / MTN MoMo β
βββββββββββββββββββββββ
- NGO creates an aid program and funds an escrow account with USDC
- Beneficiaries are enrolled with their Stellar public keys
- Conditions are defined (time-based, oracle-verified, or admin-approved)
- Field officers record condition fulfillment via the dashboard or mobile app
- Oracle/Soroban contract validates and triggers fund release
- Beneficiary claims their USDC via claimable balance
- Beneficiary off-ramps to mobile money or spends at authorized merchants
- Condition templates β Predefined condition types: school attendance, health visits, job training, time-based, custom
- Multi-tier approval β M-of-N multisig for large disbursements requiring multiple NGO signers
- Batch disbursement β Enroll and fund hundreds of beneficiaries in a single transaction batch
- Real-time dashboard β NGOs see live fund status, condition completion rates, and disbursement history
- SMS notifications β Beneficiaries receive SMS alerts when funds are available for claim
- Donor transparency portal β Donors can track exactly how their contributions are used, down to the beneficiary level
- Offline-first field app β Field officers can record condition verifications offline, syncing when connected
- Audit export β Full transaction logs exportable as CSV or PDF for compliance reporting
| Layer | Technology |
|---|---|
| Blockchain | Stellar (Mainnet / Testnet) |
| Smart Contracts | Soroban (Rust) |
| Backend | Node.js, Express, TypeScript |
| Stellar SDK | @stellar/stellar-sdk |
| Database | PostgreSQL + Prisma ORM |
| Frontend | React, TypeScript, Tailwind CSS |
| Wallet | Freighter SDK, LOBSTR |
| Stablecoin | USDC (Circle, native on Stellar) |
| Off-ramp | Stellar Anchor (SEP-6 / SEP-24) |
| Auth | JWT + role-based access control |
| Notifications | Twilio SMS |
| DevOps | Docker, GitHub Actions |
aidchain/
βββ contracts/ # Soroban smart contracts (Rust)
β βββ oracle/ # Condition oracle contract
β β βββ src/lib.rs
β β βββ Cargo.toml
β βββ escrow/ # Escrow & release contract
β β βββ src/lib.rs
β β βββ Cargo.toml
β βββ Makefile
βββ backend/ # Node.js API server
β βββ src/
β β βββ routes/
β β β βββ ngo.ts
β β β βββ beneficiary.ts
β β β βββ conditions.ts
β β βββ services/
β β β βββ stellar.ts # Stellar SDK wrappers
β β β βββ escrow.ts # Claimable balance logic
β β β βββ oracle.ts # Condition verification
β β βββ middleware/
β β βββ index.ts
β βββ prisma/
β β βββ schema.prisma
β βββ package.json
βββ frontend/ # React dashboard
β βββ src/
β β βββ components/
β β βββ pages/
β β β βββ NGODashboard.tsx
β β β βββ BeneficiaryPortal.tsx
β β β βββ DonorTracker.tsx
β β βββ App.tsx
β βββ package.json
βββ field-app/ # Offline-first field officer PWA
βββ docs/ # Architecture diagrams, API docs
βββ scripts/ # Deployment and utility scripts
βββ docker-compose.yml
βββ .env.example
βββ README.md
- Node.js >= 18.x
- Rust +
cargo(for Soroban contracts) - Docker + Docker Compose
- Stellar CLI (
stellar) - A funded Stellar Testnet account (Friendbot)
# Clone the repository
git clone https://github.com/your-org/aidchain.git
cd aidchain
# Install backend dependencies
cd backend && npm install
# Install frontend dependencies
cd ../frontend && npm install
# Install Stellar CLI (if not already installed)
cargo install --locked stellar-cli --features optCopy .env.example to .env and fill in the values:
cp .env.example .env# Stellar Network
STELLAR_NETWORK=testnet # or 'mainnet'
STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org
STELLAR_RPC_URL=https://soroban-testnet.stellar.org
# NGO Master Account
NGO_PUBLIC_KEY=G...
NGO_SECRET_KEY=S...
# USDC Asset (Testnet)
USDC_ISSUER=GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5
# Soroban Contract IDs (set after deployment)
ORACLE_CONTRACT_ID=
ESCROW_CONTRACT_ID=
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/aidchain
# Auth
JWT_SECRET=your-secret-key
# Twilio (SMS notifications)
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
TWILIO_PHONE_NUMBER=# Start PostgreSQL
docker-compose up -d postgres
# Run database migrations
cd backend && npx prisma migrate dev
# Start the backend API
npm run dev
# In a new terminal, start the frontend
cd ../frontend && npm run devThe API will be available at http://localhost:3001 and the dashboard at http://localhost:3000.
The oracle contract stores condition fulfillment records written by authorized field officers. When a condition is met, it emits an event that triggers fund release.
// contracts/oracle/src/lib.rs
#[contractimpl]
impl OracleContract {
/// Initialize the contract with authorized verifiers
pub fn initialize(env: Env, admin: Address, verifiers: Vec<Address>) { ... }
/// Record a condition as fulfilled for a beneficiary
pub fn fulfill_condition(
env: Env,
verifier: Address,
beneficiary: Address,
program_id: Symbol,
condition_type: Symbol,
evidence_hash: BytesN<32>, // IPFS hash of supporting evidence
) -> bool { ... }
/// Check if a beneficiary's condition is met
pub fn is_condition_met(
env: Env,
beneficiary: Address,
program_id: Symbol,
) -> bool { ... }
}Manages fund locking and conditional release. Integrates with the oracle contract.
// contracts/escrow/src/lib.rs
#[contractimpl]
impl EscrowContract {
/// Lock funds for a beneficiary with a condition
pub fn lock_funds(
env: Env,
ngo: Address,
beneficiary: Address,
amount: i128,
program_id: Symbol,
oracle_contract: Address,
) { ... }
/// Release funds after condition is verified
pub fn release_funds(
env: Env,
beneficiary: Address,
program_id: Symbol,
) -> i128 { ... }
/// Reclaim unclaimed funds after expiry (NGO only)
pub fn reclaim(env: Env, ngo: Address, program_id: Symbol) { ... }
}# Build contracts
cd contracts && make build
# Deploy to testnet
stellar contract deploy \
--wasm target/wasm32-unknown-unknown/release/oracle.wasm \
--source-account $NGO_SECRET_KEY \
--network testnet
# Copy the returned contract ID to your .env as ORACLE_CONTRACT_ID
# Repeat for escrow contractUsed for simple time-based or admin-approved transfers. The NGO creates a claimable balance; the beneficiary claims it once conditions are met.
import { Claimant, Asset, Operation, TransactionBuilder } from '@stellar/stellar-sdk';
const createAidBalance = async (beneficiaryPublicKey, amount, unlockTimestamp) => {
const claimants = [
new Claimant(
beneficiaryPublicKey,
Claimant.predicateNot(
Claimant.predicateBeforeAbsoluteTime(unlockTimestamp.toString())
)
),
// NGO can reclaim if unclaimed after 90 days
new Claimant(
NGO_PUBLIC_KEY,
Claimant.predicateBeforeRelativeTime('7776000')
)
];
const op = Operation.createClaimableBalance({
asset: new Asset('USDC', USDC_ISSUER),
amount: amount.toString(),
claimants,
});
// Build and submit transaction...
};Issue program-specific tokens (e.g., AIDFOOD, AIDHEALTH) for targeted disbursements redeemable only at authorized vendors.
// Issue a custom aid token
const issueAidToken = async (assetCode, recipientKey, amount) => {
const aidAsset = new Asset(assetCode, NGO_PUBLIC_KEY);
// Establish trustline, then payment operation...
};NGO escrow accounts require M-of-N signatures for large disbursements:
// Set account to require 2-of-3 signers
const setMultisig = Operation.setOptions({
masterWeight: 1,
lowThreshold: 2,
medThreshold: 2,
highThreshold: 3,
signer: { ed25519PublicKey: cosignerPublicKey, weight: 1 },
});| Method | Endpoint | Description |
|---|---|---|
POST |
/api/ngo/programs |
Create a new aid program |
GET |
/api/ngo/programs |
List all programs |
POST |
/api/ngo/programs/:id/fund |
Fund escrow for a program |
POST |
/api/ngo/beneficiaries |
Enroll a beneficiary |
GET |
/api/ngo/beneficiaries |
List all beneficiaries |
GET |
/api/ngo/reports |
Get disbursement reports |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/beneficiary/:publicKey/balance |
Get claimable balance |
POST |
/api/beneficiary/:publicKey/claim |
Claim available funds |
GET |
/api/beneficiary/:publicKey/history |
Transaction history |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/conditions/fulfill |
Record condition fulfillment (field officer) |
GET |
/api/conditions/:programId/:beneficiaryId |
Check condition status |
GET |
/api/conditions/pending |
List pending verifications |
Freighter (Browser/Mobile)
import freighterApi from '@stellar/freighter-api';
const connectWallet = async () => {
if (await freighterApi.isConnected()) {
const publicKey = await freighterApi.getPublicKey();
return publicKey;
}
};Custodial PIN Wallet (for feature phones / unbanked users)
For beneficiaries without smartphones, AidChain provides a custodial wallet accessible via USSD or SMS with a 6-digit PIN. Private keys are encrypted and stored server-side using envelope encryption (AES-256 + KMS).
AidChain integrates with Stellar Anchors implementing SEP-24 (interactive deposit/withdrawal) to enable beneficiaries to cash out to:
- MTN Mobile Money (Nigeria, Ghana, Uganda, Rwanda)
- M-Pesa (Kenya, Tanzania, Ethiopia)
- Airtel Money (Multiple African markets)
// Initiate SEP-24 withdrawal
const initiateWithdrawal = async (anchorUrl, assetCode, amount) => {
const toml = await StellarTomlResolver.resolve(anchorUrl);
const transferServerUrl = toml.TRANSFER_SERVER_SEP0024;
const response = await fetch(`${transferServerUrl}/transactions/withdraw/interactive`, {
method: 'POST',
body: JSON.stringify({ asset_code: assetCode, amount }),
});
const { url } = await response.json();
// Redirect beneficiary to anchor's KYC/withdrawal UI
window.open(url);
};- Multisig escrow β No single party can unilaterally move funds
- Oracle authorization β Only whitelisted verifier addresses can fulfill conditions on-chain
- Evidence hashing β Condition fulfillment requires an IPFS content hash of supporting evidence (photos, forms, signatures)
- Expiry & reclaim β Unclaimed funds automatically become reclaimable by the NGO after a defined period, preventing permanent lockup
- Role-based access β NGO admins, field officers, auditors, and beneficiaries have distinct permission levels
- KMS key management β Custodial wallet keys encrypted with AWS KMS or HashiCorp Vault
- Audit logging β All administrative actions logged to immutable append-only store
Every disbursement generates a fully auditable chain of evidence:
Program Created β Stellar tx hash + PostgreSQL record
Beneficiary Enrolled β Stellar account creation tx
Funds Locked β Claimable balance or Soroban escrow tx
Condition Verified β Oracle contract invocation tx + IPFS evidence hash
Funds Released β Soroban release or claimable balance claim tx
Off-ramp Initiated β SEP-24 anchor tx
Donors can verify the entire chain for any beneficiary using the public Donor Transparency Portal, which resolves all hashes to human-readable records.
# Run unit tests
cd backend && npm test
# Run integration tests against Stellar Testnet
npm run test:integration
# Test Soroban contracts
cd contracts && cargo test
# Run end-to-end tests
npm run test:e2e# Build Docker images
docker-compose build
# Deploy to production
docker-compose -f docker-compose.prod.yml up -d
# Run migrations in production
docker-compose exec backend npx prisma migrate deployFor mainnet deployment, ensure:
- All Soroban contracts are audited before deployment
- NGO escrow accounts are set up with production multisig
- USDC issuer is Circle's mainnet address:
GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN - SEP-24 anchor integrations are tested end-to-end in staging
- Claimable balance disbursement
- NGO dashboard (MVP)
- Soroban oracle + escrow contracts
- Field officer mobile app (offline-first)
- SEP-24 mobile money off-ramp integration
- Donor transparency portal
- Multi-language support (French, Swahili, Hausa, Arabic)
- DAO governance for community-run programs
- ZK proof-based condition verification (privacy-preserving)
- Integration with national ID / biometric systems
Contributions are welcome! Please read CONTRIBUTING.md before submitting a PR.
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Commit your changes:
git commit -m 'feat: add my feature' - Push to the branch:
git push origin feature/my-feature - Open a Pull Request
This project is licensed under the MIT License β see LICENSE for details.
Built with β€οΈ to reduce poverty through transparent, accountable aid distribution on Stellar.
v0.1.0 scaffold β 20-day development sprint complete.
| Layer | Status |
|---|---|
| Oracle contract | β 50% β initialize, fulfill, is_condition_met |
| Escrow contract | π² 0% β stubs only, open for contributors |
| Backend API | β 50% β CRUD routes, Stellar service, Prisma schema |
| Frontend | β 90% β NGO Dashboard, Beneficiary Portal, Donor Tracker |
| Field App | π² scaffold only β open for contributors |
See CONTRIBUTING.md to pick up where we left off.