Source Code

;; axion-chain - DAO Governance Protocol
;; On-chain voting and proposal execution

(define-constant CONTRACT-OWNER tx-sender)
(define-constant MIN-PROPOSAL-THRESHOLD u1000000)
(define-constant VOTING-PERIOD u1008)
(define-constant QUORUM-THRESHOLD u10)
(define-constant ERR-OWNER-ONLY (err u100))
(define-constant ERR-THRESHOLD (err u101))
(define-constant ERR-NOT-FOUND (err u102))
(define-constant ERR-ALREADY-VOTED (err u103))
(define-constant ERR-VOTING-CLOSED (err u104))
(define-constant ERR-VOTING-OPEN (err u105))
(define-constant ERR-QUORUM-NOT-MET (err u106))

(define-map proposals uint
  { proposer: principal,
    title: (string-ascii 64),
    description: (string-utf8 512),
    votes-for: uint,
    votes-against: uint,
    start-block: uint,
    end-block: uint,
    executed: bool,
    canceled: bool })

(define-map votes { proposal-id: uint, voter: principal } bool)
(define-map member-power principal uint)

(define-data-var proposal-count uint u0)
(define-data-var total-members uint u0)

(define-public (register-member (power uint))
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-OWNER-ONLY)
    (map-set member-power tx-sender power)
    (var-set total-members (+ (var-get total-members) u1))
    (ok true)))

(define-public (create-proposal (title (string-ascii 64)) (description (string-utf8 512)))
  (let ((power (default-to u0 (map-get? member-power tx-sender)))
        (pid (+ (var-get proposal-count) u1)))
    (asserts! (>= power MIN-PROPOSAL-THRESHOLD) ERR-THRESHOLD)
    (map-set proposals pid
      { proposer: tx-sender, title: title, description: description,
        votes-for: u0, votes-against: u0,
        start-block: block-height, end-block: (+ block-height VOTING-PERIOD),
        executed: false, canceled: false })
    (var-set proposal-count pid)
    (ok pid)))

(define-public (vote (proposal-id uint) (support bool))
  (let ((proposal (unwrap! (map-get? proposals proposal-id) ERR-NOT-FOUND))
        (power (default-to u0 (map-get? member-power tx-sender))))
    (asserts! (<= block-height (get end-block proposal)) ERR-VOTING-CLOSED)
    (asserts! (is-none (map-get? votes { proposal-id: proposal-id, voter: tx-sender })) ERR-ALREADY-VOTED)
    (map-set votes { proposal-id: proposal-id, voter: tx-sender } support)
    (if support
      (map-set proposals proposal-id (merge proposal { votes-for: (+ (get votes-for proposal) power) }))
      (map-set proposals proposal-id (merge proposal { votes-against: (+ (get votes-against proposal) power) })))
    (ok true)))

(define-public (execute-proposal (proposal-id uint))
  (let ((proposal (unwrap! (map-get? proposals proposal-id) ERR-NOT-FOUND)))
    (asserts! (> block-height (get end-block proposal)) ERR-VOTING-OPEN)
    (asserts! (not (get executed proposal)) (err u107))
    (asserts! (> (get votes-for proposal) (get votes-against proposal)) ERR-QUORUM-NOT-MET)
    (map-set proposals proposal-id (merge proposal { executed: true }))
    (ok true)))

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

Functions (8)

FunctionAccessArgs
register-memberpublicpower: uint
create-proposalpublictitle: (string-ascii 64
votepublicproposal-id: uint, support: bool
execute-proposalpublicproposal-id: uint
get-proposalread-onlyproposal-id: uint
get-voteread-onlyproposal-id: uint, voter: principal
get-member-powerread-onlymember: principal
get-proposal-countread-only