Source Code

;; TradeMint - Decentralized Trading Platform
;; A platform for trading digital assets with secure escrow capabilities

;; Constants
(define-constant contract-owner tx-sender)
(define-constant err-not-authorized (err u100))
(define-constant err-listing-not-found (err u101))
(define-constant err-invalid-status (err u102))
(define-constant err-insufficient-balance (err u103))
(define-constant err-no-active-offer (err u104))
(define-constant err-listing-expired (err u105))
(define-constant err-invalid-amount (err u106))
(define-constant err-offer-not-found (err u107))
(define-constant err-listing-closed (err u108))
(define-constant err-already-has-offer (err u109))

;; Data Variables
(define-map listings
    uint
    {
        seller: principal,
        asset: (string-ascii 32),
        price: uint,
        status: (string-ascii 10),
        expiry: uint,
        created-at: uint
    }
)

(define-map offers
    {listing-id: uint, buyer: principal}
    {
        amount: uint,
        status: (string-ascii 10),
        created-at: uint
    }
)

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

;; Events
(define-data-var event-id uint u0)

(define-private (emit-event (event-type (string-ascii 20)) (listing-id uint) (principal-data (optional principal)))
    (begin
        (var-set event-id (+ (var-get event-id) u1))
        (print {event-id: (var-get event-id), event-type: event-type, listing-id: listing-id, principal: principal-data})
    )
)

;; Private Functions
(define-private (increment-nonce)
    (begin
        (var-set listing-nonce (+ (var-get listing-nonce) u1))
        (ok (var-get listing-nonce))
    )
)


(define-private (is-listing-active (listing {seller: principal, asset: (string-ascii 32), price: uint, status: (string-ascii 10), expiry: uint, created-at: uint}))
    (and
        (is-eq (get status listing) "active")
        (< stacks-block-time (get expiry listing))
    )
)


;; Public Functions  
(define-public (create-listing (asset (string-ascii 32)) (price uint) (expiry uint))
    (let
        (
            (current-block stacks-block-time)
            (new-id (var-get listing-nonce))
        )
        ;; Increment the nonce first
        (var-set listing-nonce (+ new-id u1))
        
        ;; Validate parameters
        (asserts! (> expiry current-block) (err err-invalid-status))
        (asserts! (> price u0) (err err-invalid-amount))
        
        ;; Create the listing
        (map-insert listings
            new-id
            {
                seller: tx-sender,
                asset: asset,
                price: price,
                status: "active",
                expiry: expiry,
                created-at: current-block
            }
        )
        (emit-event "listing-created" new-id none)
        (ok new-id)
    )
)


(define-public (cancel-listing (listing-id uint))
    (let
        (
            (listing (unwrap! (map-get? listings listing-id) (err err-listing-not-found)))
        )
        (asserts! (is-eq (get seller listing) tx-sender) (err err-not-authorized))
        (asserts! (is-eq (get status listing) "active") (err err-invalid-status))
        
        (map-set listings listing-id
            (merge listing {status: "cancelled"})
        )
        (emit-event "listing-cancelled" listing-id none)
        (ok true)
    )
)



;; Admin function to recover expired listings and refund related offers
(define-public (cleanup-expired-listing (listing-id uint))
    (let
        (
            (listing (unwrap! (map-get? listings listing-id) (err err-listing-not-found)))
        )
        ;; Verify listing is expired and still active
        (asserts! (and (>= stacks-block-time (get expiry listing))
                      (is-eq (get status listing) "active"))
                 (err err-invalid-status))
        
        ;; Mark listing as expired
        (map-set listings
            listing-id
            (merge listing {status: "expired"})
        )
        
        (emit-event "listing-expired" listing-id none)
        (ok true)
    )
)

;; Read-only functions
(define-read-only (get-listing (listing-id uint))
    (map-get? listings listing-id)
)

(define-read-only (get-offer (listing-id uint) (buyer principal))
    (map-get? offers {listing-id: listing-id, buyer: buyer})
)

(define-read-only (get-listing-count)
    (var-get listing-nonce)
)

(define-read-only (is-expired (listing-id uint))
    (match (map-get? listings listing-id)
        listing (>= stacks-block-time (get expiry listing))
        false
    )
)

Functions (9)

FunctionAccessArgs
emit-eventprivateevent-type: (string-ascii 20
increment-nonceprivate
create-listingpublicasset: (string-ascii 32
cancel-listingpubliclisting-id: uint
cleanup-expired-listingpubliclisting-id: uint
get-listingread-onlylisting-id: uint
get-offerread-onlylisting-id: uint, buyer: principal
get-listing-countread-only
is-expiredread-onlylisting-id: uint