Source Code

(define-non-fungible-token authorized-nft uint)

(define-data-var token-id-nonce uint u0)
(define-data-var user-limit uint u5)
(define-data-var reset-allowed bool false)

(define-map token-authorizations {token-id: uint, user: principal} {rights: (list 20 (string-ascii 32)), expires: uint})
(define-map token-users uint (list 5 principal))
(define-map contract-rights (string-ascii 32) bool)

(define-constant err-owner-only (err u400))
(define-constant err-invalid-user (err u401))
(define-constant err-authorization-expired (err u402))
(define-constant err-user-limit-reached (err u403))
(define-constant err-reset-not-allowed (err u404))
(define-constant err-invalid-right (err u405))

(define-read-only (get-rights)
  (ok (list "display" "copy" "distribute" "modify" "commercial-use")))

(define-read-only (get-expires (token-id uint) (user principal))
  (ok (get expires (default-to {rights: (list), expires: u0} (map-get? token-authorizations {token-id: token-id, user: user})))))

(define-read-only (get-user-rights (token-id uint) (user principal))
  (ok (get rights (default-to {rights: (list), expires: u0} (map-get? token-authorizations {token-id: token-id, user: user})))))

(define-read-only (check-authorization-availability (token-id uint))
  (let ((users (default-to (list) (map-get? token-users token-id))))
    (ok (< (len users) (var-get user-limit)))))

(define-public (transfer (id uint) (sender principal) (recipient principal))
  (begin
    (asserts! (is-eq tx-sender sender) err-owner-only)
    (nft-transfer? authorized-nft id sender recipient)))

(define-public (mint (recipient principal))
  (let ((token-id (+ (var-get token-id-nonce) u1)))
    (try! (nft-mint? authorized-nft token-id recipient))
    (var-set token-id-nonce token-id)
    (ok token-id)))

(define-public (authorize-user (token-id uint) (user principal) (duration uint))
  (let ((owner (unwrap! (nft-get-owner? authorized-nft token-id) err-owner-only))
        (all-rights (unwrap-panic (get-rights))))
    (asserts! (is-eq tx-sender owner) err-owner-only)
    (authorize-user-with-rights token-id user all-rights duration)))

(define-public (authorize-user-with-rights (token-id uint) (user principal) (rights (list 20 (string-ascii 32))) (duration uint))
  (let ((owner (unwrap! (nft-get-owner? authorized-nft token-id) err-owner-only))
        (expires (+ stacks-block-height duration))
        (users (default-to (list) (map-get? token-users token-id))))
    (asserts! (is-eq tx-sender owner) err-owner-only)
    (asserts! (< (len users) (var-get user-limit)) err-user-limit-reached)
    (map-set token-authorizations {token-id: token-id, user: user} {rights: rights, expires: expires})
    (map-set token-users token-id (unwrap-panic (as-max-len? (append users user) u5)))
    (ok true)))

(define-public (transfer-user-rights (token-id uint) (new-user principal))
  (let ((auth (unwrap! (map-get? token-authorizations {token-id: token-id, user: tx-sender}) err-invalid-user)))
    (asserts! (< stacks-block-height (get expires auth)) err-authorization-expired)
    (map-delete token-authorizations {token-id: token-id, user: tx-sender})
    (map-set token-authorizations {token-id: token-id, user: new-user} auth)
    (ok true)))

(define-public (extend-duration (token-id uint) (user principal) (duration uint))
  (let ((owner (unwrap! (nft-get-owner? authorized-nft token-id) err-owner-only))
        (auth (unwrap! (map-get? token-authorizations {token-id: token-id, user: user}) err-invalid-user)))
    (asserts! (is-eq tx-sender owner) err-owner-only)
    (map-set token-authorizations {token-id: token-id, user: user} 
      {rights: (get rights auth), expires: (+ stacks-block-height duration)})
    (ok true)))

(define-public (update-user-rights (token-id uint) (user principal) (rights (list 20 (string-ascii 32))))
  (let ((owner (unwrap! (nft-get-owner? authorized-nft token-id) err-owner-only))
        (auth (unwrap! (map-get? token-authorizations {token-id: token-id, user: user}) err-invalid-user)))
    (asserts! (is-eq tx-sender owner) err-owner-only)
    (map-set token-authorizations {token-id: token-id, user: user}
      {rights: rights, expires: (get expires auth)})
    (ok true)))

(define-public (update-user-limit (new-limit uint))
  (begin
    (asserts! (is-eq tx-sender contract-caller) err-owner-only)
    (var-set user-limit new-limit)
    (ok true)))

(define-public (update-reset-allowed (allowed bool))
  (begin
    (asserts! (is-eq tx-sender contract-caller) err-owner-only)
    (var-set reset-allowed allowed)
    (ok true)))

(define-public (reset-user (token-id uint) (user principal))
  (let ((owner (unwrap! (nft-get-owner? authorized-nft token-id) err-owner-only)))
    (asserts! (is-eq tx-sender owner) err-owner-only)
    (asserts! (var-get reset-allowed) err-reset-not-allowed)
    (map-delete token-authorizations {token-id: token-id, user: user})
    (ok true)))

Functions (14)

FunctionAccessArgs
get-rightsread-only
get-expiresread-onlytoken-id: uint, user: principal
get-user-rightsread-onlytoken-id: uint, user: principal
check-authorization-availabilityread-onlytoken-id: uint
transferpublicid: uint, sender: principal, recipient: principal
mintpublicrecipient: principal
authorize-userpublictoken-id: uint, user: principal, duration: uint
authorize-user-with-rightspublictoken-id: uint, user: principal, rights: (list 20 (string-ascii 32
transfer-user-rightspublictoken-id: uint, new-user: principal
extend-durationpublictoken-id: uint, user: principal, duration: uint
update-user-rightspublictoken-id: uint, user: principal, rights: (list 20 (string-ascii 32
update-user-limitpublicnew-limit: uint
update-reset-allowedpublicallowed: bool
reset-userpublictoken-id: uint, user: principal