Source Code

;; Craft Market Contract
;; Artisan crafts marketplace
;; Halal - honest trade of handcrafts
;; 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-SOLD-OUT (err u405))
(define-constant MARKET-FEE-PCT u3)

(define-data-var product-count uint u0)
(define-data-var order-count uint u0)
(define-data-var total-sales uint u0)

(define-map artisans principal { name: (string-utf8 100), craft-type: (string-utf8 50), products: uint, sales: uint, earned: uint })
(define-map products uint { artisan: principal, name: (string-utf8 100), description: (string-utf8 200), price: uint, stock: uint, sold: uint, active: bool })
(define-map orders uint { product-id: uint, buyer: principal, quantity: uint, total: uint, status: (string-ascii 20), block: uint })

(define-public (register-artisan (name (string-utf8 100)) (craft-type (string-utf8 50)))
  (begin (map-set artisans tx-sender { name: name, craft-type: craft-type, products: u0, sales: u0, earned: u0 }) (ok true)))

(define-public (list-product (name (string-utf8 100)) (description (string-utf8 200)) (price uint) (stock uint))
  (let (
    (id (+ (var-get product-count) u1))
    (a (unwrap! (map-get? artisans tx-sender) ERR-NOT-AUTHORIZED))
  )
    (map-set products id { artisan: tx-sender, name: name, description: description, price: price, stock: stock, sold: u0, active: true })
    (map-set artisans tx-sender (merge a { products: (+ (get products a) u1) }))
    (var-set product-count id) (ok id)))

(define-public (buy-product (product-id uint) (quantity uint))
  (let (
    (p (unwrap! (map-get? products product-id) ERR-NOT-FOUND))
    (total (* quantity (get price p)))
    (fee (/ (* total MARKET-FEE-PCT) u100))
    (artisan-pay (- total fee))
    (oid (+ (var-get order-count) u1))
    (a (unwrap! (map-get? artisans (get artisan p)) ERR-NOT-FOUND))
  )
    (asserts! (get active p) ERR-NOT-FOUND)
    (asserts! (>= (get stock p) quantity) ERR-SOLD-OUT)
    (try! (stx-transfer? artisan-pay tx-sender (get artisan p)))
    (try! (stx-transfer? fee tx-sender CONTRACT-OWNER))
    (map-set orders oid { product-id: product-id, buyer: tx-sender, quantity: quantity, total: total, status: "ordered", block: stacks-block-height })
    (map-set products product-id (merge p { stock: (- (get stock p) quantity), sold: (+ (get sold p) quantity) }))
    (map-set artisans (get artisan p) (merge a { sales: (+ (get sales a) u1), earned: (+ (get earned a) artisan-pay) }))
    (var-set order-count oid)
    (var-set total-sales (+ (var-get total-sales) total)) (ok oid)))

(define-public (fulfill-order (order-id uint))
  (let (
    (o (unwrap! (map-get? orders order-id) ERR-NOT-FOUND))
    (p (unwrap! (map-get? products (get product-id o)) ERR-NOT-FOUND))
  )
    (asserts! (is-eq tx-sender (get artisan p)) ERR-NOT-AUTHORIZED)
    (map-set orders order-id (merge o { status: "shipped" })) (ok true)))

(define-read-only (get-artisan (who principal)) (map-get? artisans who))
(define-read-only (get-product (id uint)) (map-get? products id))
(define-read-only (get-order (id uint)) (map-get? orders id))
(define-read-only (get-product-count) (ok (var-get product-count)))
(define-read-only (get-total-sales) (ok (var-get total-sales)))

Functions (9)

FunctionAccessArgs
register-artisanpublicname: (string-utf8 100
list-productpublicname: (string-utf8 100
buy-productpublicproduct-id: uint, quantity: uint
fulfill-orderpublicorder-id: uint
get-artisanread-onlywho: principal
get-productread-onlyid: uint
get-orderread-onlyid: uint
get-product-countread-only
get-total-salesread-only