Source Code

(define-constant ERR_NOT_AUTHORIZED (err u200))
(define-constant ERR_NOT_FOUND (err u201))
(define-constant ERR_ALREADY_REDEEMED (err u202))

(define-non-fungible-token multi-redemption-nft uint)

(define-data-var token-id-nonce uint u0)

(define-map redemptions 
  {operator: principal, token-id: uint, redemption-id: (buff 32)} 
  {redeemed: bool, memo: (string-utf8 256), timestamp: uint}
)

(define-map token-owners uint principal)
(define-map token-uris uint (string-ascii 256))

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

(define-read-only (get-token-uri (id uint))
  (ok (map-get? token-uris id))
)

(define-read-only (get-owner (id uint))
  (ok (nft-get-owner? multi-redemption-nft id))
)

(define-public (transfer (id uint) (sender principal) (recipient principal))
  (begin
    (asserts! (is-eq tx-sender sender) ERR_NOT_AUTHORIZED)
    (nft-transfer? multi-redemption-nft id sender recipient)
  )
)

(define-public (mint (recipient principal) (uri (string-ascii 256)))
  (let (
    (id (+ (var-get token-id-nonce) u1))
  )
    (try! (nft-mint? multi-redemption-nft id recipient))
    (map-set token-uris id uri)
    (var-set token-id-nonce id)
    (ok id)
  )
)

(define-public (redeem (redemption-id (buff 32)) (token-id uint) (memo (string-utf8 256)))
  (let (
    (owner (unwrap! (nft-get-owner? multi-redemption-nft token-id) ERR_NOT_FOUND))
    (key {operator: tx-sender, token-id: token-id, redemption-id: redemption-id})
  )
    (asserts! (is-eq owner tx-sender) ERR_NOT_AUTHORIZED)
    (asserts! (is-none (map-get? redemptions key)) ERR_ALREADY_REDEEMED)
    (map-set redemptions key {
      redeemed: true, 
      memo: memo, 
      timestamp: stacks-block-time
    })
    (print {event: "redeem", operator: tx-sender, token-id: token-id, redemption-id: redemption-id, memo: memo})
    (ok true)
  )
)

(define-public (cancel (redemption-id (buff 32)) (token-id uint) (memo (string-utf8 256)))
  (let (
    (key {operator: tx-sender, token-id: token-id, redemption-id: redemption-id})
    (redemption (unwrap! (map-get? redemptions key) ERR_NOT_FOUND))
  )
    (map-delete redemptions key)
    (print {event: "cancel", operator: tx-sender, token-id: token-id, redemption-id: redemption-id, memo: memo})
    (ok true)
  )
)

(define-read-only (is-redeemed (operator principal) (redemption-id (buff 32)) (token-id uint))
  (let (
    (key {operator: operator, token-id: token-id, redemption-id: redemption-id})
    (redemption (map-get? redemptions key))
  )
    (ok (if (is-some redemption)
      (get redeemed (unwrap-panic redemption))
      false
    ))
  )
)

(define-read-only (get-redemption-info (operator principal) (redemption-id (buff 32)) (token-id uint))
  (ok (map-get? redemptions {operator: operator, token-id: token-id, redemption-id: redemption-id}))
)

Functions (9)

FunctionAccessArgs
get-last-token-idread-only
get-token-uriread-onlyid: uint
get-ownerread-onlyid: uint
transferpublicid: uint, sender: principal, recipient: principal
mintpublicrecipient: principal, uri: (string-ascii 256
redeempublicredemption-id: (buff 32
cancelpublicredemption-id: (buff 32
is-redeemedread-onlyoperator: principal, redemption-id: (buff 32
get-redemption-inforead-onlyoperator: principal, redemption-id: (buff 32