Source Code

;; DEX Order Book Contract
;; Limit orders for token trading

(define-constant err-insufficient-balance (err u100))
(define-constant err-order-not-found (err u101))
(define-constant err-not-owner (err u102))
(define-constant err-order-filled (err u103))

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

(define-map orders
    uint
    {
        maker: principal,
        sell-amount: uint,
        buy-amount: uint,
        filled-amount: uint,
        price: uint,
        is-buy: bool,
        active: bool,
        timestamp: uint
    }
)

(define-public (create-limit-order
    (sell-amount uint)
    (buy-amount uint)
    (is-buy bool))
    (let
        (
            (order-id (var-get order-nonce))
            (price (/ (* buy-amount u1000000) sell-amount))
        )
        (try! (stx-transfer? sell-amount tx-sender (as-contract tx-sender)))
        
        (map-set orders order-id {
            maker: tx-sender,
            sell-amount: sell-amount,
            buy-amount: buy-amount,
            filled-amount: u0,
            price: price,
            is-buy: is-buy,
            active: true,
            timestamp: block-height
        })
        (var-set order-nonce (+ order-id u1))
        (ok order-id)
    )
)

(define-public (fill-order (order-id uint) (fill-amount uint))
    (let
        (
            (order (unwrap! (map-get? orders order-id) err-order-not-found))
            (remaining-amount (- (get sell-amount order) (get filled-amount order)))
            (amount-to-fill (if (> fill-amount remaining-amount) remaining-amount fill-amount))
            (buy-amount-required (/ (* amount-to-fill (get buy-amount order)) (get sell-amount order)))
        )
        (asserts! (get active order) err-order-filled)
        (asserts! (> remaining-amount u0) err-order-filled)
        
        (try! (stx-transfer? buy-amount-required tx-sender (get maker order)))
        (try! (as-contract (stx-transfer? amount-to-fill tx-sender tx-sender)))
        
        (let ((new-filled-amount (+ (get filled-amount order) amount-to-fill)))
            (map-set orders order-id (merge order {
                filled-amount: new-filled-amount,
                active: (< new-filled-amount (get sell-amount order))
            }))
        )
        (ok amount-to-fill)
    )
)

(define-public (cancel-order (order-id uint))
    (let
        (
            (order (unwrap! (map-get? orders order-id) err-order-not-found))
            (remaining-amount (- (get sell-amount order) (get filled-amount order)))
        )
        (asserts! (is-eq tx-sender (get maker order)) err-not-owner)
        (asserts! (get active order) err-order-filled)
        
        (if (> remaining-amount u0)
            (try! (as-contract (stx-transfer? remaining-amount tx-sender (get maker order))))
            true
        )
        
        (map-set orders order-id (merge order {active: false}))
        (ok remaining-amount)
    )
)

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

(define-read-only (get-remaining-amount (order-id uint))
    (match (map-get? orders order-id)
        order (- (get sell-amount order) (get filled-amount order))
        u0
    )
)

(define-read-only (is-order-active (order-id uint))
    (match (map-get? orders order-id)
        order (get active order)
        false
    )
)

Functions (6)

FunctionAccessArgs
create-limit-orderpublicsell-amount: uint, buy-amount: uint, is-buy: bool
fill-orderpublicorder-id: uint, fill-amount: uint
cancel-orderpublicorder-id: uint
get-orderread-onlyorder-id: uint
get-remaining-amountread-onlyorder-id: uint
is-order-activeread-onlyorder-id: uint