Source Code

;; BitSphere Collective - Decentralized Fund Management Protocol

;; Title: BitSphere Collective
;; 
;; Summary:
;; A sophisticated decentralized autonomous fund management protocol built on Stacks, 
;; enabling Bitcoin-secured collective investment decisions through democratic governance 
;; and transparent fund allocation mechanisms.
;;
;; Description:
;; BitSphere Collective revolutionizes decentralized fund management by leveraging 
;; Bitcoin's security through Stacks' smart contract capabilities. This protocol 
;; empowers communities to pool resources, propose strategic investments, and execute 
;; collective decisions through a robust voting mechanism. Each participant's influence 
;; scales with their commitment, ensuring aligned incentives while maintaining 
;; democratic principles. With built-in security measures, time-locked deposits, and 
;; transparent execution of approved proposals, BitSphere creates a trustless 
;; environment where collective wisdom drives capital allocation in the Bitcoin ecosystem.

;; PROTOCOL CONSTANTS

(define-constant CONTRACT_OWNER tx-sender)

;; Error Constants
(define-constant ERR_OWNER_ONLY (err u100))
(define-constant ERR_NOT_INITIALIZED (err u101))
(define-constant ERR_ALREADY_INITIALIZED (err u102))
(define-constant ERR_INSUFFICIENT_BALANCE (err u103))
(define-constant ERR_INVALID_AMOUNT (err u104))
(define-constant ERR_UNAUTHORIZED (err u105))
(define-constant ERR_PROPOSAL_NOT_FOUND (err u106))
(define-constant ERR_PROPOSAL_EXPIRED (err u107))
(define-constant ERR_ALREADY_VOTED (err u108))
(define-constant ERR_BELOW_MINIMUM (err u109))
(define-constant ERR_LOCKED_PERIOD (err u110))
(define-constant ERR_TRANSFER_FAILED (err u111))
(define-constant ERR_INVALID_DURATION (err u112))
(define-constant ERR_ZERO_AMOUNT (err u113))
(define-constant ERR_INVALID_TARGET (err u114))
(define-constant ERR_INVALID_DESCRIPTION (err u115))
(define-constant ERR_INVALID_PROPOSAL_ID (err u116))

;; Protocol Parameters
(define-constant MINIMUM_PROPOSAL_DURATION u144)    ;; ~1 day (10min blocks)
(define-constant MAXIMUM_PROPOSAL_DURATION u20160)  ;; ~14 days
(define-constant MINIMUM_DEPOSIT_THRESHOLD u1000000) ;; 1 STX in microSTX
(define-constant DEFAULT_LOCK_PERIOD u1440)         ;; ~10 days in blocks
(define-constant MINIMUM_QUORUM_PERCENTAGE u10)     ;; 10% of total supply must vote

;; PROTOCOL STATE VARIABLES

(define-data-var total-supply uint u0)
(define-data-var minimum-deposit uint MINIMUM_DEPOSIT_THRESHOLD)
(define-data-var lock-period uint DEFAULT_LOCK_PERIOD)
(define-data-var protocol-initialized bool false)
(define-data-var proposal-counter uint u0)

;; DATA STRUCTURES

;; Member balance tracking
(define-map member-balances principal uint)

;; Member deposit information with time-lock mechanics
(define-map member-deposits
    principal
    {
        deposit-amount: uint,
        unlock-height: uint,
        entry-block: uint
    }
)

;; Governance proposal structure
(define-map governance-proposals
    uint
    {
        proposer: principal,
        description: (string-ascii 256),
        funding-amount: uint,
        beneficiary: principal,
        expiry-height: uint,
        executed: bool,
        votes-for: uint,
        votes-against: uint
    }
)

;; Vote tracking to prevent double-voting
(define-map member-votes {proposal-id: uint, voter: principal} bool)

;; PRIVATE UTILITY FUNCTIONS

