This document provides a technical overview of the SprintFund DAO platform architecture.
SprintFund is a decentralized governance platform built on the Stacks blockchain, enabling community-driven funding decisions through transparent proposal and voting mechanisms.
┌─────────────────────────────────────────────────────────────────┐
│ Frontend (Next.js) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ Dashboard │ │Proposals │ │ Voting │ │ Wallet Connect │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────────────┘ │
└────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Stacks Connect SDK │
│ (Wallet Authentication & TX Signing) │
└────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Stacks Blockchain │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ sprintfund-core-v4-minimal.clar │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────────┐ │ │
│ │ │ Staking │ │Proposals│ │ Voting │ │ Execution │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └──────────────┘ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────────┐ │ │
│ │ │Timelock │ │ Quorum │ │Vote Cost│ │ Stake Lockup │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └──────────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ sprintfund-logger.clar │ │
│ │ (Event Logging & Analytics) │ │
│ └────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
frontend/
├── src/
│ ├── app/ # Next.js app router
│ ├── components/ # React components
│ │ ├── ui/ # Reusable UI components
│ │ └── error-boundaries/ # Error handling components
│ ├── hooks/ # Custom React hooks
│ ├── lib/ # Utility functions
│ ├── services/ # API and blockchain services
│ ├── spa-pages/ # Page components
│ ├── store/ # Zustand state management
│ └── types/ # TypeScript type definitions
├── components/ # Legacy components
├── providers/ # React context providers
└── utils/ # Utility functions
┌──────────────────────────────────────────────────────────────┐
│ Zustand Stores │
│ ┌────────────┐ ┌────────────┐ ┌────────────────────────┐ │
│ │ Wallet │ │ Proposals │ │ Notifications │ │
│ │ Store │ │ Store │ │ Store │ │
│ └─────┬──────┘ └─────┬──────┘ └───────────┬────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────────────────┐ │
│ │ Selectors │ │ Selectors │ │ Selectors │ │
│ └────────────┘ └────────────┘ └────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
┌─────────┐ ┌──────────┐ ┌─────────┐ ┌──────────┐ ┌──────────┐
│ Stake │────▶│ Create │────▶│ Vote │────▶│ Timelock │────▶│ Execute │
│ STX │ │ Proposal │ │ (3 days)│ │ (if ≥100)│ │ │
└─────────┘ └──────────┘ └─────────┘ └──────────┘ └──────────┘
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Smart Contract State │
│ stakes-map proposals-map votes-map vote-costs-map executed-map │
└─────────────────────────────────────────────────────────────────────────────┘
User Frontend Smart Contract
│ │ │
│ 1. Connect Wallet │ │
│───────────────────────▶│ │
│ │ │
│ 2. Stake STX │ │
│───────────────────────▶│ 3. Call stake() │
│ │─────────────────────────▶│
│ │ │
│ 4. Fill Form │ │
│───────────────────────▶│ │
│ │ │
│ 5. Submit │ 6. Call create-proposal()
│───────────────────────▶│─────────────────────────▶│
│ │ │
│ 7. Confirmation │ 8. TX Confirmed │
│◀───────────────────────│◀─────────────────────────│
User Frontend Smart Contract
│ │ │
│ 1. View Proposal │ │
│───────────────────────▶│ 2. Read proposal data │
│ │─────────────────────────▶│
│ │◀─────────────────────────│
│ │ │
│ 3. Cast Vote │ │
│───────────────────────▶│ 4. Call vote() │
│ │─────────────────────────▶│
│ │ │
│ 5. Vote Recorded │ 6. TX Confirmed │
│◀───────────────────────│◀─────────────────────────│
The main contract managing all DAO operations with security hardening:
| Function | Description |
|---|---|
stake |
Deposit STX to gain voting power |
withdraw-stake |
Withdraw staked STX (after lockup) |
create-proposal |
Submit a new funding proposal (requires 10 STX stake) |
vote |
Cast vote on active proposal (quadratic cost, locks stake) |
execute-proposal |
Execute approved proposal (proposer only, after timelock) |
reclaim-vote-cost |
Reclaim vote cost after voting period ends |
get-proposal |
Read proposal details |
get-stake |
Read user's stake info |
get-vote |
Read vote details |
get-available-stake |
Get available stake after vote costs |
get-required-quorum |
Get current quorum requirement |
get-total-staked |
Get total STX staked in contract |
get-version |
Get contract version (returns 4) |
- Vote Cost Deduction: Vote costs properly deducted from stake
- Double-Vote Prevention: One vote per user per proposal
- Execution Authorization: Only proposer can execute their proposal
- Voting Period Limits: 3-day voting period (432 blocks)
- Quorum Requirements: 10% of total staked STX required
- Stake Lockup: 1-day lockup after voting (144 blocks)
- Amount Validation: 1-1000 STX range enforced
- Timelock: 1-day delay for proposals ≥100 STX
- Event Emissions: All actions emit events
- Vote Cost Reclaim: Users can reclaim vote costs after voting ends
;; User stakes with lockup
(define-map stakes
{ staker: principal }
{
amount: uint,
locked-until: uint
}
)
;; Proposal storage with timelock
(define-map proposals
{ proposal-id: uint }
{
proposer: principal,
amount: uint,
title: (string-utf8 100),
description: (string-utf8 500),
votes-for: uint,
votes-against: uint,
executed: bool,
created-at: uint,
voting-ends-at: uint,
execution-allowed-at: uint
}
)
;; Vote records with cost tracking
(define-map votes
{ proposal-id: uint, voter: principal }
{
weight: uint,
support: bool,
cost-paid: uint
}
)
;; Vote cost tracking
(define-map vote-costs
{ staker: principal }
{ total-cost: uint }
)- Vote Cost Enforcement: Vote costs are deducted from available stake, preventing unlimited voting
- Double-Vote Prevention:
ERR-ALREADY-VOTEDprevents multiple votes per proposal - Execution Authorization: Only proposers can execute their own proposals
- Time-Based Controls:
- 3-day voting period (432 blocks)
- 1-day timelock for high-value proposals (≥100 STX)
- 1-day stake lockup after voting
- Quorum Requirements: 10% of total staked STX must participate
- Amount Validation: Proposals must be between 1-1000 STX
- Stake Lockup: Prevents vote manipulation by locking stake after voting
- Event Emissions: All actions emit events for transparency and tracking
- Vote Cost Reclaim: Users can reclaim vote costs after voting period ends
- Access Control: Proper authorization checks on all sensitive operations
// Read proposal data
const proposal = await fetchCallReadOnlyFunction({
contractAddress: CONTRACT_ADDRESS,
contractName: 'sprintfund-core-v4-minimal',
functionName: 'get-proposal',
functionArgs: [uintCV(proposalId)],
});
// Submit vote transaction
await openContractCall({
contractAddress: CONTRACT_ADDRESS,
contractName: 'sprintfund-core-v4-minimal',
functionName: 'vote',
functionArgs: [uintCV(proposalId), boolCV(support), uintCV(voteWeight)],
});
// Check available stake
const availableStake = await fetchCallReadOnlyFunction({
contractAddress: CONTRACT_ADDRESS,
contractName: 'sprintfund-core-v4-minimal',
functionName: 'get-available-stake',
functionArgs: [standardPrincipalCV(userAddress)],
});
// Reclaim vote cost after voting ends
await openContractCall({
contractAddress: CONTRACT_ADDRESS,
contractName: 'sprintfund-core-v4-minimal',
functionName: 'reclaim-vote-cost',
functionArgs: [uintCV(proposalId)],
});See CONTRIBUTING.md for development setup and guidelines.