Source Code

;; Charity Auction Contract
;; Auction items for charitable causes
;; Halal - transparent charity auctions
;; 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-BID-TOO-LOW (err u405))
(define-constant ERR-ENDED (err u406))

(define-data-var auction-count uint u0)
(define-data-var total-charity uint u0)

(define-map auctions uint {
  seller: principal, item: (string-utf8 100), beneficiary: principal,
  min-bid: uint, highest-bid: uint, highest-bidder: (optional principal),
  end-block: uint, settled: bool, charity-pct: uint
})
(define-map bid-history { auction-id: uint, index: uint } { bidder: principal, amount: uint, block: uint })
(define-map bid-count uint uint)

(define-public (create-auction (item (string-utf8 100)) (beneficiary principal) (min-bid uint) (duration uint) (charity-pct uint))
  (let ((id (+ (var-get auction-count) u1)))
    (map-set auctions id { seller: tx-sender, item: item, beneficiary: beneficiary, min-bid: min-bid, highest-bid: u0, highest-bidder: none, end-block: (+ stacks-block-height duration), settled: false, charity-pct: charity-pct })
    (var-set auction-count id) (ok id)))

(define-public (place-bid (auction-id uint) (amount uint))
  (let (
    (auction (unwrap! (map-get? auctions auction-id) ERR-NOT-FOUND))
    (idx (default-to u0 (map-get? bid-count auction-id)))
  )
    (asserts! (< stacks-block-height (get end-block auction)) ERR-ENDED)
    (asserts! (> amount (get highest-bid auction)) ERR-BID-TOO-LOW)
    (asserts! (>= amount (get min-bid auction)) ERR-BID-TOO-LOW)
    (try! (stx-transfer? amount tx-sender CONTRACT-OWNER))
    ;; Refund previous highest bidder
    (match (get highest-bidder auction)
      prev-bidder (try! (stx-transfer? (get highest-bid auction) CONTRACT-OWNER prev-bidder))
      true)
    (map-set bid-history { auction-id: auction-id, index: idx } { bidder: tx-sender, amount: amount, block: stacks-block-height })
    (map-set bid-count auction-id (+ idx u1))
    (map-set auctions auction-id (merge auction { highest-bid: amount, highest-bidder: (some tx-sender) }))
    (ok amount)))

(define-public (settle-auction (auction-id uint))
  (let (
    (auction (unwrap! (map-get? auctions auction-id) ERR-NOT-FOUND))
    (charity-amount (/ (* (get highest-bid auction) (get charity-pct auction)) u100))
    (seller-amount (- (get highest-bid auction) charity-amount))
  )
    (asserts! (>= stacks-block-height (get end-block auction)) ERR-NOT-FOUND)
    (asserts! (not (get settled auction)) ERR-ENDED)
    (if (> charity-amount u0) (try! (stx-transfer? charity-amount CONTRACT-OWNER (get beneficiary auction))) true)
    (if (> seller-amount u0) (try! (stx-transfer? seller-amount CONTRACT-OWNER (get seller auction))) true)
    (map-set auctions auction-id (merge auction { settled: true }))
    (var-set total-charity (+ (var-get total-charity) charity-amount))
    (ok charity-amount)))

(define-read-only (get-auction (id uint)) (map-get? auctions id))
(define-read-only (get-bid (auction-id uint) (index uint)) (map-get? bid-history { auction-id: auction-id, index: index }))
(define-read-only (get-auction-count) (ok (var-get auction-count)))
(define-read-only (get-total-charity) (ok (var-get total-charity)))

Functions (7)

FunctionAccessArgs
create-auctionpublicitem: (string-utf8 100
place-bidpublicauction-id: uint, amount: uint
settle-auctionpublicauction-id: uint
get-auctionread-onlyid: uint
get-bidread-onlyauction-id: uint, index: uint
get-auction-countread-only
get-total-charityread-only