Repository navigation
Expand file tree
/
Copy pathcitycats-nft.clar
More file actions
223 lines (193 loc) · 7.62 KB
/
Copy pathcitycats-nft.clar
File metadata and controls
223 lines (193 loc) · 7.62 KB
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
(impl-trait .sip-009-nft-trait-standard.nft-trait)
(use-trait commission-trait .commission-trait.commission)
(define-non-fungible-token CityCats uint)
;; Storage
(define-map token-count principal uint)
(define-map market uint {price: uint, commission: principal})
;; Define Constants
(define-constant CONTRACT-OWNER tx-sender)
(define-constant CITYCATS-LIMIT u2050)
;; Define error codes
(define-constant ERR-SOLD-OUT (err u100))
(define-constant ERR-WRONG-COMMISSION (err u102))
(define-constant ERR-NOT-AUTHORIZED (err u103))
(define-constant ERR-NOT-FOUND (err u104))
(define-constant ERR-METADATA-FROZEN (err u105))
(define-constant ERR-MINT-ALREADY-SET (err u106))
(define-constant ERR-LISTING (err u107))
(define-constant ERR-FAILED-TO-TRANSFER-STX (err u108))
(define-constant ERR-NOT-OWNER (err u109))
;; Withdraw wallets
;; Citycats 1 3%
(define-constant WALLET_1 'SPNWZ5V2TPWGQGVDR6T7B6RQ4XMGZ4PXTEE0VQ0S)
;; Citycats 2 97%
(define-constant WALLET_2 'SP30AYNXCNBTMANSZHZ0FVVGM7W5WF5BJZDX7NW3)
;; Define Variables
(define-data-var last-id uint u0)
(define-data-var metadata-frozen bool false)
;; Store the root token uri used to query metadata
(define-data-var base-token-uri (string-ascii 210) "ipfs://Qmdy9aXsXJpZNrNaDtqKdFQecJkXMeWa2XhcSmWkdk9t51/")
;; Store the mint address allowed to trigger minting
(define-map mint-address bool principal)
;; Token count for account
(define-read-only (get-balance (account principal))
(default-to u0
(map-get? token-count account)))
(define-private (trnsfr (id uint) (sender principal) (recipient principal))
(match (nft-transfer? CityCats id sender recipient)
success
(let
((sender-balance (get-balance sender))
(recipient-balance (get-balance recipient)))
(map-set token-count
sender
(- sender-balance u1))
(map-set token-count
recipient
(+ recipient-balance u1))
(ok success))
error (err error)))
;; SIP009: Transfer token to a specified principal
(define-public (transfer (id uint) (sender principal) (recipient principal))
(begin
(asserts! (is-eq tx-sender sender) ERR-NOT-AUTHORIZED)
(asserts! (is-none (map-get? market id)) ERR-LISTING)
(trnsfr id sender recipient)))
;; SIP009: Get the owner of the specified token ID
(define-read-only (get-owner (id uint))
;; Make sure to replace Citycats
(ok (nft-get-owner? CityCats id)))
;; SIP009: Get the last token ID
(define-read-only (get-last-token-id)
(ok (var-get last-id)))
;; SIP009: Get the token URI. You can set it to any other URI
(define-read-only (get-token-uri (token-id uint))
(ok (some (concat (concat (var-get base-token-uri) (uint-to-string token-id)) ".json"))))
;; Mint new NFT - can only be called from the mint address
(define-public (mint (new-owner principal))
(let ((next-id (+ u1 (var-get last-id))))
(asserts! (called-from-mint) ERR-NOT-AUTHORIZED)
(asserts! (< (var-get last-id) CITYCATS-LIMIT) ERR-SOLD-OUT)
(match (nft-mint? CityCats next-id new-owner)
success
(let
((current-balance (get-balance new-owner)))
(begin
(try! (stx-transfer? u1500000 tx-sender WALLET_1)) ;; 3 %
(try! (stx-transfer? u48500000 tx-sender WALLET_2)) ;; 97 %
(var-set last-id next-id)
(map-set token-count
new-owner
(+ current-balance u1)
)
(ok true)))
error (err (* error u10000)))))
(define-public (treasure-mint (new-owner principal))
(let ((next-id (+ u1 (var-get last-id))))
(asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
(asserts! (called-from-mint) ERR-NOT-AUTHORIZED)
(asserts! (< (var-get last-id) CITYCATS-LIMIT) ERR-SOLD-OUT)
(match (nft-mint? CityCats next-id new-owner)
success
(let
((current-balance (get-balance new-owner)))
(begin
(var-set last-id next-id)
(map-set token-count
new-owner
(+ current-balance u1)
)
(ok true)))
error (err (* error u10000)))))
(define-private (is-sender-owner (id uint))
(let ((owner (unwrap! (nft-get-owner? CityCats id) false)))
(or (is-eq tx-sender owner) (is-eq contract-caller owner))))
;; Marketplace function
(define-read-only (get-listing-in-ustx (id uint))
(map-get? market id))
;; Marketplace function
(define-public (list-in-ustx (id uint) (price uint) (comm <commission-trait>))
(let ((listing {price: price, commission: (contract-of comm)}))
(asserts! (is-sender-owner id) ERR-NOT-AUTHORIZED)
(map-set market id listing)
(print (merge listing {a: "list-in-ustx", id: id}))
(ok true)))
;; Marketplace function
(define-public (unlist-in-ustx (id uint))
(begin
(asserts! (is-sender-owner id) ERR-NOT-AUTHORIZED)
(map-delete market id)
(print {a: "unlist-in-ustx", id: id})
(ok true)))
;; Marketplace function
(define-public (buy-in-ustx (id uint) (comm <commission-trait>))
(let ((owner (unwrap! (nft-get-owner? CityCats id) ERR-NOT-FOUND))
(listing (unwrap! (map-get? market id) ERR-LISTING))
(price (get price listing)))
(asserts! (is-eq (contract-of comm) (get commission listing)) ERR-WRONG-COMMISSION)
(try! (stx-transfer? price tx-sender owner))
(try! (contract-call? comm pay id price))
(try! (trnsfr id owner tx-sender))
(map-delete market id)
(print {a: "buy-in-ustx", id: id})
(ok true)))
;; Manage function
(define-public (burn (id uint))
(let ((owner (unwrap! (nft-get-owner? CityCats id) ERR-NOT-AUTHORIZED)))
(asserts! (is-eq owner contract-caller) ERR-NOT-OWNER)
(map-delete market id)
(nft-burn? CityCats id contract-caller)
)
)
;; Set base token uri
(define-public (set-base-token-uri (new-base-token-uri (string-ascii 80)))
(begin
(asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
(asserts! (not (var-get metadata-frozen)) ERR-METADATA-FROZEN)
(var-set base-token-uri new-base-token-uri)
(ok true)))
;; Reveal
(define-public (reveal (reveal-uri (string-ascii 80)))
(begin
(try! (set-base-token-uri reveal-uri))
(ok true)))
;; Freeze metadata
(define-public (freeze-metadata)
(begin
(asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
(var-set metadata-frozen true)
(ok true)))
;; Manage the Mint
(define-private (called-from-mint)
(let ((the-mint
(unwrap! (map-get? mint-address true)
false)))
(is-eq contract-caller the-mint)))
;; Set mint address - can only be called once
(define-public (set-mint-address)
(let ((the-mint (map-get? mint-address true)))
(asserts! (and (is-none the-mint)
(map-insert mint-address true tx-sender))
ERR-MINT-ALREADY-SET)
(ok tx-sender)))
;; Utils to convert an uint to string
;; Clarity doesn't support uint-to-string natively for now
;; Code for uint to string
(define-constant LIST_40 (list
true true true true true true true true true true
true true true true true true true true true true
true true true true true true true true true true
true true true true true true true true true true
))
(define-read-only (uint-to-string (value uint))
(get return (fold uint-to-string-clojure LIST_40 {value: value, return: ""}))
)
(define-read-only (uint-to-string-clojure (i bool) (data {value: uint, return: (string-ascii 40)}))
(if (> (get value data) u0)
{
value: (/ (get value data) u10),
return: (unwrap-panic (as-max-len? (concat (unwrap-panic (element-at "0123456789" (mod (get value data) u10))) (get return data)) u40))
}
data
)
)