Source Code

;; Simple DAO Voting Contract
;; Members can create and vote on proposals

(define-constant contract-owner tx-sender)
(define-constant err-not-member (err u100))
(define-constant err-already-voted (err u101))
(define-constant err-proposal-not-found (err u102))
(define-constant err-voting-closed (err u103))

(define-data-var proposal-count uint u0)
(define-data-var voting-period uint u144) ;; ~1 day in blocks

(define-map members principal bool)
(define-map proposals
    uint
    {
        proposer: principal,
        title: (string-ascii 50),
        description: (string-ascii 500),
        votes-for: uint,
        votes-against: uint,
        start-block: uint,
        executed: bool
    }
)
(define-map votes {proposal-id: uint, voter: principal} bool)

;; Add member (only owner)
(define-public (add-member (member principal))
    (begin
        (asserts! (is-eq tx-sender contract-owner) err-not-member)
        (ok (map-set members member true))
    )
)

;; Create proposal
(define-public (create-proposal (title (string-ascii 50)) (description (string-ascii 500)))
    (let
        (
            (proposal-id (var-get proposal-count))
        )
        (asserts! (default-to false (map-get? members tx-sender)) err-not-member)
        (map-set proposals proposal-id {
            proposer: tx-sender,
            title: title,
            description: description,
            votes-for: u0,
            votes-against: u0,
            start-block: block-height,
            executed: false
        })
        (var-set proposal-count (+ proposal-id u1))
        (ok proposal-id)
    )
)

;; Vote on proposal
(define-public (vote (proposal-id uint) (support bool))
    (let
        (
            (proposal (unwrap! (map-get? proposals proposal-id) err-proposal-not-found))
            (voter-key {proposal-id: proposal-id, voter: tx-sender})
        )
        (asserts! (default-to false (map-get? members tx-sender)) err-not-member)
        (asserts! (is-none (map-get? votes voter-key)) err-already-voted)
        (asserts! (< (- block-height (get start-block proposal)) (var-get voting-period)) err-voting-closed)
        
        (map-set votes voter-key true)
        (if support
            (map-set proposals proposal-id (merge proposal {votes-for: (+ (get votes-for proposal) u1)}))
            (map-set proposals proposal-id (merge proposal {votes-against: (+ (get votes-against proposal) u1)}))
        )
        (ok true)
    )
)

;; Read-only functions
(define-read-only (get-proposal (proposal-id uint))
    (map-get? proposals proposal-id)
)

(define-read-only (has-voted (proposal-id uint) (voter principal))
    (is-some (map-get? votes {proposal-id: proposal-id, voter: voter}))
)

(define-read-only (is-member (account principal))
    (default-to false (map-get? members account))
)

;; Initialize contract owner as member
(map-set members contract-owner true)

Functions (6)

FunctionAccessArgs
add-memberpublicmember: principal
create-proposalpublictitle: (string-ascii 50
votepublicproposal-id: uint, support: bool
get-proposalread-onlyproposal-id: uint
has-votedread-onlyproposal-id: uint, voter: principal
is-memberread-onlyaccount: principal