Source Code

(define-non-fungible-token drn-nft uint)

(define-constant ERR-NOT-AUTHORIZED (err u100))
(define-constant ERR-NOT-FOUND (err u101))
(define-constant ERR-LISTING-EXISTS (err u102))
(define-constant ERR-NOT-LISTED (err u103))
(define-constant ERR-EXPIRED (err u104))
(define-constant ERR-PRICE-MISMATCH (err u105))
(define-constant ERR-TOKEN-MISMATCH (err u106))
(define-constant ERR-INVALID-PAYMENT (err u107))

(define-data-var token-id-nonce uint u0)
(define-data-var royalty-address principal tx-sender)
(define-data-var royalty-percent uint u250)

(define-map token-uri uint (string-ascii 256))
(define-map listings uint {
  price: uint,
  expires: uint,
  token: (optional principal),
  benchmark: uint
})
(define-map historical-price uint uint)

(define-read-only (get-last-token-id)
  (ok (var-get token-id-nonce))
)

(define-read-only (get-token-uri (token uint))
  (ok (map-get? token-uri token))
)

(define-read-only (get-owner (token uint))
  (ok (nft-get-owner? drn-nft token))
)

(define-read-only (get-listing (token uint))
  (ok (map-get? listings token))
)

(define-read-only (get-royalty-info (token uint) (sale-price uint))
  (let (
    (hist-price (default-to u0 (map-get? historical-price token)))
    (taxable (if (> sale-price hist-price) (- sale-price hist-price) u0))
    (royalty (/ (* taxable (var-get royalty-percent)) u10000))
  )
    (ok {recipient: (var-get royalty-address), amount: royalty})
  )
)

(define-public (mint (recipient principal) (uri (string-ascii 256)))
  (let ((new-id (+ (var-get token-id-nonce) u1)))
    (try! (nft-mint? drn-nft new-id recipient))
    (map-set token-uri new-id uri)
    (var-set token-id-nonce new-id)
    (ok new-id)
  )
)

(define-public (transfer (token uint) (sender principal) (recipient principal))
  (let ((owner (unwrap! (nft-get-owner? drn-nft token) ERR-NOT-FOUND)))
    (asserts! (or (is-eq tx-sender owner) (is-eq tx-sender sender)) ERR-NOT-AUTHORIZED)
    (try! (nft-transfer? drn-nft token sender recipient))
    (ok true)
  )
)

(define-public (list-item (token uint) (price uint) (expires uint) (payment-token (optional principal)))
  (let ((owner (unwrap! (nft-get-owner? drn-nft token) ERR-NOT-FOUND)))
    (asserts! (is-eq tx-sender owner) ERR-NOT-AUTHORIZED)
    (asserts! (> price u0) ERR-INVALID-PAYMENT)
    (asserts! (> expires stacks-block-time) ERR-EXPIRED)
    (map-set listings token {
      price: price,
      expires: expires,
      token: payment-token,
      benchmark: (default-to u0 (map-get? historical-price token))
    })
    (ok true)
  )
)

(define-public (delist-item (token uint))
  (let ((owner (unwrap! (nft-get-owner? drn-nft token) ERR-NOT-FOUND)))
    (asserts! (is-eq tx-sender owner) ERR-NOT-AUTHORIZED)
    (asserts! (is-some (map-get? listings token)) ERR-NOT-LISTED)
    (map-delete listings token)
    (ok true)
  )
)

(define-public (buy-item (token uint) (price uint) (payment-token (optional principal)))
  (let (
    (listing (unwrap! (map-get? listings token) ERR-NOT-LISTED))
    (seller (unwrap! (nft-get-owner? drn-nft token) ERR-NOT-FOUND))
    (royalty-info (unwrap! (get-royalty-info token price) ERR-NOT-FOUND))
  )
    (asserts! (is-eq price (get price listing)) ERR-PRICE-MISMATCH)
    (asserts! (is-eq payment-token (get token listing)) ERR-TOKEN-MISMATCH)
    (asserts! (< stacks-block-time (get expires listing)) ERR-EXPIRED)
    (if (is-some payment-token)
      (begin
        (try! (stx-transfer? (get amount royalty-info) tx-sender (get recipient royalty-info)))
        (try! (stx-transfer? (- price (get amount royalty-info)) tx-sender seller))
      )
      (begin
        (try! (stx-transfer? (get amount royalty-info) tx-sender (get recipient royalty-info)))
        (try! (stx-transfer? (- price (get amount royalty-info)) tx-sender seller))
      )
    )
    (try! (nft-transfer? drn-nft token seller tx-sender))
    (map-set historical-price token price)
    (map-delete listings token)
    (ok true)
  )
)

(define-public (set-royalty (recipient principal) (percent uint))
  (begin
    (asserts! (is-eq tx-sender (var-get royalty-address)) ERR-NOT-AUTHORIZED)
    (var-set royalty-address recipient)
    (var-set royalty-percent percent)
    (ok true)
  )
)

Functions (11)

FunctionAccessArgs
get-last-token-idread-only
get-token-uriread-onlytoken: uint
get-ownerread-onlytoken: uint
get-listingread-onlytoken: uint
get-royalty-inforead-onlytoken: uint, sale-price: uint
mintpublicrecipient: principal, uri: (string-ascii 256
transferpublictoken: uint, sender: principal, recipient: principal
list-itempublictoken: uint, price: uint, expires: uint, payment-token: (optional principal
delist-itempublictoken: uint
buy-itempublictoken: uint, price: uint, payment-token: (optional principal
set-royaltypublicrecipient: principal, percent: uint