Source Code

;; Bounty Board Contract
;; Post and complete bounties/tasks for rewards
;; Halal - fair work compensation
;; 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-DONE (err u405))
(define-constant ERR-SELF-CLAIM (err u406))

(define-data-var bounty-count uint u0)
(define-data-var total-paid uint u0)

(define-map bounties uint {
  creator: principal, title: (string-utf8 100), reward: uint,
  status: (string-ascii 20), hunter: (optional principal), created: uint
})

(define-public (create-bounty (title (string-utf8 100)) (reward uint))
  (let ((id (+ (var-get bounty-count) u1)))
    (map-set bounties id { creator: tx-sender, title: title, reward: reward, status: "open", hunter: none, created: stacks-block-height })
    (var-set bounty-count id) (ok id)))

(define-public (claim-bounty (id uint))
  (let ((bounty (unwrap! (map-get? bounties id) ERR-NOT-FOUND)))
    (asserts! (is-eq (get status bounty) "open") ERR-ALREADY-DONE)
    (asserts! (not (is-eq tx-sender (get creator bounty))) ERR-SELF-CLAIM)
    (map-set bounties id (merge bounty { status: "claimed", hunter: (some tx-sender) })) (ok true)))

(define-public (approve-bounty (id uint))
  (let ((bounty (unwrap! (map-get? bounties id) ERR-NOT-FOUND)))
    (asserts! (is-eq tx-sender (get creator bounty)) ERR-NOT-AUTHORIZED)
    (asserts! (is-eq (get status bounty) "claimed") ERR-ALREADY-DONE)
    (match (get hunter bounty) h
      (begin
        (try! (stx-transfer? (get reward bounty) tx-sender h))
        (map-set bounties id (merge bounty { status: "completed" }))
        (var-set total-paid (+ (var-get total-paid) (get reward bounty)))
        (ok true))
      ERR-NOT-FOUND)))

(define-public (cancel-bounty (id uint))
  (let ((bounty (unwrap! (map-get? bounties id) ERR-NOT-FOUND)))
    (asserts! (is-eq tx-sender (get creator bounty)) ERR-NOT-AUTHORIZED)
    (asserts! (is-eq (get status bounty) "open") ERR-ALREADY-DONE)
    (map-set bounties id (merge bounty { status: "cancelled" })) (ok true)))

(define-read-only (get-bounty (id uint)) (map-get? bounties id))
(define-read-only (get-bounty-count) (ok (var-get bounty-count)))
(define-read-only (get-total-paid) (ok (var-get total-paid)))

Functions (7)

FunctionAccessArgs
create-bountypublictitle: (string-utf8 100
claim-bountypublicid: uint
approve-bountypublicid: uint
cancel-bountypublicid: uint
get-bountyread-onlyid: uint
get-bounty-countread-only
get-total-paidread-only