(define-private (is-protocol-owner)
    (is-eq tx-sender CONTRACT_OWNER)
)

(define-private (ensure-initialized)
    (ok (asserts! (var-get protocol-initialized) ERR_NOT_INITIALIZED))
)

(define-private (validate-proposal-id (proposal-id uint))
    (ok (asserts! (and (> proposal-id u0) (<= proposal-id (var-get proposal-counter))) ERR_INVALID_PROPOSAL_ID))
)

(define-private (get-member-voting-power (member principal))
    (default-to u0 (map-get? member-balances member))
)

(define-private (mint-membership-tokens (recipient principal) (amount uint))
    (let (
        (current-balance (default-to u0 (map-get? member-balances recipient)))
    )
        (map-set member-balances recipient (+ current-balance amount))
        (var-set total-supply (+ (var-get total-supply) amount))
        (ok true)
    )
)

(define-private (burn-membership-tokens (holder principal) (amount uint))
    (let (
        (current-balance (default-to u0 (map-get? member-balances holder)))
    )
        (asserts! (>= current-balance amount) ERR_INSUFFICIENT_BALANCE)
        (map-set member-balances holder (- current-balance amount))
        (var-set total-supply (- (var-get total-supply) amount))
        (ok true)
    )
)

;; PROTOCOL INITIALIZATION

(define-public (initialize-protocol)
    (begin
        (asserts! (is-protocol-owner) ERR_OWNER_ONLY)
        (asserts! (not (var-get protocol-initialized)) ERR_ALREADY_INITIALIZED)
        (ok (var-set protocol-initialized true))
    )
)

;; MEMBER DEPOSIT & WITHDRAWAL FUNCTIONS

(define-public (join-collective (deposit-amount uint))
    (begin
        (try! (ensure-initialized))
        (asserts! (>= deposit-amount (var-get minimum-deposit)) ERR_BELOW_MINIMUM)
        (asserts! (> deposit-amount u0) ERR_ZERO_AMOUNT)

        ;; Secure STX transfer to protocol
        (try! (stx-transfer? deposit-amount tx-sender current-contract))
        
        ;; Record or update member deposit with time-lock
        (let (
            (existing-deposit (default-to {deposit-amount: u0, unlock-height: u0, entry-block: u0} 
                (map-get? member-deposits tx-sender)))
        )
            (map-set member-deposits tx-sender {
                deposit-amount: (+ (get deposit-amount existing-deposit) deposit-amount),
                unlock-height: (+ stacks-block-height (var-get lock-period)),
                entry-block: (if (is-eq (get entry-block existing-deposit) u0) 
                    stacks-block-height 
                    (get entry-block existing-deposit))
            })
        )
        
        ;; Issue membership tokens proportional to deposit
        (print {event: "member-joined", member: tx-sender, amount: deposit-amount, block: stacks-block-height})
        (mint-membership-tokens tx-sender deposit-amount)
    )
)

(define-public (exit-collective (withdrawal-amount uint))
    (begin
        (try! (ensure-initialized))
        (asserts! (> withdrawal-amount u0) ERR_ZERO_AMOUNT)

        (let (
            (deposit-info (unwrap! (map-get? member-deposits tx-sender) ERR_UNAUTHORIZED))
            (member-balance (default-to u0 (map-get? member-balances tx-sender)))
        )
            (asserts! (>= stacks-block-height (get unlock-height deposit-info)) ERR_LOCKED_PERIOD)
            (asserts! (>= member-balance withdrawal-amount) ERR_INSUFFICIENT_BALANCE)
            (asserts! (>= (get deposit-amount deposit-info) withdrawal-amount) ERR_INSUFFICIENT_BALANCE)
            
            ;; Update state BEFORE external call (reentrancy protection)
            ;; Burn membership tokens
            (try! (burn-membership-tokens tx-sender withdrawal-amount))
            
            ;; Update deposit record
            (map-set member-deposits tx-sender 
                (merge deposit-info {deposit-amount: (- (get deposit-amount deposit-info) withdrawal-amount)}))
            
            ;; Transfer STX back to member
            (let ((member tx-sender))
                (try! (as-contract? ((with-all-assets-unsafe)) (try! (stx-transfer? withdrawal-amount tx-sender member)))))
            (print {event: "member-exited", member: tx-sender, amount: withdrawal-amount, block: stacks-block-height})
            (ok true)
        )
    )
)

