Source Code

;; clarity-version 4
;; proof-of-claim-nft.clar
;; Simple SIP-009 NFT that serves as proof of deadman vault claim
;; Each NFT is a certificate showing the beneficiary claimed the funds

(define-constant ERR-NOT-AUTHORIZED u401)
(define-constant ERR-NOT-FOUND u404)

(define-non-fungible-token proof-of-claim uint)

(define-data-var last-token-id uint u0)
(define-data-var contract-owner principal tx-sender)

;; Authorized minters (vault contracts that can mint)
(define-map authorized-minters principal bool)

;; Token metadata - who claimed and when
(define-map token-data uint {
  beneficiary: principal,
  claimed-at: uint
})

;; ===== SIP-009 FUNCTIONS =====

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

(define-read-only (get-token-uri (token-id uint))
  (ok (some (generate-token-uri token-id))))

(define-read-only (get-owner (token-id uint))
  (ok (nft-get-owner? proof-of-claim token-id)))

(define-public (transfer (token-id uint) (sender principal) (recipient principal))
  (begin
    (asserts! (is-eq tx-sender sender) (err ERR-NOT-AUTHORIZED))
    (nft-transfer? proof-of-claim token-id sender recipient)))

;; ===== ADMIN FUNCTIONS =====

(define-public (set-authorized-minter (minter principal) (authorized bool))
  (begin
    (asserts! (is-eq tx-sender (var-get contract-owner)) (err ERR-NOT-AUTHORIZED))
    (ok (map-set authorized-minters minter authorized))))

(define-public (transfer-ownership (new-owner principal))
  (begin
    (asserts! (is-eq tx-sender (var-get contract-owner)) (err ERR-NOT-AUTHORIZED))
    (var-set contract-owner new-owner)
    (ok true)))

;; ===== MINTING FUNCTIONS =====

(define-public (mint (recipient principal))
  (let (
    (token-id (+ (var-get last-token-id) u1))
    (is-authorized (default-to false (map-get? authorized-minters tx-sender)))
  )
    (asserts! (or is-authorized (is-eq tx-sender (var-get contract-owner))) (err ERR-NOT-AUTHORIZED))
    
    ;; Mint NFT
    (try! (nft-mint? proof-of-claim token-id recipient))
    
    ;; Store metadata
    (map-set token-data token-id {
      beneficiary: recipient,
      claimed-at: burn-block-height
    })
    
    ;; Update counter
    (var-set last-token-id token-id)
    (ok token-id)))

;; ===== SVG GENERATION =====

(define-read-only (generate-token-uri (token-id uint))
  (match (map-get? token-data token-id)
    data (concat "data:application/json;charset=utf-8,{\"name\":\"Proof of Claim Certificate\",\"description\":\"This NFT certifies that the beneficiary has claimed funds from a deadman vault\",\"image\":\"data:image/svg+xml;charset=utf-8,"
           (concat (generate-svg)
           "\"}"))
    ""))

(define-read-only (generate-svg)
  "<svg xmlns='http://www.w3.org/2000/svg' width='400' height='400'><rect width='400' height='400' fill='%23111'/><rect x='20' y='20' width='360' height='360' fill='none' stroke='%23FFD700' stroke-width='4'/><text x='200' y='100' text-anchor='middle' fill='%23FFD700' font-size='24' font-weight='bold'>PROOF OF CLAIM</text><text x='200' y='180' text-anchor='middle' fill='%23FFF' font-size='16'>This certificate confirms that</text><text x='200' y='210' text-anchor='middle' fill='%23FFF' font-size='16'>the beneficiary has successfully</text><text x='200' y='240' text-anchor='middle' fill='%23FFF' font-size='16'>claimed funds from a</text><text x='200' y='270' text-anchor='middle' fill='%23FFF' font-size='16'>Deadman Savings Vault</text><circle cx='200' cy='320' r='30' fill='none' stroke='%23FFD700' stroke-width='3'/><text x='200' y='330' text-anchor='middle' fill='%23FFD700' font-size='18' font-weight='bold'>OK</text></svg>")

;; ===== READ-ONLY QUERIES =====

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

(define-read-only (is-authorized-minter (minter principal))
  (default-to false (map-get? authorized-minters minter)))

Functions (11)

FunctionAccessArgs
get-last-token-idread-only
get-token-uriread-onlytoken-id: uint
get-ownerread-onlytoken-id: uint
transferpublictoken-id: uint, sender: principal, recipient: principal
set-authorized-minterpublicminter: principal, authorized: bool
transfer-ownershippublicnew-owner: principal
mintpublicrecipient: principal
generate-token-uriread-onlytoken-id: uint
generate-svgread-only
get-token-metadataread-onlytoken-id: uint
is-authorized-minterread-onlyminter: principal