Source Code

;; File: contracts/aura-nft-v4.clar
;; Bitcoin Aura NFT v4 - Hardened controls (Clarity 4)

;; SIP-009 compliance
(impl-trait .nft-trait.nft-trait)

;; --- TOKEN ---

(define-non-fungible-token bitcoin-aura-v4 uint)

;; --- CONSTANTS ---

(define-constant collection-uri "https://esolvhnpvfoavgycrwgy.supabase.co/storage/v1/object/public/bitcoin-aura/metadata/collection.json")
(define-constant fire-uri "https://esolvhnpvfoavgycrwgy.supabase.co/storage/v1/object/public/bitcoin-aura/metadata/fire.json")
(define-constant water-uri "https://esolvhnpvfoavgycrwgy.supabase.co/storage/v1/object/public/bitcoin-aura/metadata/water.json")
(define-constant stone-uri "https://esolvhnpvfoavgycrwgy.supabase.co/storage/v1/object/public/bitcoin-aura/metadata/stone.json")

(define-constant aura-fire "FIRE TRADER")
(define-constant aura-water "WATER FLOW")
(define-constant aura-stone "STONE HODLER")

(define-constant err-unauthorized (err u100))
(define-constant err-invalid-sender (err u101))
(define-constant err-token-not-found (err u404))
(define-constant err-btc-already-claimed (err u409))
(define-constant err-invalid-aura (err u410))
(define-constant err-invalid-metadata-uri (err u411))
(define-constant err-invalid-btc-address (err u412))
(define-constant err-mint-paused (err u413))

;; --- STORAGE ---

(define-data-var contract-owner principal tx-sender)
(define-data-var minter principal tx-sender)
(define-data-var mint-paused bool false)
(define-data-var last-token-id uint u0)

;; Token metadata
(define-map aura-metadata uint (string-ascii 20))
(define-map token-uri uint (string-ascii 256))

;; BTC identity linkage
(define-map btc-address uint (string-ascii 64))
(define-map btc-to-token (string-ascii 64) uint)

;; --- VALIDATION HELPERS ---

(define-private (assert-contract-owner)
  (if (is-eq tx-sender (var-get contract-owner))
    (ok true)
    err-unauthorized
  )
)

(define-private (assert-mint-allowed)
  (if (var-get mint-paused)
    err-mint-paused
    (if (is-eq tx-sender (var-get minter))
      (ok true)
      err-unauthorized
    )
  )
)

(define-private (is-supported-aura (aura-type (string-ascii 20)))
  (or
    (is-eq aura-type aura-fire)
    (is-eq aura-type aura-water)
    (is-eq aura-type aura-stone)
  )
)

(define-private (is-valid-uri-for-aura (aura-type (string-ascii 20)) (metadata-uri (string-ascii 256)))
  (or
    (and (is-eq aura-type aura-fire) (is-eq metadata-uri fire-uri))
    (and (is-eq aura-type aura-water) (is-eq metadata-uri water-uri))
    (and (is-eq aura-type aura-stone) (is-eq metadata-uri stone-uri))
  )
)

(define-private (is-valid-btc-address (btc-addr (string-ascii 64)))
  (let ((address-len (len btc-addr)))
    (and (>= address-len u14) (<= address-len u64))
  )
)

;; --- MINTING ---

(define-public (mint (btc-addr (string-ascii 64)) (aura-type (string-ascii 20)) (metadata-uri (string-ascii 256)))
  (begin
    (try! (assert-mint-allowed))
    (asserts! (is-valid-btc-address btc-addr) err-invalid-btc-address)
    (asserts! (is-supported-aura aura-type) err-invalid-aura)
    (asserts! (is-valid-uri-for-aura aura-type metadata-uri) err-invalid-metadata-uri)
    (let ((token-id (+ (var-get last-token-id) u1)))
      (begin
        (asserts! (map-insert btc-to-token btc-addr token-id) err-btc-already-claimed)
        (try! (nft-mint? bitcoin-aura-v4 token-id tx-sender))
        (map-set btc-address token-id btc-addr)
        (map-set aura-metadata token-id aura-type)
        (map-set token-uri token-id metadata-uri)
        (var-set last-token-id token-id)
        (ok token-id)
      )
    )
  )
)

