-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathredeeem-nft-v0.clar
206 lines (174 loc) · 8.29 KB
/
redeeem-nft-v0.clar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
(impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait)
(define-non-fungible-token redeeem-nft uint)
;; Contract constants
(define-constant CONTRACT-OWNER tx-sender)
;; Custom errors
(define-constant ERR-NOT-AUTHORIZED (err u400)) ;; contract operation not unauthorized
(define-constant ERR-NFT-NOT-OWNED (err u401)) ;; nft operation not authorized
(define-constant ERR-APPROVAL-NOT-FOUND (err u402)) ;; approval doesnt exists for the token
(define-constant ERR-COLLECTION-CREATION (err 403)) ;; cant create a collection
(define-constant ERR-COLLECTION-COMPLETED (err u404)) ;; no more size on collection to mint a new token
(define-constant ERR-COLLECTION-NOT-FOUND (err u405)) ;; collection doesnt exists
(define-constant ERR-COLLECTION-WRITE (err u406)) ;; principal has no permission to write on the collection
(define-constant ERR-INSUFFICIENT-FUNDS (err u407)) ;; principal has insuffient funds to pay mint cost
(define-constant ERR-NFT-NOT-FOUND (err u408)) ;; nft doesnt exists
;; Data structures
(define-map meta uint (tuple (collection-id uint) (uri (string-ascii 256))))
(define-map collection-meta uint (tuple (creator principal) (max-size uint) (last-minted uint)))
;; (define-map meta uint {collection-id: uint, uri: (string-ascii 256)})
(define-map nft-approvals uint {approval: principal})
;; Contract variables
(define-data-var last-token-id uint u0)
(define-data-var last-collection-id uint u0)
(define-data-var mint-cost uint u0)
(define-data-var public-minting bool false)
;; Get the public minting status of the contract
(define-read-only (is-minting-public)
(ok (var-get public-minting)))
;; Get current cost to mint
(define-read-only (get-mint-cost)
(ok (var-get mint-cost)))
;; Get the approval status of a principal for a given token identifier
(define-read-only (get-approval (token-id uint))
(ok (get approval (map-get? nft-approvals token-id))))
;; Get the owner of a given token identifier
(define-read-only (get-owner (token-id uint))
(ok (nft-get-owner? redeeem-nft token-id)))
;; Get the owner of a given collection identifier
(define-read-only (get-collection-owner (collection-id uint))
(ok (get creator (map-get? collection-meta collection-id))))
;; Last token ID, limited to uint range
(define-read-only (get-last-token-id)
(ok (var-get last-token-id)))
;; Get the URI for metadata associated with the token
(define-read-only (get-token-uri (token-id uint))
(ok (get uri (map-get? meta token-id))))
;; Get a token collection-id
(define-read-only (get-token-collection-id (token-id uint))
(ok (get collection-id (map-get? meta token-id))))
;; Get the STX balance of a given principal
(define-read-only (get-stx-account-balance (account principal))
(ok (stx-get-balance account)))
;; Get data for a given Collection ID
(define-read-only (get-collection-data (collection-id uint))
(ok (map-get? collection-meta collection-id))
)
;; Set public minting state
(define-public (set-public-minting (value bool))
(begin
(asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
(var-set public-minting value)
(ok true)))
;; Set the mint cost
(define-public (set-mint-cost (cost uint))
(begin
(asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
(var-set mint-cost cost)
(ok true)))
;; Transfer from the sender to a new principal - Approval automatically revoked
(define-public (transfer (token-id uint) (owner principal) (recipient principal))
(if (is-owner-or-approved token-id tx-sender)
(begin
(try!
(if (is-eq (ok none) (get-approval token-id))
(ok false)
(revoke-approval token-id)))
(try! (nft-transfer? redeeem-nft token-id owner recipient))
(ok true))
ERR-NFT-NOT-OWNED))
;; Approve contract owner to act on behalf of token owner
(define-public (set-approval (token-id uint))
(if (is-owner token-id tx-sender)
(begin
(map-set nft-approvals token-id {approval: CONTRACT-OWNER})
(ok true))
ERR-NFT-NOT-OWNED))
;; Revoke approval for contract owner to act on behalf of the token owner
(define-public (revoke-approval (token-id uint))
(begin
(asserts! (is-owner-or-approved token-id tx-sender) ERR-NFT-NOT-OWNED)
(asserts! (map-delete nft-approvals token-id) ERR-APPROVAL-NOT-FOUND)
(ok true)))
;; Set the URI for given token
(define-public (set-token-uri (token-id uint) (uri (string-ascii 256)))
(match (map-get? meta token-id)
token-meta
(begin
(asserts! (or (is-eq tx-sender CONTRACT-OWNER) (is-collection-owner (get collection-id token-meta) tx-sender)) ERR-NOT-AUTHORIZED)
(map-set meta token-id {collection-id: (get collection-id token-meta), uri: uri} )
(ok true))
ERR-NFT-NOT-FOUND))
;; Set the collection id for given token
(define-public (set-token-collection-id (token-id uint) (collection-id uint))
(match (map-get? meta token-id)
token-meta
(begin
(asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
(map-set meta token-id {collection-id: collection-id, uri: (get uri token-meta)} )
(ok true))
ERR-NFT-NOT-FOUND))
;; Mint an NFT on a given Collection
(define-public (mint (collection-id uint) (uri (string-ascii 256)))
(match (map-get? collection-meta collection-id)
collection
(begin
(asserts! (or (is-eq (get max-size collection) u0) (and (> (get max-size collection) u0) (< (get last-minted collection) (get max-size collection)))) ERR-COLLECTION-COMPLETED)
(asserts! (or (is-eq tx-sender CONTRACT-OWNER) (is-eq tx-sender (get creator collection))) ERR-COLLECTION-WRITE)
(asserts! (or (is-eq tx-sender CONTRACT-OWNER) (var-get public-minting)) ERR-NOT-AUTHORIZED)
(ok (try! (mint-token tx-sender collection-id uri))))
ERR-COLLECTION-NOT-FOUND))
;; Redeeem the NFT for a physical asset should burn the token on the blockchain
(define-public (redeeem (token-id uint))
(begin
(asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
(match (nft-burn? redeeem-nft token-id tx-sender)
success (ok true)
error (err error))))
;; Creates a new collection
(define-public (create-collection (max-size uint))
(let ((next-collection-id (+ u1 (var-get last-collection-id))))
(begin
(asserts! (or (is-eq tx-sender CONTRACT-OWNER) (var-get public-minting)) ERR-NOT-AUTHORIZED)
(map-insert collection-meta next-collection-id { creator: tx-sender, max-size: max-size, last-minted: u0 })
(var-set last-collection-id next-collection-id)
(ok next-collection-id))))
;; Checks if a principal owns the token
(define-private (is-owner (token-id uint) (user principal))
(is-eq user (unwrap! (nft-get-owner? redeeem-nft token-id) false)))
;; Checks if a principal owns the token
(define-private (is-collection-owner (collection-id uint) (user principal))
(match (map-get? collection-meta collection-id)
collection (is-eq user (get creator collection))
false))
;; Checks if the contract owner is approved to act on behalf of the token owner
(define-private (is-approved (token-id uint))
(is-eq CONTRACT-OWNER (unwrap! (get approval (map-get? nft-approvals token-id)) false)))
(define-private (is-owner-or-approved (token-id uint) (user principal))
(if (is-owner token-id user)
true
(if (is-approved token-id) true false)))
;; Mint a token to a specific principal
(define-private (mint-token (new-owner principal) (collection-id uint) (uri (string-ascii 256)))
(if (charge-stx)
(let ((next-token-id (+ u1 (var-get last-token-id))))
(match (nft-mint? redeeem-nft next-token-id new-owner)
success
(begin
(map-insert meta next-token-id { uri: uri, collection-id: collection-id })
(match (map-get? collection-meta collection-id)
collection
(begin
(map-set collection-meta collection-id {creator: (get creator collection), max-size: (get max-size collection), last-minted: (+ u1 (get last-minted collection))})
(var-set last-token-id next-token-id)
(ok next-token-id))
ERR-COLLECTION-NOT-FOUND
))
error (err error)))
ERR-INSUFFICIENT-FUNDS))
;; Charge the minting if needed
(define-private (charge-stx)
(if (> (var-get mint-cost) u0)
(match (stx-transfer? (var-get mint-cost) tx-sender (as-contract tx-sender))
success true
error false)
true))