Source Code

;; Voting Delegate Contract
;; Delegate voting power to representatives
;; Halal - shura (consultation) with delegation
;; Clarity 4 compatible

(define-constant CONTRACT-OWNER tx-sender)
(define-constant ERR-NOT-AUTHORIZED (err u401))
(define-constant ERR-NOT-FOUND (err u404))
(define-constant ERR-ALREADY-VOTED (err u405))
(define-constant ERR-SELF-DELEGATE (err u406))

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

(define-map delegation principal principal)
(define-map voting-power principal uint)
(define-map proposals uint { title: (string-utf8 100), creator: principal, yes-power: uint, no-power: uint, end-block: uint, status: (string-ascii 20) })
(define-map proposal-votes { proposal-id: uint, voter: principal } bool)

(define-public (register-voter (power uint))
  (begin
    (map-set voting-power tx-sender power) (ok true)))

(define-public (delegate-to (delegate principal))
  (let ((my-power (default-to u0 (map-get? voting-power tx-sender))))
    (asserts! (not (is-eq tx-sender delegate)) ERR-SELF-DELEGATE)
    (map-set delegation tx-sender delegate)
    (map-set voting-power delegate (+ (default-to u0 (map-get? voting-power delegate)) my-power))
    (map-set voting-power tx-sender u0)
    (ok true)))

(define-public (revoke-delegation)
  (let (
    (delegate (unwrap! (map-get? delegation tx-sender) ERR-NOT-FOUND))
    (my-power (default-to u1 (map-get? voting-power tx-sender)))
  )
    (map-delete delegation tx-sender)
    (map-set voting-power tx-sender my-power)
    (ok true)))

(define-public (create-proposal (title (string-utf8 100)) (duration uint))
  (let ((id (+ (var-get proposal-count) u1)))
    (map-set proposals id { title: title, creator: tx-sender, yes-power: u0, no-power: u0, end-block: (+ stacks-block-height duration), status: "active" })
    (var-set proposal-count id) (ok id)))

(define-public (cast-vote (proposal-id uint) (support bool))
  (let (
    (proposal (unwrap! (map-get? proposals proposal-id) ERR-NOT-FOUND))
    (power (default-to u1 (map-get? voting-power tx-sender)))
  )
    (asserts! (< stacks-block-height (get end-block proposal)) ERR-NOT-FOUND)
    (asserts! (is-none (map-get? proposal-votes { proposal-id: proposal-id, voter: tx-sender })) ERR-ALREADY-VOTED)
    (map-set proposal-votes { proposal-id: proposal-id, voter: tx-sender } true)
    (if support
      (map-set proposals proposal-id (merge proposal { yes-power: (+ (get yes-power proposal) power) }))
      (map-set proposals proposal-id (merge proposal { no-power: (+ (get no-power proposal) power) })))
    (ok power)))

(define-read-only (get-proposal (id uint)) (map-get? proposals id))
(define-read-only (get-power (who principal)) (ok (default-to u0 (map-get? voting-power who))))
(define-read-only (get-delegate (who principal)) (map-get? delegation who))
(define-read-only (get-proposal-count) (ok (var-get proposal-count)))
(define-read-only (has-voted (proposal-id uint) (voter principal)) (ok (is-some (map-get? proposal-votes { proposal-id: proposal-id, voter: voter }))))

Functions (10)

FunctionAccessArgs
register-voterpublicpower: uint
delegate-topublicdelegate: principal
revoke-delegationpublic
create-proposalpublictitle: (string-utf8 100
cast-votepublicproposal-id: uint, support: bool
get-proposalread-onlyid: uint
get-powerread-onlywho: principal
get-delegateread-onlywho: principal
get-proposal-countread-only
has-votedread-onlyproposal-id: uint, voter: principal