Source Code

;; NFT Marketplace - SIP-009 compliant trading with royalties
;; Built for Stacks Builder Challenge by Marcus David

(define-constant contract-owner tx-sender)
(define-constant err-not-found (err u101))
(define-constant err-unauthorized (err u102))
(define-constant err-listing-exists (err u103))
(define-constant err-insufficient-payment (err u104))

(define-data-var platform-fee-rate uint u250) ;; 2.5%
(define-data-var next-listing-id uint u1)

(define-map listings
  uint
  {
    seller: principal,
    nft-contract: principal,
    token-id: uint,
    price: uint,
    royalty-percent: uint,
    creator: principal,
    active: bool
  }
)

(define-map nft-listings { nft-contract: principal, token-id: uint } uint)

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

(define-public (list-nft 
    (nft-contract principal)
    (token-id uint)
    (price uint)
    (royalty-percent uint)
    (creator principal))
  (let ((listing-id (var-get next-listing-id)))
    (asserts! (<= royalty-percent u1000) err-unauthorized)
    (map-set listings listing-id {
      seller: tx-sender,
      nft-contract: nft-contract,
      token-id: token-id,
      price: price,
      royalty-percent: royalty-percent,
      creator: creator,
      active: true
    })
    (map-set nft-listings { nft-contract: nft-contract, token-id: token-id } listing-id)
    (var-set next-listing-id (+ listing-id u1))
    (ok listing-id)
  )
)

(define-public (buy-nft (listing-id uint))
  (match (map-get? listings listing-id)
    listing
      (let
        (
          (platform-fee (/ (* (get price listing) (var-get platform-fee-rate)) u10000))
          (royalty (/ (* (get price listing) (get royalty-percent listing)) u10000))
          (seller-amount (- (- (get price listing) platform-fee) royalty))
        )
        (asserts! (get active listing) err-not-found)
        (try! (stx-transfer-memo? (get price listing) tx-sender (as-contract tx-sender) 0x6e6674207075726368617365))
        (try! (as-contract (stx-transfer-memo? seller-amount tx-sender (get seller listing) 0x73656c6c6572207061796d656e74)))
        (try! (as-contract (stx-transfer-memo? royalty tx-sender (get creator listing) 0x63726561746f7220726f79616c7479)))
        (try! (as-contract (stx-transfer-memo? platform-fee tx-sender contract-owner 0x706c6174666f726d20666565)))
        (map-set listings listing-id (merge listing { active: false }))
        (ok true)
      )
    err-not-found
  )
)

(define-public (cancel-listing (listing-id uint))
  (match (map-get? listings listing-id)
    listing
      (begin
        (asserts! (is-eq tx-sender (get seller listing)) err-unauthorized)
        (map-set listings listing-id (merge listing { active: false }))
        (ok true)
      )
    err-not-found
  )
)

Functions (4)

FunctionAccessArgs
get-listingread-onlylisting-id: uint
list-nftpublicnft-contract: principal, token-id: uint, price: uint, royalty-percent: uint, creator: principal
buy-nftpubliclisting-id: uint
cancel-listingpubliclisting-id: uint