;; --- SIP-009 REQUIRED ---

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

(define-read-only (get-token-uri (token-id uint))
  (if (is-some (nft-get-owner? bitcoin-aura-v4 token-id))
    (ok (map-get? token-uri token-id))
    (ok none)
  )
)

(define-read-only (get-owner (token-id uint))
  (ok (nft-get-owner? bitcoin-aura-v4 token-id))
)

(define-public (transfer (token-id uint) (sender principal) (recipient principal))
  (begin
    (asserts! (is-eq tx-sender sender) err-invalid-sender)
    (nft-transfer? bitcoin-aura-v4 token-id sender recipient)
  )
)

;; --- EXTRA VIEWS ---

(define-read-only (get-aura (token-id uint))
  (ok (map-get? aura-metadata token-id))
)

(define-read-only (get-btc-address (token-id uint))
  (ok (map-get? btc-address token-id))
)

(define-read-only (get-token-by-btc (btc-addr (string-ascii 64)))
  (ok (map-get? btc-to-token btc-addr))
)

(define-read-only (get-collection-uri)
  (ok collection-uri)
)

;; --- ADMIN ---

(define-public (set-contract-owner (new-owner principal))
  (begin
    (try! (assert-contract-owner))
    (var-set contract-owner new-owner)
    (ok true)
  )
)

(define-public (set-minter (new-minter principal))
  (begin
    (try! (assert-contract-owner))
    (var-set minter new-minter)
    (ok true)
  )
)

(define-public (set-mint-paused (paused bool))
  (begin
    (try! (assert-contract-owner))
    (var-set mint-paused paused)
    (ok true)
  )
)

(define-read-only (get-contract-owner)
  (ok (var-get contract-owner))
)

(define-read-only (get-minter)
  (ok (var-get minter))
)

(define-read-only (get-mint-paused)
  (ok (var-get mint-paused))
)

;; --- AURA UPDATE ---

(define-public (update-aura (btc-addr (string-ascii 64)) (new-aura-type (string-ascii 20)) (new-metadata-uri (string-ascii 256)))
  (begin
    (asserts! (is-valid-btc-address btc-addr) err-invalid-btc-address)
    (asserts! (is-supported-aura new-aura-type) err-invalid-aura)
    (asserts! (is-valid-uri-for-aura new-aura-type new-metadata-uri) err-invalid-metadata-uri)
    (let ((token-id (unwrap! (map-get? btc-to-token btc-addr) err-token-not-found)))
      (let ((owner (unwrap! (nft-get-owner? bitcoin-aura-v4 token-id) err-token-not-found)))
        (begin
          (asserts! (is-eq tx-sender owner) err-unauthorized)
          (map-set aura-metadata token-id new-aura-type)
          (map-set token-uri token-id new-metadata-uri)
          (ok true)
        )
      )
    )
  )
)

Functions (21)

FunctionAccessArgs
assert-contract-ownerprivate
assert-mint-allowedprivate
is-supported-auraprivateaura-type: (string-ascii 20
is-valid-uri-for-auraprivateaura-type: (string-ascii 20
is-valid-btc-addressprivatebtc-addr: (string-ascii 64
mintpublicbtc-addr: (string-ascii 64
get-last-token-idread-only
get-token-uriread-onlytoken-id: uint
get-ownerread-onlytoken-id: uint
transferpublictoken-id: uint, sender: principal, recipient: principal
get-auraread-onlytoken-id: uint
get-btc-addressread-onlytoken-id: uint
get-token-by-btcread-onlybtc-addr: (string-ascii 64
get-collection-uriread-only
set-contract-ownerpublicnew-owner: principal
set-minterpublicnew-minter: principal
set-mint-pausedpublicpaused: bool
get-contract-ownerread-only
get-minterread-only
get-mint-pausedread-only
update-aurapublicbtc-addr: (string-ascii 64