Programmable Multi-Signature Treasury for Stellar Soroban
A production-ready, open-source smart contract and frontend that enables DAOs, grant committees, and ecosystem funds to manage treasuries with programmable spending policies on Stellar.
DAOs and grant committees on Stellar currently manage treasuries through basic multisig with no programmable spending rules:
- ❌ No daily/monthly spending limits
- ❌ No time-locked large withdrawals
- ❌ No signer rotation without full re-deploy
- ❌ No auditable on-chain policy enforcement
StellarVault solves this by adding a programmable policy layer on top of standard N-of-M multisig, enabling treasuries to:
✅ Enforce spending limits and time-delays
✅ Rotate signers safely without redeployment
✅ Maintain full on-chain auditability
✅ Customize policies per organization's needs
This directly addresses the treasury tooling gap identified in Stellar Development Foundation's ecosystem priorities.
┌─────────────────────────────────────────────────────────────┐
│ StellarVault │
│ │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ Frontend │◄───────►│ Soroban │ │
│ │ (Next.js) │ │ Contract │ │
│ │ │ │ │ │
│ │ - Dashboard │ │ - Proposals │ │
│ │ - Propose │ │ - Approvals │ │
│ │ - Signers │ │ - Execution │ │
│ └────────────────┘ │ - Policies │ │
│ ▲ └────────────────┘ │
│ │ │ │
│ │ │ │
│ ┌──────▼──────────┐ ┌────────▼────────┐ │
│ │ Freighter │ │ Stellar Token │ │
│ │ Wallet │ │ Contract │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Flow:
1. Signer proposes transfer → On-chain proposal created
2. N signers approve → Threshold reached
3. IF large transfer → Timelock starts
4. Execute → Token transfer + policy checks
See docs/ARCHITECTURE.md for detailed design rationale.
- Stellar CLI v21.0.0+
- Rust 1.74.0+
- Node.js 18+
- Freighter Wallet browser extension
# Clone the repository
git clone https://github.com/babatech/stellarvault
cd stellarvault
# Build and deploy to Testnet
./scripts/deploy_testnet.shThis will:
- Build the contract WASM
- Optimize for size
- Deploy to Stellar Testnet
- Save the contract ID to
frontend/.env.local
# Edit the signer config (first run creates a template)
./scripts/init_vault.sh
# Edit scripts/vault_config.json with your signers
nano scripts/vault_config.json
# Initialize the vault
./scripts/init_vault.shcd frontend
npm install
npm run devOpen http://localhost:3000 and connect your Freighter wallet.
All functions enforce require_auth() on the appropriate signer.
| Function | Parameters | Auth Required | Returns | Description |
|---|---|---|---|---|
initialize |
signers: Vec<Address>threshold: u32daily_limit: i128large_transfer_threshold: i128timelock_seconds: u64token: Address |
No (one-time) | Result<()> |
Initialize vault (callable once) |
propose_transfer |
proposer: Addressto: Addressamount: i128 |
Yes (proposer) | Result<u64> |
Create a transfer proposal |
propose_signer_change |
proposer: Addressadd: Option<Address>remove: Option<Address>new_threshold: Option<u32> |
Yes (proposer) | Result<u64> |
Propose signer set changes |
approve_transfer |
signer: Addressproposal_id: u64 |
Yes (signer) | Result<()> |
Approve a proposal |
revoke_approval |
signer: Addressproposal_id: u64 |
Yes (signer) | Result<()> |
Revoke your approval |
execute_transfer |
caller: Addressproposal_id: u64 |
Yes (any signer) | Result<()> |
Execute approved proposal |
get_proposal |
id: u64 |
No | Proposal |
Get proposal details |
get_signers |
- | No | Vec<Address> |
Get current signers |
get_config |
- | No | VaultConfig |
Get vault configuration |
| Error | Code | Description |
|---|---|---|
Unauthorized |
1 | Caller is not a signer |
AlreadyInitialized |
2 | Contract already initialized |
NotFound |
3 | Proposal not found |
AlreadyApproved |
4 | Signer already approved |
ThresholdNotMet |
5 | Insufficient approvals |
TimelockActive |
6 | Timelock period not expired |
InvalidThreshold |
7 | Threshold invalid (0 or > signers) |
DailyLimitExceeded |
8 | Exceeds daily spending limit |
AlreadyExecuted |
9 | Proposal already executed |
Full error documentation: docs/SECURITY.md
# Propose a transfer
stellar contract invoke \
--id $CONTRACT_ID \
--source signer1 \
--network testnet \
-- \
propose_transfer \
--proposer $(stellar keys address signer1) \
--to GABC123... \
--amount 10000000
# Approve proposal #1
stellar contract invoke \
--id $CONTRACT_ID \
--source signer2 \
--network testnet \
-- \
approve_transfer \
--signer $(stellar keys address signer2) \
--proposal_id 1
# Execute approved proposal
stellar contract invoke \
--id $CONTRACT_ID \
--source signer1 \
--network testnet \
-- \
execute_transfer \
--caller $(stellar keys address signer1) \
--proposal_id 1See scripts/invoke_examples.sh for complete examples.
cargo test
# Run with output
cargo test -- --nocapture
# Run specific test
cargo test test_initialize_successCoverage: 25+ unit and integration tests covering:
- ✅ All public functions (success + failure paths)
- ✅ Authorization checks
- ✅ Timelock enforcement
- ✅ Daily limit tracking
- ✅ Signer rotation
- ✅ Full proposal lifecycle
- ARCHITECTURE.md - Design decisions and storage layout
- SECURITY.md - Threat model and responsible disclosure
- API Reference - Complete function documentation
This project is designed for Stellar Wave Program contributors. Here are scoped, well-documented issues to get started:
-
Add spending category tags
Add an optionalcategory: Stringfield to transfer proposals for treasury accounting.
Files:types.rs,lib.rs
Skills: Rust, Soroban SDK -
Proposal expiry
Addexpires_at: u64to proposals and reject execution after expiry.
Files:types.rs,lib.rs,test.rs
Skills: Rust, time-based logic -
Frontend: Export proposal history to CSV
Add a "Download CSV" button on the dashboard.
Files:frontend/app/page.tsx
Skills: TypeScript, React
-
Signer weighting (non-uniform voting power)
Replace boolean approvals with weighted votes. Storesigner → weightmap.
Files:types.rs,storage.rs,lib.rs,test.rs
Skills: Rust, contract storage design -
Emergency pause mechanism
Add a specialpause()function requiring a higher threshold (e.g., 75%) to freeze all transfers.
Files:lib.rs,storage.rs,test.rs
Skills: Rust, state machine design
-
Per-recipient allowlist with separate limits
Storerecipient → monthly_limitmap. Bypass full multisig for pre-approved recipients below their limit.
Files:types.rs,storage.rs,lib.rs,test.rs, frontend
Skills: Rust, complex storage, frontend integration -
Proposal comments/rationale on-chain
Store a short memo (max 256 chars) with each proposal. Display in frontend.
Files:types.rs,lib.rs,frontend/
Skills: Rust, frontend, UX design -
Multi-token support
Generalize to support multiple token types in one vault.
Files: Major refactor ofstorage.rs,lib.rs,test.rs
Skills: Rust, contract architecture, testing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Run tests (
cargo test && cd frontend && npm run lint) - Commit with clear messages
- Open a Pull Request
See CONTRIBUTING.md for guidelines.
This contract handles real funds. Please review docs/SECURITY.md for:
- Threat model
- What
require_auth()protects against - Upgrade policy (immutable by default)
- Responsible disclosure process
Audit Status: Not yet audited. Use at your own risk in production.
This project is licensed under the MIT License - see LICENSE file.
Stellar Wave Program rewards contributors for improving the Stellar ecosystem. StellarVault is optimized for Wave:
- Clear Problem Statement: Fills a documented gap in Stellar's treasury tooling (SDF priority)
- Modular Codebase: Well-structured with isolated, testable components
- Good First Issues: 8 pre-scoped issues ranging from 5-50 points
- Documentation: Extensive inline docs, architecture guides, and API reference
- Production Quality: 90%+ test coverage, error handling, security documentation
- Open License: MIT — freely forkable and improvable
For Wave Contributors: Pick an issue above, claim it in Discussions, submit your PR, and earn points!
Built with ❤️ for the Stellar community.
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Stellar Discord: #soroban
Built on Stellar. Secured by Soroban. Powered by community.