Source Code

(define-constant contract-owner tx-sender)
(define-constant err-owner-only (err u100))
(define-constant err-not-found (err u101))
(define-constant err-unauthorized (err u102))
(define-constant err-invalid-params (err u103))
(define-constant err-order-filled (err u104))

(define-map orders
  {order-id: uint}
  {
    seller: principal,
    variety: (string-ascii 64),
    quantity: uint,
    price-per-unit: uint,
    min-quantity: uint,
    status: (string-ascii 16),
    created-at: uint,
    expires-at: uint
  }
)

(define-map trades
  {trade-id: uint}
  {
    order-id: uint,
    buyer: principal,
    quantity: uint,
    price: uint,
    settled: bool,
    timestamp: uint
  }
)

(define-data-var order-nonce uint u0)
(define-data-var trade-nonce uint u0)

(define-read-only (get-order (order-id uint))
  (map-get? orders {order-id: order-id})
)

(define-read-only (get-trade (trade-id uint))
  (map-get? trades {trade-id: trade-id})
)

(define-public (create-order
  (variety (string-ascii 64))
  (quantity uint)
  (price-per-unit uint)
  (min-quantity uint)
  (duration uint)
)
  (let ((order-id (var-get order-nonce)))
    (asserts! (> quantity u0) err-invalid-params)
    (asserts! (> price-per-unit u0) err-invalid-params)
    (asserts! (<= min-quantity quantity) err-invalid-params)
    (map-set orders {order-id: order-id}
      {
        seller: tx-sender,
        variety: variety,
        quantity: quantity,
        price-per-unit: price-per-unit,
        min-quantity: min-quantity,
        status: "active",
        created-at: stacks-block-height,
        expires-at: (+ stacks-block-height duration)
      }
    )
    (var-set order-nonce (+ order-id u1))
    (ok order-id)
  )
)

(define-public (accept-order (order-id uint) (quantity uint))
  (let (
    (order (unwrap! (map-get? orders {order-id: order-id}) err-not-found))
    (trade-id (var-get trade-nonce))
  )
    (asserts! (is-eq (get status order) "active") err-order-filled)
    (asserts! (< stacks-block-height (get expires-at order)) err-invalid-params)
    (asserts! (>= quantity (get min-quantity order)) err-invalid-params)
    (asserts! (<= quantity (get quantity order)) err-invalid-params)
    (map-set trades {trade-id: trade-id}
      {
        order-id: order-id,
        buyer: tx-sender,
        quantity: quantity,
        price: (* quantity (get price-per-unit order)),
        settled: false,
        timestamp: stacks-block-height
      }
    )
    (if (is-eq quantity (get quantity order))
      (map-set orders {order-id: order-id}
        (merge order {status: "filled"})
      )
      (map-set orders {order-id: order-id}
        (merge order {quantity: (- (get quantity order) quantity)})
      )
    )
    (var-set trade-nonce (+ trade-id u1))
    (ok trade-id)
  )
)

(define-public (settle-trade (trade-id uint))
  (let ((trade (unwrap! (map-get? trades {trade-id: trade-id}) err-not-found)))
    (asserts! (is-eq tx-sender (get buyer trade)) err-unauthorized)
    (ok (map-set trades {trade-id: trade-id}
      (merge trade {settled: true})
    ))
  )
)

(define-public (cancel-order (order-id uint))
  (let ((order (unwrap! (map-get? orders {order-id: order-id}) err-not-found)))
    (asserts! (is-eq tx-sender (get seller order)) err-unauthorized)
    (asserts! (is-eq (get status order) "active") err-invalid-params)
    (ok (map-set orders {order-id: order-id}
      (merge order {status: "cancelled"})
    ))
  )
)

Functions (6)

FunctionAccessArgs
get-orderread-onlyorder-id: uint
get-traderead-onlytrade-id: uint
create-orderpublicvariety: (string-ascii 64
accept-orderpublicorder-id: uint, quantity: uint
settle-tradepublictrade-id: uint
cancel-orderpublicorder-id: uint