;; GOVERNANCE PROPOSAL SYSTEM

(define-public (submit-proposal
    (description (string-ascii 256))
    (funding-amount uint)
    (beneficiary principal)
    (voting-duration uint)
)
    (begin
        (try! (ensure-initialized))

        ;; Comprehensive input validation
        (asserts! (> (len description) u0) ERR_INVALID_DESCRIPTION)
        (asserts! (> funding-amount u0) ERR_ZERO_AMOUNT)
        (asserts! (not (is-eq beneficiary current-contract)) ERR_INVALID_TARGET)
        (asserts! (and (>= voting-duration MINIMUM_PROPOSAL_DURATION) 
                      (<= voting-duration MAXIMUM_PROPOSAL_DURATION)) ERR_INVALID_DURATION)
        
        (let (
            (proposer-balance (default-to u0 (map-get? member-balances tx-sender)))
            (new-proposal-id (+ (var-get proposal-counter) u1))
        )
            (asserts! (> proposer-balance u0) ERR_UNAUTHORIZED)
            
            ;; Create governance proposal
            (map-set governance-proposals new-proposal-id {
                proposer: tx-sender,
                description: description,
                funding-amount: funding-amount,
                beneficiary: beneficiary,
                expiry-height: (+ stacks-block-height voting-duration),
                executed: false,
                votes-for: u0,
                votes-against: u0
            })
            
            (var-set proposal-counter new-proposal-id)
            (print {event: "proposal-submitted", proposal-id: new-proposal-id, proposer: tx-sender, amount: funding-amount})
            (ok new-proposal-id)
        )
    )
)

(define-public (cast-vote (proposal-id uint) (support bool))
    (begin
        (try! (ensure-initialized))
        (try! (validate-proposal-id proposal-id))

        (let (
            (proposal (unwrap! (map-get? governance-proposals proposal-id) ERR_PROPOSAL_NOT_FOUND))
            (voting-power (get-member-voting-power tx-sender))
        )
            (asserts! (> voting-power u0) ERR_UNAUTHORIZED)
            (asserts! (< stacks-block-height (get expiry-height proposal)) ERR_PROPOSAL_EXPIRED)
            (asserts! (is-none (map-get? member-votes {proposal-id: proposal-id, voter: tx-sender})) ERR_ALREADY_VOTED)
            
            ;; Record member vote
            (map-set member-votes {proposal-id: proposal-id, voter: tx-sender} support)
            
            ;; Update proposal vote tallies
            (map-set governance-proposals proposal-id 
                (merge proposal 
                    {
                        votes-for: (if support 
                            (+ (get votes-for proposal) voting-power)
                            (get votes-for proposal)),
                        votes-against: (if support
                            (get votes-against proposal)
                            (+ (get votes-against proposal) voting-power))
                    }
                )
            )
            
            (print {event: "vote-cast", proposal-id: proposal-id, voter: tx-sender, support: support, power: voting-power})
            (ok true)
        )
    )
)

