A decentralized crowdfunding platform built on the Stellar network using Soroban smart contracts. Fund-My-Cause lets anyone create a campaign on-chain, accept contributions in XLM or any Stellar token, and automatically release or refund funds based on whether the goal is met.
Check out our public roadmap to see what's coming next!
View the Roadmap — see our planned milestones and features.
Full component details and data-flow walkthroughs: docs/architecture.md
- A creator deploys and initializes a campaign with a funding goal, deadline, and minimum contribution.
- Contributors pledge tokens before the deadline.
- If the goal is met by the deadline, the creator withdraws the funds (minus an optional platform fee).
- If the goal is not met, each contributor individually claims their refund via a pull-based model.
Fund-My-Cause/
├── apps/
│ └── interface/ # Next.js 16 frontend (TypeScript + Tailwind)
│ ├── src/
│ │ ├── app/ # Next.js App Router pages & layouts
│ │ ├── components/ # UI components (Navbar, ProgressBar, PledgeModal, etc.)
│ │ ├── context/ # WalletContext (Freighter wallet integration)
│ │ ├── lib/ # Soroban contract client helpers
│ │ └── types/ # Shared TypeScript types
│ └── package.json
├── contracts/
│ └── crowdfund/ # Soroban smart contract (Rust)
│ ├── src/
│ │ └── lib.rs # Core contract logic
│ └── Cargo.toml
│ └── registry/ # Soroban registry contract for campaign discovery
│ ├── src/
│ │ └── lib.rs # register/list campaign contract IDs
│ └── Cargo.toml
├── scripts/
│ └── deploy.sh # Automated deploy + initialize script
├── .github/
│ └── workflows/
│ └── rust_ci.yml # CI: build WASM + run tests
├── Cargo.toml # Rust workspace config
├── package.json # Node workspace config
└── README.md
The Soroban contract lives in contracts/crowdfund/src/lib.rs and exposes the following interface:
| Function | Description |
|---|---|
initialize(creator, token, goal, deadline, min_contribution, title, description, social_links, platform_config) |
Create a new campaign |
contribute(contributor, amount) |
Pledge tokens before the deadline |
update_metadata(title, description, social_links) |
Update campaign metadata if status is Active |
withdraw() |
Creator claims funds after a successful campaign |
refund_single(contributor) |
Contributor claims their own refund if goal not met |
get_stats() |
Returns CampaignStats (total raised, progress bps, contributor count, etc.) |
total_raised() |
Current total raised |
goal() |
Campaign funding goal |
deadline() |
Campaign deadline (ledger timestamp) |
contribution(contributor) |
Contribution amount for a specific address |
min_contribution() |
Minimum allowed contribution |
title() / description() |
Campaign metadata |
social_links() |
Campaign social URLs |
version() |
Contract version number |
Rather than a single transaction refunding all contributors (which would fail at scale), each contributor calls refund_single to claim their own refund. This is gas-efficient, scalable, and avoids a single point of failure.
An optional PlatformConfig can be set at initialization with a fee in basis points (e.g. 250 = 2.5%). The fee is deducted from the creator's payout on withdrawal and sent to the platform address.
The interface is a Next.js 16 app using the App Router, Tailwind CSS v4, and Freighter wallet integration.
Key components:
Navbar— wallet connect/disconnect via FreighterProgressBar— visual funding progressCountdownTimer— live countdown to campaign deadlinePledgeModal— contribution flow with wallet auth
The app uses @stellar/freighter-api for wallet connectivity. The WalletContext provider wraps the app and exposes connect, disconnect, address, and signTx.
| Requirement | Version | Installation |
|---|---|---|
| Rust | 1.70+ | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh |
| wasm32 target | - | rustup target add wasm32-unknown-unknown |
| Stellar CLI | 21.0+ | Installation Guide |
| Requirement | Version | Installation |
|---|---|---|
| Node.js | 18+ | nodejs.org |
| npm | 9+ | Included with Node.js |
| Freighter | Latest | freighter.app |
- Docker (for containerized deployment)
- GitHub CLI (for release automation)
git clone https://github.com/Fund-My-Cause/Fund-My-Cause.git
cd Fund-My-Cause# Build WASM
cargo build --release --target wasm32-unknown-unknown
# Run tests
cargo test --workspaceDEADLINE=$(date -d "+30 days" +%s)
./scripts/deploy.sh <CREATOR_ADDRESS> <TOKEN_ADDRESS> 1000 $DEADLINE 10 "My Campaign" "A great cause" null [REGISTRY_CONTRACT_ID]If REGISTRY_CONTRACT_ID is omitted, the script deploys a new registry contract.
After campaign initialization, the script calls registry.register(campaign_id) automatically.
Save the printed Contract ID and Registry ID — you'll need them in frontend config.
Use the environment switcher script:
# Switch to development environment
./scripts/switch-env.sh development
# Or manually create .env.local
cp apps/interface/.env.example apps/interface/.env.local
# Edit .env.local with your contract IDsFor detailed configuration options, see docs/environment-config.md.
cd apps/interface
npm install
npm run devOpen http://localhost:3000.
For the full deployment guide — environment variables, multi-stage build details, health checks, production hardening, and troubleshooting — see docs/docker.md.
# 1. Copy and fill in your env vars
cp apps/interface/.env.example apps/interface/.env.local
# Edit apps/interface/.env.local with your contract ID and RPC URL
# 2. Build and start
docker compose up --buildThe app will be available at http://localhost:3000.
# Build context must be the repo root (monorepo workspace)
docker build -f apps/interface/Dockerfile -t fund-my-cause .
docker run -p 3000:3000 --env-file apps/interface/.env.local fund-my-causeThe Dockerfile uses a two-stage build to keep the production image small (~150–250 MB):
builder— installs all dependencies and compiles Next.js withoutput: 'standalone'runner— copies only the standalone bundle; no source files or dev dependencies are shipped
| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_CONTRACT_ID |
Yes | Crowdfund contract address |
NEXT_PUBLIC_RPC_URL |
Yes | Soroban RPC endpoint |
NEXT_PUBLIC_NETWORK_PASSPHRASE |
Yes | Stellar network passphrase |
NEXT_PUBLIC_HORIZON_URL |
No | Horizon REST API endpoint |
NEXT_PUBLIC_PINATA_API_KEY |
No | Pinata IPFS key (image uploads) |
See docs/docker.md for the full variable reference, health check setup, and production deployment considerations.
GitHub Actions workflows:
rust_ci.yml— builds WASM + runs Rust tests on push/PR tomainfrontend_ci.yml— lints and typechecks the frontend on push/PR tomainplaywright.yml— runs Playwright E2E tests on PRs targetingmaindeploy-testnet.yml— deploys contracts to Stellar testnet on push todevelop
Dependabot is configured to keep npm, Cargo, and GitHub Actions dependencies up to date weekly.
The frontend enforces a minimum 80% coverage threshold across all metrics (statements, branches, functions, lines) via Jest. The build fails if any metric drops below this floor.
Run coverage locally:
cd apps/interface
npm run test:coverageThresholds are configured in apps/interface/jest.config.js under coverageThreshold.global.
Fund-My-Cause takes security seriously. For comprehensive security information, see:
- Security Guidelines — Overview of security practices and policies
- Security Model & Threat Analysis — Detailed threat model and mitigation strategies
- Security Checklist — Pre-deployment, deployment, and operational checklists
- Incident Response Procedures — Procedures for detecting and responding to security incidents
- Security Best Practices — User security guidance and wallet security
- SECURITY.md — Vulnerability reporting policy and supported versions
Please do not open a public GitHub issue for security vulnerabilities.
Report vulnerabilities privately via GitHub Security Advisories or email security@fund-my-cause.org.
Include:
- A clear description of the vulnerability
- Steps to reproduce or a proof-of-concept
- Affected component (smart contract, frontend, CI/CD)
- Potential impact assessment
We follow coordinated disclosure and will credit researchers in release notes unless anonymity is requested.
| Resource | Description |
|---|---|
| docs/api/ | Full contract API reference — every function, type, event, and error code |
| docs/tutorials/ | Step-by-step guides: getting started, contributing, dashboards, matching, saved searches |
| sdks/js/ | TypeScript SDK — typed client for all contract operations |
| playground/ | Interactive testnet playground — query and invoke contracts from the CLI or REST Client |
| examples/ | Runnable integration examples (Node.js + React) |
- Fork the repo
- Create a feature branch:
git checkout -b feat/my-feature - Commit with conventional commits:
git commit -m "feat: add X" - Open a pull request
MIT — see LICENSE.
Cargo.lock is committed to this repository intentionally.
For application binaries and smart contracts, locking every transitive dependency to an exact version is a security requirement — not optional. Without it:
- A
cargo buildon a different machine or at a later date may silently pull in a newer (potentially compromised or breaking) version of any dependency. - Audits and vulnerability scans target specific versions; a floating lock file makes those results meaningless.
- Soroban WASM bytecode must be byte-for-byte reproducible so that on-chain contract hashes can be independently verified.
This follows the Cargo book's recommendation for binaries and aligns with Rust smart contract best practices.
Fund-My-Cause is powered by the Stellar network and Soroban smart contracts. Stellar provides fast, low-cost transactions with 5-second finality, making it ideal for crowdfunding at scale.