Source Code

;; Salam Forward Contract
;; Islamic forward sale - pay now, deliver later
;; Halal - salam (advance payment for future goods)
;; 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-DELIVERED (err u405))
(define-constant ERR-NOT-DUE (err u406))

(define-data-var contract-count uint u0)
(define-data-var total-volume uint u0)

(define-map salam-contracts uint {
  buyer: principal, seller: principal, commodity: (string-utf8 100),
  quantity: uint, price: uint, delivery-block: uint,
  delivered: bool, status: (string-ascii 20), created: uint
})
(define-map seller-contracts principal uint)

(define-public (create-salam (seller principal) (commodity (string-utf8 100)) (quantity uint) (price uint) (delivery-blocks uint))
  (let ((id (+ (var-get contract-count) u1)))
    (try! (stx-transfer? price tx-sender seller))
    (map-set salam-contracts id {
      buyer: tx-sender, seller: seller, commodity: commodity,
      quantity: quantity, price: price, delivery-block: (+ stacks-block-height delivery-blocks),
      delivered: false, status: "active", created: stacks-block-height
    })
    (map-set seller-contracts seller (+ (default-to u0 (map-get? seller-contracts seller)) u1))
    (var-set contract-count id)
    (var-set total-volume (+ (var-get total-volume) price))
    (print { event: "salam-created", id: id, buyer: tx-sender, seller: seller, commodity: commodity })
    (ok id)))

(define-public (confirm-delivery (contract-id uint))
  (let ((sc (unwrap! (map-get? salam-contracts contract-id) ERR-NOT-FOUND)))
    (asserts! (is-eq tx-sender (get buyer sc)) ERR-NOT-AUTHORIZED)
    (asserts! (not (get delivered sc)) ERR-ALREADY-DELIVERED)
    (map-set salam-contracts contract-id (merge sc { delivered: true, status: "completed" }))
    (print { event: "salam-delivered", id: contract-id })
    (ok true)))

(define-public (dispute-contract (contract-id uint))
  (let ((sc (unwrap! (map-get? salam-contracts contract-id) ERR-NOT-FOUND)))
    (asserts! (is-eq tx-sender (get buyer sc)) ERR-NOT-AUTHORIZED)
    (asserts! (> stacks-block-height (get delivery-block sc)) ERR-NOT-DUE)
    (asserts! (not (get delivered sc)) ERR-ALREADY-DELIVERED)
    (map-set salam-contracts contract-id (merge sc { status: "disputed" }))
    (ok true)))

(define-public (resolve-dispute (contract-id uint) (refund bool))
  (let ((sc (unwrap! (map-get? salam-contracts contract-id) ERR-NOT-FOUND)))
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (if refund
      (begin (try! (stx-transfer? (get price sc) (get seller sc) (get buyer sc)))
        (map-set salam-contracts contract-id (merge sc { status: "refunded" })))
      (map-set salam-contracts contract-id (merge sc { status: "resolved" })))
    (ok true)))

(define-read-only (get-contract (id uint)) (map-get? salam-contracts id))
(define-read-only (get-contract-count) (ok (var-get contract-count)))
(define-read-only (get-total-volume) (ok (var-get total-volume)))
(define-read-only (is-overdue (id uint))
  (match (map-get? salam-contracts id) sc (ok (and (not (get delivered sc)) (> stacks-block-height (get delivery-block sc)))) (ok false)))

Functions (8)

FunctionAccessArgs
create-salampublicseller: principal, commodity: (string-utf8 100
confirm-deliverypubliccontract-id: uint
dispute-contractpubliccontract-id: uint
resolve-disputepubliccontract-id: uint, refund: bool
get-contractread-onlyid: uint
get-contract-countread-only
get-total-volumeread-only
is-overdueread-onlyid: uint