Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

StellarVault

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.

License: MIT Stellar


🎯 Problem Statement

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.


🏗️ Architecture

┌─────────────────────────────────────────────────────────────┐
│                       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.


🚀 Quick Start

Prerequisites

1. Deploy the Contract

# Clone the repository
git clone https://github.com/babatech/stellarvault
cd stellarvault

# Build and deploy to Testnet
./scripts/deploy_testnet.sh

This will:

  • Build the contract WASM
  • Optimize for size
  • Deploy to Stellar Testnet
  • Save the contract ID to frontend/.env.local

2. Initialize the Vault

# 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.sh

3. Run the Frontend

cd frontend
npm install
npm run dev

Open http://localhost:3000 and connect your Freighter wallet.


📚 Contract API Reference

All functions enforce require_auth() on the appropriate signer.

Function Parameters Auth Required Returns Description
initialize signers: Vec<Address>
threshold: u32
daily_limit: i128
large_transfer_threshold: i128
timelock_seconds: u64
token: Address
No (one-time) Result<()> Initialize vault (callable once)
propose_transfer proposer: Address
to: Address
amount: i128
Yes (proposer) Result<u64> Create a transfer proposal
propose_signer_change proposer: Address
add: Option<Address>
remove: Option<Address>
new_threshold: Option<u32>
Yes (proposer) Result<u64> Propose signer set changes
approve_transfer signer: Address
proposal_id: u64
Yes (signer) Result<()> Approve a proposal
revoke_approval signer: Address
proposal_id: u64
Yes (signer) Result<()> Revoke your approval
execute_transfer caller: Address
proposal_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 Codes

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


🔧 CLI Usage Examples

# 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 1

See scripts/invoke_examples.sh for complete examples.


🧪 Testing

cargo test

# Run with output
cargo test -- --nocapture

# Run specific test
cargo test test_initialize_success

Coverage: 25+ unit and integration tests covering:

  • ✅ All public functions (success + failure paths)
  • ✅ Authorization checks
  • ✅ Timelock enforcement
  • ✅ Daily limit tracking
  • ✅ Signer rotation
  • ✅ Full proposal lifecycle

📖 Documentation


🌊 Wave-Ready: Good First Issues

This project is designed for Stellar Wave Program contributors. Here are scoped, well-documented issues to get started:

🟢 Easy (5-10 points)

  1. Add spending category tags
    Add an optional category: String field to transfer proposals for treasury accounting.
    Files: types.rs, lib.rs
    Skills: Rust, Soroban SDK

  2. Proposal expiry
    Add expires_at: u64 to proposals and reject execution after expiry.
    Files: types.rs, lib.rs, test.rs
    Skills: Rust, time-based logic

  3. Frontend: Export proposal history to CSV
    Add a "Download CSV" button on the dashboard.
    Files: frontend/app/page.tsx
    Skills: TypeScript, React

🟡 Medium (15-25 points)

  1. Signer weighting (non-uniform voting power)
    Replace boolean approvals with weighted votes. Store signer → weight map.
    Files: types.rs, storage.rs, lib.rs, test.rs
    Skills: Rust, contract storage design

  2. Emergency pause mechanism
    Add a special pause() function requiring a higher threshold (e.g., 75%) to freeze all transfers.
    Files: lib.rs, storage.rs, test.rs
    Skills: Rust, state machine design

🔴 Hard (30-50 points)

  1. Per-recipient allowlist with separate limits
    Store recipient → monthly_limit map. 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

  2. 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

  3. Multi-token support
    Generalize to support multiple token types in one vault.
    Files: Major refactor of storage.rs, lib.rs, test.rs
    Skills: Rust, contract architecture, testing


🤝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Run tests (cargo test && cd frontend && npm run lint)
  4. Commit with clear messages
  5. Open a Pull Request

See CONTRIBUTING.md for guidelines.


🛡️ Security

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.


📜 License

This project is licensed under the MIT License - see LICENSE file.


🌟 Why This Project is Wave-Ready

Stellar Wave Program rewards contributors for improving the Stellar ecosystem. StellarVault is optimized for Wave:

  1. Clear Problem Statement: Fills a documented gap in Stellar's treasury tooling (SDF priority)
  2. Modular Codebase: Well-structured with isolated, testable components
  3. Good First Issues: 8 pre-scoped issues ranging from 5-50 points
  4. Documentation: Extensive inline docs, architecture guides, and API reference
  5. Production Quality: 90%+ test coverage, error handling, security documentation
  6. Open License: MIT — freely forkable and improvable

For Wave Contributors: Pick an issue above, claim it in Discussions, submit your PR, and earn points!


🙏 Acknowledgments

Built with ❤️ for the Stellar community.


📞 Support


Built on Stellar. Secured by Soroban. Powered by community.

About

Programmable multi-sig treasury vault for Stellar DAOs, grant committees, and ecosystem funds — spending limits, timelocked large transfers, signer rotation

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages