Source Code

;; SIP-009 Non-Fungible Token Implementation
;; NFT contract for the Stacks blockchain
;; Built by rajuice for Stacks Builder Rewards

;; Define the NFT
(define-non-fungible-token stacks-builder-nft uint)

;; Constants
(define-constant CONTRACT-OWNER tx-sender)
(define-constant ERR-NOT-AUTHORIZED (err u401))
(define-constant ERR-NOT-FOUND (err u404))
(define-constant ERR-MAX-SUPPLY-REACHED (err u410))
(define-constant ERR-LISTING-NOT-FOUND (err u411))

;; Maximum supply
(define-constant MAX-SUPPLY u10000)

;; Data vars
(define-data-var last-token-id uint u0)
(define-data-var base-uri (string-utf8 256) u"https://stacks-builder-nft.com/metadata/")
(define-data-var mint-price uint u1000000)
(define-data-var minting-enabled bool true)

;; Data maps
(define-map token-metadata uint (string-utf8 256))
(define-map token-listings uint uint)

;; Get the last minted token ID
(define-read-only (get-last-token-id)
  (ok (var-get last-token-id)))

;; Get the token URI for a specific token
(define-read-only (get-token-uri (token-id uint))
  (ok (some (var-get base-uri))))

;; Get the owner of a specific token
(define-read-only (get-owner (token-id uint))
  (ok (nft-get-owner? stacks-builder-nft token-id)))

;; Transfer an NFT
(define-public (transfer (token-id uint) (sender principal) (recipient principal))
  (begin
    (asserts! (is-eq tx-sender sender) ERR-NOT-AUTHORIZED)
    (asserts! (is-some (nft-get-owner? stacks-builder-nft token-id)) ERR-NOT-FOUND)
    (map-delete token-listings token-id)
    (nft-transfer? stacks-builder-nft token-id sender recipient)))

;; Mint a new NFT (public minting with payment)
(define-public (mint)
  (let (
    (token-id (+ (var-get last-token-id) u1))
    (price (var-get mint-price))
  )
    (asserts! (var-get minting-enabled) ERR-NOT-AUTHORIZED)
    (asserts! (<= token-id MAX-SUPPLY) ERR-MAX-SUPPLY-REACHED)
    (try! (stx-transfer? price tx-sender CONTRACT-OWNER))
    (try! (nft-mint? stacks-builder-nft token-id tx-sender))
    (var-set last-token-id token-id)
    (ok token-id)))

;; Owner mint (free, for airdrops)
(define-public (mint-for (recipient principal))
  (let ((token-id (+ (var-get last-token-id) u1)))
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (asserts! (<= token-id MAX-SUPPLY) ERR-MAX-SUPPLY-REACHED)
    (try! (nft-mint? stacks-builder-nft token-id recipient))
    (var-set last-token-id token-id)
    (ok token-id)))

;; Burn an NFT
(define-public (burn (token-id uint))
  (begin
    (asserts! (is-eq (some tx-sender) (nft-get-owner? stacks-builder-nft token-id)) ERR-NOT-AUTHORIZED)
    (map-delete token-listings token-id)
    (nft-burn? stacks-builder-nft token-id tx-sender)))

;; Set base URI (owner only)
(define-public (set-base-uri (new-uri (string-utf8 256)))
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (var-set base-uri new-uri)
    (ok true)))

;; Set mint price (owner only)
(define-public (set-mint-price (new-price uint))
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (var-set mint-price new-price)
    (ok true)))

;; Toggle minting (owner only)
(define-public (toggle-minting)
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (var-set minting-enabled (not (var-get minting-enabled)))
    (ok (var-get minting-enabled))))

;; List NFT for sale
(define-public (list-for-sale (token-id uint) (price uint))
  (begin
    (asserts! (is-eq (some tx-sender) (nft-get-owner? stacks-builder-nft token-id)) ERR-NOT-AUTHORIZED)
    (map-set token-listings token-id price)
    (ok true)))

;; Remove from sale
(define-public (unlist (token-id uint))
  (begin
    (asserts! (is-eq (some tx-sender) (nft-get-owner? stacks-builder-nft token-id)) ERR-NOT-AUTHORIZED)
    (map-delete token-listings token-id)
    (ok true)))

;; Buy listed NFT
(define-public (buy (token-id uint))
  (let (
    (listing-price (unwrap! (map-get? token-listings token-id) ERR-LISTING-NOT-FOUND))
    (owner (unwrap! (nft-get-owner? stacks-builder-nft token-id) ERR-NOT-FOUND))
  )
    (try! (stx-transfer? listing-price tx-sender owner))
    (try! (nft-transfer? stacks-builder-nft token-id owner tx-sender))
    (map-delete token-listings token-id)
    (ok true)))

;; Get listing price
(define-read-only (get-listing-price (token-id uint))
  (map-get? token-listings token-id))

;; Read-only getters
(define-read-only (get-mint-price)
  (ok (var-get mint-price)))

(define-read-only (get-max-supply)
  (ok MAX-SUPPLY))

(define-read-only (is-minting-enabled)
  (ok (var-get minting-enabled)))

(define-read-only (get-remaining-supply)
  (ok (- MAX-SUPPLY (var-get last-token-id))))

Functions (18)

FunctionAccessArgs
get-last-token-idread-only
get-token-uriread-onlytoken-id: uint
get-ownerread-onlytoken-id: uint
transferpublictoken-id: uint, sender: principal, recipient: principal
mintpublic
mint-forpublicrecipient: principal
burnpublictoken-id: uint
set-base-uripublicnew-uri: (string-utf8 256
set-mint-pricepublicnew-price: uint
toggle-mintingpublic
list-for-salepublictoken-id: uint, price: uint
unlistpublictoken-id: uint
buypublictoken-id: uint
get-listing-priceread-onlytoken-id: uint
get-mint-priceread-only
get-max-supplyread-only
is-minting-enabledread-only
get-remaining-supplyread-only