/
bitcoin-l2-odyssey.clar
272 lines (233 loc) · 7.86 KB
/
bitcoin-l2-odyssey.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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
;; title: StarNFT
;; version: 0.1.0
;; summary: Galxe StarNFT
;; description:
;; traits
;;
(impl-trait 'SP3QSAJQ4EA8WXEDSRRKMZZ29NH91VZ6C5X88FGZQ.nft-approvable-trait.nft-approvable-trait)
;; (impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait)
;; token definitions
;;
(define-non-fungible-token starnfts uint)
;; constants
(define-constant token-name "GalxeStarNFT")
(define-constant token-symbol "GALXE")
;; errors
(define-constant err-owner-only (err u100))
(define-constant err-not-token-owner (err u101))
(define-constant err-invalid-signature (err u102))
(define-constant err-cap-reached (err u103))
(define-constant err-invalid-signer-public-key (err u104))
(define-constant err-non-transferrable (err u105))
(define-constant err-invalid-address (err u106))
(define-constant err-not-approval (err u107))
;; full uri: https://graphigo.prd.galaxy.eco/metadata/{contract_hash}/{nft_id}.json
(define-constant base-uri "https://graphigo.prd.galaxy.eco/metadata/SPYHQS4RFA4N87RDWNPEWYRYK3C6N2Q8S5CY3XG5.bitcoin-l2-odyssey/")
;; data vars
;;
(define-data-var contract-owner principal tx-sender)
;; signer public key
(define-data-var signer-public-key (buff 33) 0x036c572987e98f6244716c02ffa82a4aa244e3c8d965d6cac7079d98dcc2d78c32)
(define-data-var last-token-id uint u0)
;; transferrable
(define-data-var transferrable bool true)
;; data maps
;;
;; nft approvals<token-id, approval>
(define-map nft-approvals uint principal)
;; minted verify ids<verify-id, minted>
(define-map minted-verify-ids uint bool)
;; campaign minted<cid, minted>
(define-map campaign-minted uint uint)
;; nft cids<token-id, cid>
(define-map nft-cids uint uint)
;; public functions
;;
(define-public (transfer (token-id uint) (owner principal) (recipient principal))
(begin
(asserts! (var-get transferrable) err-non-transferrable)
(asserts! (and (is-owner token-id owner) (is-owner-or-approval token-id tx-sender)) err-not-token-owner)
(clear-approval token-id)
(nft-transfer? starnfts token-id owner recipient)
)
)
;; sets an approval principal - allowed to call transfer on owner behalf.
(define-public (set-approval-for (token-id uint) (approval principal))
(begin
(asserts! (is-owner token-id tx-sender) err-not-token-owner)
(map-set nft-approvals token-id approval)
(print {evt: "set-approval-for", token-id: token-id, approval: approval})
(ok true)
)
)
(define-public (claim (cid uint) (verify-id uint) (cap uint) (owner principal) (signature (buff 65)))
(begin
(asserts! (is-standard owner) err-invalid-address)
;; check cap
(asserts! (under-cap cid cap) err-cap-reached)
;; check verify id
(asserts! (not (is-minted verify-id)) err-invalid-signature)
;; verify signature
;; (asserts! (valid-signature cid verify-id cap owner signature) err-invalid-signature)
(let
(
(token-id (+ (var-get last-token-id) u1))
(minted-count (+ (get-minted cid) u1))
)
;; increase cap
(map-set campaign-minted cid minted-count)
;; save verify id
(map-set minted-verify-ids verify-id true)
;; save nft cid
(map-set nft-cids token-id cid)
;; save last token id
(var-set last-token-id token-id)
;; mint token
(try! (nft-mint? starnfts token-id owner))
(print {evt: "claim", token-id: token-id, cid: cid, verify-id: verify-id, cap: cap, owner: owner})
(ok token-id)
)
)
)
(define-public (update-transfferable (new-transferrable bool))
(begin
(asserts! (is-eq tx-sender (var-get contract-owner)) err-owner-only)
(var-set transferrable new-transferrable)
(print {evt: "update-transfferable", new-transferrable: new-transferrable})
(ok true)
)
)
(define-public (update-owner (new-owner principal))
(begin
(asserts! (is-eq tx-sender (var-get contract-owner)) err-owner-only)
(asserts! (is-standard new-owner) err-invalid-address)
(var-set contract-owner new-owner)
(print {evt: "update-owner", new-owner: new-owner})
(ok true)
)
)
(define-public (update-signer-public-key (new-public-key (buff 33)))
(begin
(asserts! (is-eq tx-sender (var-get contract-owner)) err-owner-only)
(asserts! (not (is-eq new-public-key 0x000000000000000000000000000000000000000000000000000000000000000000)) err-invalid-signer-public-key)
(var-set signer-public-key new-public-key)
(print {evt: "update-signer-public-key", new-public-key: new-public-key})
(ok true)
)
)
;; read only functions
;;
(define-read-only (get-last-token-id)
(ok (var-get last-token-id))
)
(define-read-only (get-token-uri (token-id uint))
(ok
(if (is-none (nft-get-owner? starnfts token-id))
none
(some (nft-uri token-id))
)
)
)
(define-read-only (name)
(ok token-name)
)
(define-read-only (symbol)
(ok token-symbol)
)
(define-read-only (get-transferrable)
(ok (var-get transferrable))
)
(define-read-only (get-owner (token-id uint))
(ok (nft-get-owner? starnfts token-id))
)
(define-read-only (get-approval (token-id uint))
(ok (unwrap! (map-get? nft-approvals token-id) err-not-approval))
)
(define-read-only (get-signer-public-key)
(ok (var-get signer-public-key))
)
(define-read-only (get-cid (token-id uint))
(ok (map-get? nft-cids token-id))
)
(define-read-only (get-campaign-minted (cid uint))
(ok (get-minted cid))
)
(define-read-only (is-verify-id-minted (verify-id uint))
(ok (map-get? minted-verify-ids verify-id))
)
(define-read-only (get-contract-hash)
(ok (contract-hash))
)
;; private functions
;;
(define-private (contract-hash)
(unwrap-panic (to-consensus-buff? (as-contract tx-sender)))
)
(define-private (is-owner (token-id uint) (user principal))
(is-eq user (unwrap! (nft-get-owner? starnfts token-id) false))
)
(define-private (is-approval (token-id uint) (user principal))
(is-eq user (unwrap! (map-get? nft-approvals token-id) false))
)
(define-private (is-owner-or-approval (token-id uint) (user principal))
(if (is-owner token-id user) true
(if (is-approval token-id user) true false)
)
)
(define-private (clear-approval (token-id uint))
(map-delete nft-approvals token-id)
)
(define-private (get-minted (cid uint))
;; if none, return 0
;; else return value
(default-to u0 (map-get? campaign-minted cid))
)
(define-private (is-minted (verify-id uint))
;; if exist, return true
(is-some (map-get? minted-verify-ids verify-id))
)
(define-private (under-cap (cid uint) (cap uint))
;; if cap equals 0, no cap
(if (is-eq cap u0)
true
(< (get-minted cid) cap)
)
)
(define-private (valid-signature (cid uint) (verify-id uint) (cap uint) (owner principal) (signature (buff 65)))
(let
(
(msg-hash (hash-claim-msg cid verify-id cap owner))
)
(secp256k1-verify msg-hash signature (var-get signer-public-key))
)
)
(define-private (hash-claim-msg (cid uint) (verify-id uint) (cap uint) (owner principal))
;; sha256(concat(sha256(chain-id), sha256(cid), sha256(verify-id), sha256(cap)))
(sha256
(concat
(concat
(concat
(concat
(concat
(sha256 chain-id)
(contract-hash)
)
(sha256 cid)
)
(sha256 verify-id)
)
(sha256 cap)
)
(unwrap-panic (to-consensus-buff? owner))
)
)
)
(define-private (nft-uri (token-id uint))
(concat
(concat
base-uri
(int-to-ascii token-id)
)
".json"
)
)