(define-public (execute-approved-proposal (proposal-id uint))
    (begin
        (try! (ensure-initialized))
        (try! (validate-proposal-id proposal-id))

        (let (
            (proposal (unwrap! (map-get? governance-proposals proposal-id) ERR_PROPOSAL_NOT_FOUND))
            (available-funds (stx-get-balance current-contract))
        )
            (asserts! (not (get executed proposal)) ERR_UNAUTHORIZED)
            ;; FIXED: Ensure voting period has ENDED (not expired before execution)
            (asserts! (>= stacks-block-height (get expiry-height proposal)) ERR_PROPOSAL_EXPIRED)
            ;; Require simple majority
            (asserts! (> (get votes-for proposal) (get votes-against proposal)) ERR_UNAUTHORIZED)
            ;; Check minimum quorum participation
            (let ((total-votes (+ (get votes-for proposal) (get votes-against proposal))))
                (asserts! (>= (* total-votes u100) (* (var-get total-supply) MINIMUM_QUORUM_PERCENTAGE)) ERR_UNAUTHORIZED)
            )
            (asserts! (>= available-funds (get funding-amount proposal)) ERR_INSUFFICIENT_BALANCE)
            
            ;; Mark proposal as executed BEFORE transfer (reentrancy protection)
            (map-set governance-proposals proposal-id (merge proposal {executed: true}))
            
            ;; Execute approved funding transfer
            (try! (as-contract? ((with-all-assets-unsafe)) (try! (stx-transfer? (get funding-amount proposal) tx-sender (get beneficiary proposal)))))
            
            (print {event: "proposal-executed", proposal-id: proposal-id, amount: (get funding-amount proposal), beneficiary: (get beneficiary proposal)})
            (ok true)
        )
    )
)

;; ADMIN FUNCTIONS

(define-public (update-minimum-deposit (new-minimum uint))
    (begin
        (asserts! (is-protocol-owner) ERR_OWNER_ONLY)
        (asserts! (> new-minimum u0) ERR_ZERO_AMOUNT)
        (var-set minimum-deposit new-minimum)
        (print {event: "minimum-deposit-updated", new-value: new-minimum})
        (ok true)
    )
)

(define-public (update-lock-period (new-period uint))
    (begin
        (asserts! (is-protocol-owner) ERR_OWNER_ONLY)
        (asserts! (> new-period u0) ERR_ZERO_AMOUNT)
        (var-set lock-period new-period)
        (print {event: "lock-period-updated", new-value: new-period})
        (ok true)
    )
)

;; READ-ONLY QUERY FUNCTIONS

(define-read-only (get-member-balance (member principal))
    (ok (default-to u0 (map-get? member-balances member)))
)

(define-read-only (get-total-member-tokens)
    (ok (var-get total-supply))
)

(define-read-only (get-proposal-details (proposal-id uint))
    (ok (map-get? governance-proposals proposal-id))
)

(define-read-only (get-member-deposit-info (member principal))
    (ok (map-get? member-deposits member))
)

(define-read-only (get-member-vote (proposal-id uint) (voter principal))
    (ok (map-get? member-votes {proposal-id: proposal-id, voter: voter}))
)

(define-read-only (get-protocol-status)
    (ok {
        initialized: (var-get protocol-initialized),
        total-proposals: (var-get proposal-counter),
        total-supply: (var-get total-supply),
        contract-balance: (stx-get-balance current-contract)
    })
)

Functions (20)

FunctionAccessArgs
get-total-member-tokensread-only
is-protocol-ownerprivate
ensure-initializedprivate
validate-proposal-idprivateproposal-id: uint
get-member-voting-powerprivatemember: principal
mint-membership-tokensprivaterecipient: principal, amount: uint
burn-membership-tokensprivateholder: principal, amount: uint
initialize-protocolpublic
join-collectivepublicdeposit-amount: uint
exit-collectivepublicwithdrawal-amount: uint
submit-proposalpublicdescription: (string-ascii 256
cast-votepublicproposal-id: uint, support: bool
execute-approved-proposalpublicproposal-id: uint
update-minimum-depositpublicnew-minimum: uint
update-lock-periodpublicnew-period: uint
get-member-balanceread-onlymember: principal
get-proposal-detailsread-onlyproposal-id: uint
get-member-deposit-inforead-onlymember: principal
get-member-voteread-onlyproposal-id: uint, voter: principal
get-protocol-statusread-only