;; 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)
)
)
)
)
)