-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathBNS-V2.clar
1690 lines (1611 loc) · 82.8 KB
/
BNS-V2.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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;; title: BNS-V2
;; version: V-1
;; summary: Updated BNS contract, handles the creation of new namespaces and new names on each namespace
;; description:
;; traits
;; (new) Import SIP-09 NFT trait
(impl-trait .sip-09.nft-trait)
;; (new) Import a custom commission trait for handling commissions for NFT marketplaces functions
(use-trait commission-trait .commission-trait.commission)
;; token definition
;; (new) Define the non-fungible token (NFT) called BNS-V2 with unique identifiers as unsigned integers
(define-non-fungible-token BNS-V2 uint)
;; Time-to-live (TTL) constants for namespace preorders and name preorders, and the duration for name grace period.
;; The TTL for namespace and names preorders. (1 day)
(define-constant PREORDER-CLAIMABILITY-TTL u144)
;; The duration after revealing a namespace within which it must be launched. (1 year)
(define-constant NAMESPACE-LAUNCHABILITY-TTL u52595)
;; The grace period duration for name renewals post-expiration. (34 days)
(define-constant NAME-GRACE-PERIOD-DURATION u5000)
;; (new) The length of the hash should match this
(define-constant HASH160LEN u20)
;; Defines the price tiers for namespaces based on their lengths.
(define-constant NAMESPACE-PRICE-TIERS (list
u640000000000
u64000000000 u64000000000
u6400000000 u6400000000 u6400000000 u6400000000
u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000)
)
;; (new) Constant to store the token URI, allowing for metadata association with the NFT
(define-constant token-uri "test")
;; errors
(define-constant ERR-UNWRAP (err u101))
(define-constant ERR-NOT-AUTHORIZED (err u102))
(define-constant ERR-NOT-LISTED (err u103))
(define-constant ERR-WRONG-COMMISSION (err u104))
(define-constant ERR-LISTED (err u105))
(define-constant ERR-NO-NAME (err u106))
(define-constant ERR-HASH-MALFORMED (err u107))
(define-constant ERR-STX-BURNT-INSUFFICIENT (err u108))
(define-constant ERR-PREORDER-NOT-FOUND (err u109))
(define-constant ERR-CHARSET-INVALID (err u110))
(define-constant ERR-NAMESPACE-ALREADY-EXISTS (err u111))
(define-constant ERR-PREORDER-CLAIMABILITY-EXPIRED (err u112))
(define-constant ERR-NAMESPACE-NOT-FOUND (err u113))
(define-constant ERR-OPERATION-UNAUTHORIZED (err u114))
(define-constant ERR-NAMESPACE-ALREADY-LAUNCHED (err u115))
(define-constant ERR-NAMESPACE-PREORDER-LAUNCHABILITY-EXPIRED (err u116))
(define-constant ERR-NAMESPACE-NOT-LAUNCHED (err u117))
(define-constant ERR-NAME-NOT-AVAILABLE (err u118))
(define-constant ERR-NAMESPACE-BLANK (err u119))
(define-constant ERR-NAME-BLANK (err u120))
(define-constant ERR-NAME-REVOKED (err u121))
(define-constant ERR-NAME-PREORDERED-BEFORE-NAMESPACE-LAUNCH (err u122))
(define-constant ERR-NAMESPACE-HAS-MANAGER (err u123))
(define-constant ERR-OVERFLOW (err u124))
(define-constant ERR-NO-NAMESPACE-MANAGER (err u125))
(define-constant ERR-FAST-MINTED-BEFORE (err u126))
(define-constant ERR-PREORDERED-BEFORE (err u127))
(define-constant ERR-NAME-NOT-CLAIMABLE-YET (err u128))
(define-constant ERR-IMPORTED-BEFORE (err u129))
(define-constant ERR-LIFETIME-EQUAL-0 (err u130))
;; variables
;; (new) Counter to keep track of the last minted NFT ID, ensuring unique identifiers
(define-data-var bns-index uint u0)
;; maps
;; (new) Map to track market listings, associating NFT IDs with price and commission details
(define-map market uint {price: uint, commission: principal})
;; (new) Define a map to link NFT IDs to their respective names and namespaces.
(define-map index-to-name uint
{
name: (buff 48), namespace: (buff 20)
}
)
;; (new) Define a map to link names and namespaces to their respective NFT IDs.
(define-map name-to-index
{
name: (buff 48), namespace: (buff 20)
}
uint
)
;; (updated) Contains detailed properties of names, including registration and importation times, revocation status, and zonefile hash.
(define-map name-properties
{ name: (buff 48), namespace: (buff 20) }
{
registered-at: (optional uint),
imported-at: (optional uint),
;; Updated this to be a boolean, since we do not need know when it was revoked, only if it is revoked
revoked-at: bool,
zonefile-hash: (optional (buff 20)),
;; The fqn used to make the earliest preorder at any given point
hashed-salted-fqn-preorder: (optional (buff 20)),
;; Added this field in name-properties to know exactly who has the earliest preorder at any given point
preordered-by: (optional principal),
renewal-height: uint,
stx-burn: uint,
owner: principal,
}
)
;; (update) Stores properties of namespaces, including their import principals, reveal and launch times, and pricing functions.
(define-map namespaces (buff 20)
{
namespace-manager: (optional principal),
manager-transferable: bool,
manager-frozen: bool,
namespace-import: principal,
revealed-at: uint,
launched-at: (optional uint),
lifetime: uint,
can-update-price-function: bool,
price-function:
{
buckets: (list 16 uint),
base: uint,
coeff: uint,
nonalpha-discount: uint,
no-vowel-discount: uint
}
}
)
;; Records namespace preorder transactions with their creation times, and STX burned.
;; Removed the claimed field as it is not necessary
(define-map namespace-preorders
{ hashed-salted-namespace: (buff 20), buyer: principal }
{ created-at: uint, stx-burned: uint }
)
;; Tracks preorders, to avoid attacks
(define-map namespace-single-preorder (buff 20) bool)
;; Tracks preorders, to avoid attacks
(define-map name-single-preorder (buff 20) bool)
;; Tracks preorders for names, including their creation times, and STX burned.
(define-map name-preorders
{ hashed-salted-fqn: (buff 20), buyer: principal }
{ created-at: uint, stx-burned: uint, claimed: bool}
)
;; It maps a user's principal to the ID of their primary name.
(define-map primary-name principal uint)
;; read-only
;; @desc (new) SIP-09 compliant function to get the last minted token's ID
(define-read-only (get-last-token-id)
;; Returns the current value of bns-index variable, which tracks the last token ID
(ok (var-get bns-index))
)
(define-read-only (get-renewal-height (id uint))
(let
(
(name-namespace (unwrap! (get-bns-from-id id) ERR-NO-NAME))
(namespace-props (unwrap! (map-get? namespaces (get namespace name-namespace)) ERR-NAMESPACE-NOT-FOUND))
(name-props (unwrap! (map-get? name-properties name-namespace) ERR-NO-NAME))
(renewal-height (get renewal-height name-props))
(namespace-lifetime (get lifetime namespace-props))
)
;; Check if the namespace requires renewals
(asserts! (not (is-eq namespace-lifetime u0)) ERR-LIFETIME-EQUAL-0)
;; If the check passes then check the renewal-height of the name
(ok
(if (is-eq renewal-height u0)
;; If it is true then it means it was imported so return the namespace launch blockheight + lifetime
(+ (unwrap! (get launched-at namespace-props) ERR-NAMESPACE-NOT-LAUNCHED) namespace-lifetime)
renewal-height
)
)
)
)
;; @desc (new) SIP-09 compliant function to get token URI
(define-read-only (get-token-uri (id uint))
;; Returns a predefined set URI for the token metadata
(ok (some token-uri))
)
;; @desc (new) SIP-09 compliant function to get the owner of a specific token by its ID
(define-read-only (get-owner (id uint))
;; Check and return the owner of the specified NFT
(ok (nft-get-owner? BNS-V2 id))
)
;; Read-only function `get-namespace-price` calculates the registration price for a namespace based on its length.
;; @params:
;; namespace (buff 20): The namespace for which the price is being calculated.
(define-read-only (get-namespace-price (namespace (buff 20)))
(let
(
;; Calculate the length of the namespace.
(namespace-len (len namespace))
)
;; Ensure the namespace is not blank, its length is greater than 0.
(asserts! (> namespace-len u0) ERR-NAMESPACE-BLANK)
;; Retrieve the price for the namespace based on its length from the NAMESPACE-PRICE-TIERS list.
;; The price tier is determined by the minimum of 7 or the namespace length minus one.
(ok (unwrap! (element-at NAMESPACE-PRICE-TIERS (min u7 (- namespace-len u1))) ERR-UNWRAP))
)
)
;; Read-only function `get-name-price` calculates the registration price for a name based on the price buckets of the namespace
;; @params:
;; namespace (buff 20): The namespace for which the price is being calculated.
;; name (buff 48): The name for which the price is being calculated.
(define-read-only (get-name-price (namespace (buff 20)) (name (buff 48)))
(let
(
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
)
(ok (compute-name-price name (get price-function namespace-props)))
)
)
;; Read-only function `can-namespace-be-registered` checks if a namespace is available for registration.
;; @params:
;; namespace (buff 20): The namespace being checked for availability.
(define-read-only (can-namespace-be-registered (namespace (buff 20)))
;; Returns the result of `is-namespace-available` directly, indicating if the namespace can be registered.
(ok (is-namespace-available namespace))
)
;; Read-only function `get-namespace-properties` for retrieving properties of a specific namespace.
;; @params:
;; namespace (buff 20): The namespace whose properties are being queried.
(define-read-only (get-namespace-properties (namespace (buff 20)))
(let
(
;; Fetch the properties of the specified namespace from the `namespaces` map.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
)
;; Returns the namespace along with its associated properties.
(ok { namespace: namespace, properties: namespace-props })
)
)
;; Read only function to get name properties
(define-read-only (get-bns-info (name (buff 48)) (namespace (buff 20)))
(map-get? name-properties {name: name, namespace: namespace})
)
;; (new) Defines a read-only function to fetch the unique ID of a BNS name given its name and the namespace it belongs to.
(define-read-only (get-id-from-bns (name (buff 48)) (namespace (buff 20)))
;; Attempts to retrieve the ID from the 'name-to-index' map using the provided name and namespace as the key.
(map-get? name-to-index {name: name, namespace: namespace})
)
;; (new) Defines a read-only function to fetch the unique ID of a BNS name given its name and the namespace it belongs to.
(define-read-only (get-bns-from-id (id uint))
;; Attempts to retrieve the ID from the 'name-to-index' map using the provided name and namespace as the key.
(map-get? index-to-name id)
)
;; (new) Fetcher for primary name
(define-read-only (get-primary-name (owner principal))
(map-get? primary-name owner)
)
;; public functions
;; @desc (new) SIP-09 compliant function to transfer a token from one owner to another.
;; @param id: ID of the NFT being transferred.
;; @param owner: Principal of the current owner of the NFT.
;; @param recipient: Principal of the recipient of the NFT.
(define-public (transfer (id uint) (owner principal) (recipient principal))
(let
(
;; Get the name and namespace of the NFT.
(name-and-namespace (unwrap! (get-bns-from-id id) ERR-NO-NAME))
(namespace (get namespace name-and-namespace))
(name (get name name-and-namespace))
;; Get namespace properties and manager.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
(manager-transfers (get manager-transferable namespace-props))
;; Get name properties and owner.
(name-props (unwrap! (map-get? name-properties name-and-namespace) ERR-NO-NAME))
(registered-at-value (get registered-at name-props))
(nft-current-owner (unwrap! (nft-get-owner? BNS-V2 id) ERR-NO-NAME))
)
;; First check if the name was registered
(match registered-at-value
is-registered
;; If it was registered, check if registered-at is lower than current blockheight
;; This check works to make sure that if a name is fast-claimed they have to wait 1 block to transfer it
(asserts! (< is-registered burn-block-height) ERR-OPERATION-UNAUTHORIZED)
;; If it is not registered then continue
true
)
;; Check that the namespace is launched
(asserts! (is-some (get launched-at namespace-props)) ERR-NAMESPACE-NOT-LAUNCHED)
;; Check that the name is not revoked
(asserts! (not (get revoked-at name-props)) ERR-NAME-REVOKED)
;; Check owner and recipient is not the same
(asserts! (not (is-eq nft-current-owner recipient)) ERR-OPERATION-UNAUTHORIZED)
;; We only need to check if manager transfers are true or false, if true then they have to do transfers through the manager contract that calls into mng-transfer, if false then they can call into this function
(asserts! (not manager-transfers) ERR-NOT-AUTHORIZED)
;; Check tx-sender or contract-caller
(asserts! (or (is-eq tx-sender nft-current-owner) (is-eq contract-caller nft-current-owner)) ERR-NOT-AUTHORIZED)
;; Check if in fact the owner is-eq to nft-current-owner
(asserts! (is-eq owner nft-current-owner) ERR-NOT-AUTHORIZED)
;; Ensures the NFT is not currently listed in the market.
(asserts! (is-none (map-get? market id)) ERR-LISTED)
;; Update the name properties with the new owner and reset the zonefile hash.
(map-set name-properties name-and-namespace (merge name-props {zonefile-hash: none, owner: recipient}))
;; Update primary name if needed for owner
(update-primary-name-owner id owner)
;; Update primary name if needed for recipient
(update-primary-name-recipient id recipient)
;; Execute the NFT transfer.
(nft-transfer? BNS-V2 id nft-current-owner recipient)
)
)
;; @desc (new) manager function to be called by managed namespaces that allows manager transfers.
;; @param id: ID of the NFT being transferred.
;; @param owner: Principal of the current owner of the NFT.
;; @param recipient: Principal of the recipient of the NFT.
(define-public (mng-transfer (id uint) (owner principal) (recipient principal))
(let
(
;; Get the name and namespace of the NFT.
(name-and-namespace (unwrap! (get-bns-from-id id) ERR-NO-NAME))
(namespace (get namespace name-and-namespace))
(name (get name name-and-namespace))
;; Get namespace properties and manager.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
(manager-transfers (get manager-transferable namespace-props))
(manager (get namespace-manager namespace-props))
;; Get name properties and owner.
(name-props (unwrap! (map-get? name-properties name-and-namespace) ERR-NO-NAME))
(registered-at-value (get registered-at name-props))
(nft-current-owner (unwrap! (nft-get-owner? BNS-V2 id) ERR-NO-NAME))
)
;; First check if the name was registered
(match registered-at-value
is-registered
;; If it was registered, check if registered-at is lower than current blockheight
;; This check works to make sure that if a name is fast-claimed they have to wait 1 block to transfer it
(asserts! (< is-registered burn-block-height) ERR-OPERATION-UNAUTHORIZED)
;; If it is not registered then continue
true
)
;; Check that the namespace is launched
(asserts! (is-some (get launched-at namespace-props)) ERR-NAMESPACE-NOT-LAUNCHED)
;; Check that the name is not revoked
(asserts! (not (get revoked-at name-props)) ERR-NAME-REVOKED)
;; Check owner and recipient is not the same
(asserts! (not (is-eq nft-current-owner recipient)) ERR-OPERATION-UNAUTHORIZED)
;; We only need to check if manager transfers are true or false, if true then continue, if false then they can call into `transfer` function
(asserts! manager-transfers ERR-NOT-AUTHORIZED)
;; Check tx-sender or contract-caller, we unwrap-panic because if manager-transfers is true then there has to be a manager
(asserts! (is-eq contract-caller (unwrap-panic manager)) ERR-NOT-AUTHORIZED)
;; Check if in fact the owner is-eq to nft-current-owner
(asserts! (is-eq owner nft-current-owner) ERR-NOT-AUTHORIZED)
;; Ensures the NFT is not currently listed in the market.
(asserts! (is-none (map-get? market id)) ERR-LISTED)
;; Update primary name if needed for owner
(update-primary-name-owner id owner)
;; Update primary name if needed for recipient
(update-primary-name-recipient id recipient)
;; Update the name properties with the new owner and reset the zonefile hash.
(map-set name-properties name-and-namespace (merge name-props {zonefile-hash: none, owner: recipient}))
;; Execute the NFT transfer.
(nft-transfer? BNS-V2 id nft-current-owner recipient)
)
)
;; @desc (new) Function to list an NFT for sale.
;; @param id: ID of the NFT being listed.
;; @param price: Listing price.
;; @param comm-trait: Address of the commission-trait.
(define-public (list-in-ustx (id uint) (price uint) (comm-trait <commission-trait>))
(let
(
;; Get the name and namespace of the NFT.
(name-and-namespace (unwrap! (map-get? index-to-name id) ERR-NO-NAME))
(namespace (get namespace name-and-namespace))
;; Get namespace properties and manager.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
(namespace-manager (get namespace-manager namespace-props))
;; Get name properties and registered-at value.
(name-props (unwrap! (map-get? name-properties name-and-namespace) ERR-NO-NAME))
(registered-at-value (get registered-at name-props))
;; Creates a listing record with price and commission details
(listing {price: price, commission: (contract-of comm-trait)})
)
;; Checks if the name was registered
(match registered-at-value
is-registered
;; If it was registered, check if registered-at is lower than current blockheight
;; Same as transfers, this check works to make sure that if a name is fast-claimed they have to wait 1 block to list it
(asserts! (< is-registered burn-block-height) ERR-OPERATION-UNAUTHORIZED)
;; If it is not registered then continue
true
)
;; Check if there is a namespace manager
(match namespace-manager
manager
;; If there is then check that the contract-caller is the manager
(asserts! (is-eq manager contract-caller) ERR-NOT-AUTHORIZED)
;; If there isn't assert that the owner is the tx-sender
(asserts! (is-eq (some tx-sender) (nft-get-owner? BNS-V2 id)) ERR-NOT-AUTHORIZED)
)
;; Updates the market map with the new listing details
(map-set market id listing)
;; Prints listing details
(ok (print (merge listing {a: "list-in-ustx", id: id})))
)
)
;; @desc (new) Function to remove an NFT listing from the market.
;; @param id: ID of the NFT being unlisted.
(define-public (unlist-in-ustx (id uint))
(let
(
;; Get the name and namespace of the NFT.
(name-and-namespace (unwrap! (map-get? index-to-name id) ERR-NO-NAME))
(namespace (get namespace name-and-namespace))
;; Verify if the NFT is listed in the market.
(market-map (unwrap! (map-get? market id) ERR-NOT-LISTED))
;; Get namespace properties and manager.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
(namespace-manager (get namespace-manager namespace-props))
)
;; Check if there is a namespace manager
(match namespace-manager
manager
;; If there is then check that the contract-caller is the manager
(asserts! (is-eq manager contract-caller) ERR-NOT-AUTHORIZED)
;; If there isn't assert that the owner is the tx-sender
(asserts! (is-eq (some tx-sender) (nft-get-owner? BNS-V2 id)) ERR-NOT-AUTHORIZED)
)
;; Deletes the listing from the market map
(map-delete market id)
;; Prints unlisting details
(ok (print {a: "unlist-in-ustx", id: id}))
)
)
;; @desc (new) Function to buy an NFT listed for sale, transferring ownership and handling commission.
;; @param id: ID of the NFT being purchased.
;; @param comm-trait: Address of the commission-trait.
(define-public (buy-in-ustx (id uint) (comm-trait <commission-trait>))
(let
(
;; Retrieves current owner and listing details
(owner (unwrap! (nft-get-owner? BNS-V2 id) ERR-NO-NAME))
(listing (unwrap! (map-get? market id) ERR-NOT-LISTED))
(price (get price listing))
)
;; Verifies the commission details match the listing
(asserts! (is-eq (contract-of comm-trait) (get commission listing)) ERR-WRONG-COMMISSION)
;; Transfers STX from buyer to seller
(try! (stx-transfer? price tx-sender owner))
;; Handle commission payment
(try! (contract-call? comm-trait pay id price))
;; Transfers the NFT to the buyer
;; This function differs from the `transfer` method by not checking who the tx-sender or contract-caller is, otherwise trasnfers would never be executed
(try! (purchase-transfer id owner tx-sender))
;; Removes the listing from the market map
(map-delete market id)
;; Prints purchase details
(ok (print {a: "buy-in-ustx", id: id}))
)
)
;; @desc (new) Sets the primary name for the caller to a specific BNS name they own.
;; @param primary-name-id: ID of the name to be set as primary.
(define-public (set-primary-name (primary-name-id uint))
(begin
;; Verify the tx-sender is the owner of the name.
(asserts! (is-eq (unwrap! (nft-get-owner? BNS-V2 primary-name-id) ERR-NO-NAME) tx-sender) ERR-NOT-AUTHORIZED)
;; Update the tx-sender's primary name.
(map-set primary-name tx-sender primary-name-id)
;; Return true upon successful execution.
(ok true)
)
)
;; @desc (new) Defines a public function to burn an NFT, under managed namespaces.
;; @param id: ID of the NFT to be burned.
(define-public (mng-burn (id uint))
(let
(
;; Get the name details associated with the given ID.
(name-and-namespace (unwrap! (get-bns-from-id id) ERR-NO-NAME))
;; Get the owner of the name.
(owner (unwrap! (nft-get-owner? BNS-V2 id) ERR-UNWRAP))
)
;; Ensure the caller is the current namespace manager.
(asserts! (is-eq contract-caller (unwrap! (get namespace-manager (unwrap! (map-get? namespaces (get namespace name-and-namespace)) ERR-NAMESPACE-NOT-FOUND)) ERR-NO-NAMESPACE-MANAGER)) ERR-NOT-AUTHORIZED)
;; Unlist the NFT if it is listed.
(match (map-get? market id)
listed-name
(map-delete market id)
true
)
;; Update primary name if needed for the owner of the name
(update-primary-name-owner id owner)
;; Delete the name from all maps:
;; Remove the name-to-index.
(map-delete name-to-index name-and-namespace)
;; Remove the index-to-name.
(map-delete index-to-name id)
;; Remove the name-properties.
(map-delete name-properties name-and-namespace)
;; Executes the burn operation for the specified NFT.
(nft-burn? BNS-V2 id (unwrap! (nft-get-owner? BNS-V2 id) ERR-UNWRAP))
)
)
;; @desc (new) Transfers the management role of a specific namespace to a new principal.
;; @param new-manager: Principal of the new manager.
;; @param namespace: Buffer of the namespace.
(define-public (mng-manager-transfer (new-manager (optional principal)) (namespace (buff 20)))
(let
(
;; Retrieve namespace properties and current manager.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
)
;; Ensure the caller is the current namespace manager.
(asserts! (is-eq contract-caller (unwrap! (get namespace-manager namespace-props) ERR-NO-NAMESPACE-MANAGER)) ERR-NOT-AUTHORIZED)
;; Ensure manager can be changed
(asserts! (not (get manager-frozen namespace-props)) ERR-NOT-AUTHORIZED)
;; Update the namespace manager to the new manager.
(ok
(map-set namespaces namespace
(merge
namespace-props
{namespace-manager: new-manager}
)
)
)
)
)
;; @desc (new) freezes the ability to make manager transfers
;; @param namespace: Buffer of the namespace.
(define-public (freeze-manager (namespace (buff 20)))
(let
(
;; Retrieve namespace properties and current manager.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
)
;; Ensure the caller is the current namespace manager.
(asserts! (is-eq contract-caller (unwrap! (get namespace-manager namespace-props) ERR-NO-NAMESPACE-MANAGER)) ERR-NOT-AUTHORIZED)
;; Update the namespace manager to the new manager.
(ok
(map-set namespaces namespace
(merge
namespace-props
{manager-frozen: true}
)
)
)
)
)
;;;; NAMESPACES
;; @desc Public function `namespace-preorder` initiates the registration process for a namespace by sending a transaction with a salted hash of the namespace.
;; This transaction burns the registration fee as a commitment.
;; @params: hashed-salted-namespace (buff 20): The hashed and salted namespace being preordered.
;; @params: stx-to-burn (uint): The amount of STX tokens to be burned as part of the preorder process.
(define-public (namespace-preorder (hashed-salted-namespace (buff 20)) (stx-to-burn uint))
(begin
;; Validate that the hashed-salted-namespace is exactly 20 bytes long.
(asserts! (is-eq (len hashed-salted-namespace) HASH160LEN) ERR-HASH-MALFORMED)
;; Check if the same hashed-salted-fqn has been used before
(asserts! (is-none (map-get? namespace-single-preorder hashed-salted-namespace)) ERR-PREORDERED-BEFORE)
;; Confirm that the STX amount to be burned is positive
(asserts! (> stx-to-burn u0) ERR-STX-BURNT-INSUFFICIENT)
;; Execute the token burn operation.
(try! (stx-burn? stx-to-burn tx-sender))
;; Record the preorder details in the `namespace-preorders` map
(map-set namespace-preorders
{ hashed-salted-namespace: hashed-salted-namespace, buyer: tx-sender }
{ created-at: burn-block-height, stx-burned: stx-to-burn }
)
;; Sets the map with just the hashed-salted-namespace as the key
(map-set namespace-single-preorder hashed-salted-namespace true)
;; Return the block height at which the preorder claimability expires.
(ok (+ burn-block-height PREORDER-CLAIMABILITY-TTL))
)
)
;; @desc Public function `namespace-reveal` completes the second step in the namespace registration process.
;; It associates the revealed namespace with its corresponding preorder, establishes the namespace's pricing function, and sets its lifetime and ownership details.
;; @param: namespace (buff 20): The namespace being revealed.
;; @param: namespace-salt (buff 20): The salt used during the preorder to generate a unique hash.
;; @param: p-func-base, p-func-coeff, p-func-b1 to p-func-b16: Parameters defining the price function for registering names within this namespace.
;; @param: p-func-non-alpha-discount (uint): Discount applied to names with non-alphabetic characters.
;; @param: p-func-no-vowel-discount (uint): Discount applied to names without vowels.
;; @param: lifetime (uint): Duration that names within this namespace are valid before needing renewal.
;; @param: namespace-import (principal): The principal authorized to import names into this namespace.
;; @param: namespace-manager (optional principal): The principal authorized to manage the namespace.
(define-public (namespace-reveal
(namespace (buff 20))
(namespace-salt (buff 20))
(p-func-base uint)
(p-func-coeff uint)
(p-func-b1 uint)
(p-func-b2 uint)
(p-func-b3 uint)
(p-func-b4 uint)
(p-func-b5 uint)
(p-func-b6 uint)
(p-func-b7 uint)
(p-func-b8 uint)
(p-func-b9 uint)
(p-func-b10 uint)
(p-func-b11 uint)
(p-func-b12 uint)
(p-func-b13 uint)
(p-func-b14 uint)
(p-func-b15 uint)
(p-func-b16 uint)
(p-func-non-alpha-discount uint)
(p-func-no-vowel-discount uint)
(lifetime uint)
(namespace-import principal)
(namespace-manager (optional principal))
(can-update-price bool)
(manager-transfers bool)
(manager-frozen bool)
)
(let
(
;; Generate the hashed, salted namespace identifier to match with its preorder.
(hashed-salted-namespace (hash160 (concat namespace namespace-salt)))
;; Define the price function based on the provided parameters.
(price-function
{
buckets: (list p-func-b1 p-func-b2 p-func-b3 p-func-b4 p-func-b5 p-func-b6 p-func-b7 p-func-b8 p-func-b9 p-func-b10 p-func-b11 p-func-b12 p-func-b13 p-func-b14 p-func-b15 p-func-b16),
base: p-func-base,
coeff: p-func-coeff,
nonalpha-discount: p-func-non-alpha-discount,
no-vowel-discount: p-func-no-vowel-discount
}
)
;; Retrieve the preorder record to ensure it exists and is valid for the revealing namespace.
(preorder (unwrap! (map-get? namespace-preorders { hashed-salted-namespace: hashed-salted-namespace, buyer: tx-sender }) ERR-PREORDER-NOT-FOUND))
;; Calculate the namespace's registration price for validation.
(namespace-price (try! (get-namespace-price namespace)))
)
;; Ensure the namespace consists of valid characters only.
(asserts! (not (has-invalid-chars namespace)) ERR-CHARSET-INVALID)
;; Check that the namespace is available for reveal.
(asserts! (unwrap! (can-namespace-be-registered namespace) ERR-NAMESPACE-ALREADY-EXISTS) ERR-NAMESPACE-ALREADY-EXISTS)
;; Verify the burned amount during preorder meets or exceeds the namespace's registration price.
(asserts! (>= (get stx-burned preorder) namespace-price) ERR-STX-BURNT-INSUFFICIENT)
;; Confirm the reveal action is performed within the allowed timeframe from the preorder.
(asserts! (< burn-block-height (+ (get created-at preorder) PREORDER-CLAIMABILITY-TTL)) ERR-PREORDER-CLAIMABILITY-EXPIRED)
;; Ensure at least 1 block has passed after the preorder to avoid namespace sniping.
(asserts! (>= burn-block-height (+ (get created-at preorder) u1)) ERR-OPERATION-UNAUTHORIZED)
;; Check if the namespace manager is assigned
(match namespace-manager
namespace-m
;; If namespace-manager is assigned, then assign everything except the lifetime, that is set to u0 sinces renewals will be made in the namespace manager contract and set the can update price function to false, since no changes will ever need to be made there.
(map-set namespaces namespace
{
namespace-manager: namespace-manager,
manager-transferable: manager-transfers,
manager-frozen: manager-frozen,
namespace-import: namespace-import,
revealed-at: burn-block-height,
launched-at: none,
lifetime: u0,
can-update-price-function: can-update-price,
price-function: price-function
}
)
;; If no manager is assigned
(map-set namespaces namespace
{
namespace-manager: none,
manager-transferable: manager-transfers,
manager-frozen: manager-frozen,
namespace-import: namespace-import,
revealed-at: burn-block-height,
launched-at: none,
lifetime: lifetime,
can-update-price-function: can-update-price,
price-function: price-function
}
)
)
;; Confirm successful reveal of the namespace
(ok true)
)
)
;; @desc Public function `namespace-launch` marks a namespace as launched and available for public name registrations.
;; @param: namespace (buff 20): The namespace to be launched and made available for public registrations.
(define-public (namespace-launch (namespace (buff 20)))
(let
(
;; Retrieve the properties of the namespace to ensure it exists and to check its current state.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
)
;; Ensure the transaction sender is the namespace's designated import principal.
(asserts! (is-eq (get namespace-import namespace-props) tx-sender) ERR-OPERATION-UNAUTHORIZED)
;; Verify the namespace has not already been launched.
(asserts! (is-none (get launched-at namespace-props)) ERR-NAMESPACE-ALREADY-LAUNCHED)
;; Confirm that the action is taken within the permissible time frame since the namespace was revealed.
(asserts! (< burn-block-height (+ (get revealed-at namespace-props) NAMESPACE-LAUNCHABILITY-TTL)) ERR-NAMESPACE-PREORDER-LAUNCHABILITY-EXPIRED)
;; Update the `namespaces` map with the newly launched status.
(map-set namespaces namespace (merge namespace-props { launched-at: (some burn-block-height) }))
;; Emit an event to indicate the namespace is now ready and launched.
(print { namespace: namespace, status: "ready", properties: (map-get? namespaces namespace) })
;; Confirm the successful launch of the namespace.
(ok true)
)
)
;; @desc (new) Public function `turn-off-manager-transfers` disables manager transfers for a namespace (callable only once).
;; @param: namespace (buff 20): The namespace for which manager transfers will be disabled.
(define-public (turn-off-manager-transfers (namespace (buff 20)))
(let
(
;; Retrieve the properties of the namespace and manager.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
(namespace-manager (unwrap! (get namespace-manager namespace-props) ERR-NO-NAMESPACE-MANAGER))
)
;; Ensure the function caller is the namespace manager.
(asserts! (is-eq contract-caller namespace-manager) ERR-NOT-AUTHORIZED)
;; Disable manager transfers.
(map-set namespaces namespace (merge namespace-props {manager-transferable: false}))
;; Confirm successful execution.
(ok true)
)
)
;; @desc Public function `name-import` allows the insertion of names into a namespace that has been revealed but not yet launched.
;; This facilitates pre-populating the namespace with specific names, assigning owners and zone file hashes to them.
;; @param: namespace (buff 20): The namespace into which the name is being imported.
;; @param: name (buff 48): The name being imported into the namespace.
;; @param: beneficiary (principal): The principal who will own the imported name.
;; @param: zonefile-hash (buff 20): The hash of the zone file associated with the imported name.
;; @param: stx-burn (uint): The amount of STX tokens to be burned as part of the import process.
(define-public (name-import (namespace (buff 20)) (name (buff 48)) (beneficiary principal) (zonefile-hash (buff 20)))
(let
(
;; Fetch properties of the specified namespace.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
;; Fetch the latest index to mint
(current-mint (+ (var-get bns-index) u1))
(price (if (is-none (get namespace-manager namespace-props))
(try! (compute-name-price name (get price-function namespace-props)))
u0
)
)
)
;; Ensure the name is not already registered.
(asserts! (is-none (map-get? name-properties {name: name, namespace: namespace})) ERR-NAME-NOT-AVAILABLE)
;; Verify that the name contains only valid characters.
(asserts! (not (has-invalid-chars name)) ERR-CHARSET-INVALID)
;; Ensure the transaction sender is the namespace's designated import principal or the namespace manager
(asserts! (or (is-eq (get namespace-import namespace-props) tx-sender) (is-eq (get namespace-manager namespace-props) (some contract-caller))) ERR-OPERATION-UNAUTHORIZED)
;; Check that the namespace has not been launched yet, as names can only be imported to namespaces that are revealed but not launched.
(asserts! (is-none (get launched-at namespace-props)) ERR-NAMESPACE-ALREADY-LAUNCHED)
;; Confirm that the import is occurring within the allowed timeframe since the namespace was revealed.
(asserts! (< burn-block-height (+ (get revealed-at namespace-props) NAMESPACE-LAUNCHABILITY-TTL)) ERR-NAMESPACE-PREORDER-LAUNCHABILITY-EXPIRED)
;; Set the name properties
(map-set name-properties {name: name, namespace: namespace}
{
registered-at: none,
imported-at: (some burn-block-height),
revoked-at: false,
zonefile-hash: (some zonefile-hash),
hashed-salted-fqn-preorder: none,
preordered-by: none,
renewal-height: u0,
stx-burn: price,
owner: beneficiary,
}
)
(map-set name-to-index {name: name, namespace: namespace} current-mint)
(map-set index-to-name current-mint {name: name, namespace: namespace})
;; Update primary name if needed for send-to
(update-primary-name-recipient current-mint beneficiary)
;; Update the index of the minting
(var-set bns-index current-mint)
;; Mint the name to the beneficiary
(try! (nft-mint? BNS-V2 current-mint beneficiary))
;; Log the new name registration
(print
{
topic: "new-name",
owner: beneficiary,
name: {name: name, namespace: namespace},
id: current-mint,
}
)
;; Confirm successful import of the name.
(ok true)
)
)
;; @desc Public function `namespace-update-price` updates the pricing function for a specific namespace.
;; @param: namespace (buff 20): The namespace for which the price function is being updated.
;; @param: p-func-base (uint): The base price used in the pricing function.
;; @param: p-func-coeff (uint): The coefficient used in the pricing function.
;; @param: p-func-b1 to p-func-b16 (uint): The bucket-specific multipliers for the pricing function.
;; @param: p-func-non-alpha-discount (uint): The discount applied for non-alphabetic characters.
;; @param: p-func-no-vowel-discount (uint): The discount applied when no vowels are present.
(define-public (namespace-update-price
(namespace (buff 20))
(p-func-base uint)
(p-func-coeff uint)
(p-func-b1 uint)
(p-func-b2 uint)
(p-func-b3 uint)
(p-func-b4 uint)
(p-func-b5 uint)
(p-func-b6 uint)
(p-func-b7 uint)
(p-func-b8 uint)
(p-func-b9 uint)
(p-func-b10 uint)
(p-func-b11 uint)
(p-func-b12 uint)
(p-func-b13 uint)
(p-func-b14 uint)
(p-func-b15 uint)
(p-func-b16 uint)
(p-func-non-alpha-discount uint)
(p-func-no-vowel-discount uint)
)
(let
(
;; Retrieve the current properties of the namespace.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
;; Construct the new price function.
(price-function
{
buckets: (list p-func-b1 p-func-b2 p-func-b3 p-func-b4 p-func-b5 p-func-b6 p-func-b7 p-func-b8 p-func-b9 p-func-b10 p-func-b11 p-func-b12 p-func-b13 p-func-b14 p-func-b15 p-func-b16),
base: p-func-base,
coeff: p-func-coeff,
nonalpha-discount: p-func-non-alpha-discount,
no-vowel-discount: p-func-no-vowel-discount
}
)
)
(match (get namespace-manager namespace-props)
manager
;; Ensure that the transaction sender is the namespace's designated import principal.
(asserts! (is-eq manager contract-caller) ERR-OPERATION-UNAUTHORIZED)
;; Ensure that the transaction sender is the namespace's designated import principal.
(asserts! (or (is-eq (get namespace-import namespace-props) tx-sender) (is-eq (get namespace-import namespace-props) contract-caller)) ERR-OPERATION-UNAUTHORIZED)
)
;; Verify the namespace's price function can still be updated.
(asserts! (get can-update-price-function namespace-props) ERR-OPERATION-UNAUTHORIZED)
;; Update the namespace's record in the `namespaces` map with the new price function.
(map-set namespaces namespace (merge namespace-props { price-function: price-function }))
;; Confirm the successful update of the price function.
(ok true)
)
)
;; @desc Public function `namespace-freeze-price` disables the ability to update the price function for a given namespace.
;; @param: namespace (buff 20): The target namespace for which the price function update capability is being revoked.
(define-public (namespace-freeze-price (namespace (buff 20)))
(let
(
;; Retrieve the properties of the specified namespace to verify its existence and fetch its current settings.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
)
(match (get namespace-manager namespace-props)
manager
;; Ensure that the transaction sender is the same as the namespace's designated import principal.
(asserts! (is-eq manager contract-caller) ERR-OPERATION-UNAUTHORIZED)
;; Ensure that the transaction sender is the same as the namespace's designated import principal.
(asserts! (or (is-eq (get namespace-import namespace-props) tx-sender) (is-eq (get namespace-import namespace-props) contract-caller)) ERR-OPERATION-UNAUTHORIZED)
)
;; Update the namespace properties in the `namespaces` map, setting `can-update-price-function` to false.
(map-set namespaces namespace
(merge namespace-props { can-update-price-function: false })
)
;; Return a success confirmation.
(ok true)
)
)
;; @desc (new) A 'fast' one-block registration function: (name-claim-fast)
;; Warning: this *is* snipeable, for a slower but un-snipeable claim, use the pre-order & register functions
;; @param: name (buff 48): The name being claimed.
;; @param: namespace (buff 20): The namespace under which the name is being claimed.
;; @param: zonefile-hash (buff 20): The hash of the zone file associated with the name.
;; @param: stx-burn (uint): The amount of STX to burn for the claim.
;; @param: send-to (principal): The principal to whom the name will be sent.
(define-public (name-claim-fast (name (buff 48)) (namespace (buff 20)) (zonefile-hash (buff 20)) (send-to principal))
(let
(
;; Retrieve namespace properties.
(namespace-props (unwrap! (map-get? namespaces namespace) ERR-NAMESPACE-NOT-FOUND))
(current-namespace-manager (get namespace-manager namespace-props))
;; Calculates the ID for the new name to be minted.
(id-to-be-minted (+ (var-get bns-index) u1))
;; Check if the name already exists.
(name-props (map-get? name-properties {name: name, namespace: namespace}))
;; new to get the price of the name
(name-price (if (is-none current-namespace-manager)
(try! (compute-name-price name (get price-function namespace-props)))
u0
)
)
)
;; Ensure the name is not already registered.
(asserts! (is-none name-props) ERR-NAME-NOT-AVAILABLE)
;; Verify that the name contains only valid characters.
(asserts! (not (has-invalid-chars name)) ERR-CHARSET-INVALID)
;; Ensure that the namespace is launched
(asserts! (is-some (get launched-at namespace-props)) ERR-NAMESPACE-NOT-LAUNCHED)
;; Check namespace manager
(match current-namespace-manager
manager
;; If manager, check contract-caller is manager
(asserts! (is-eq contract-caller manager) ERR-NOT-AUTHORIZED)
;; If no manager
(begin
;; Asserts tx-sender or contract-caller is the send-to
(asserts! (or (is-eq tx-sender send-to) (is-eq contract-caller send-to)) ERR-NOT-AUTHORIZED)
;; Updated this to burn the actual ammount of the name-price
(try! (stx-burn? name-price send-to))
)
)
;; Update the index
(var-set bns-index id-to-be-minted)
;; Sets properties for the newly registered name.
(map-set name-properties
{
name: name, namespace: namespace
}
{
registered-at: (some (+ burn-block-height u1)),
imported-at: none,
revoked-at: false,
zonefile-hash: (some zonefile-hash),
hashed-salted-fqn-preorder: none,
preordered-by: none,
;; Updated this to actually start with the registered-at date/block, and also to be u0 if it is a managed namespace
renewal-height: (if (is-some current-namespace-manager)
u0
(+ (get lifetime namespace-props) burn-block-height u1)
),
stx-burn: name-price,
owner: send-to,
}
)
(map-set name-to-index {name: name, namespace: namespace} id-to-be-minted)
(map-set index-to-name id-to-be-minted {name: name, namespace: namespace})
;; Update primary name if needed for send-to
(update-primary-name-recipient id-to-be-minted send-to)
;; Mints the new BNS name.
(try! (nft-mint? BNS-V2 id-to-be-minted send-to))
;; Log the new name registration
(print
{
topic: "new-name",
owner: send-to,
name: {name: name, namespace: namespace},
id: id-to-be-minted,
}
)
;; Signals successful completion.
(ok id-to-be-minted)
)
)
;; @desc Defines a public function `name-preorder` for preordering BNS names by burning the registration fee and submitting the salted hash.
;; Callable by anyone; the actual check for authorization happens in the `name-register` function.
;; @param: hashed-salted-fqn (buff 20): The hashed and salted fully qualified name.
;; @param: stx-to-burn (uint): The amount of STX to burn for the preorder.
(define-public (name-preorder (hashed-salted-fqn (buff 20)) (stx-to-burn uint))
(begin
;; Validate the length of the hashed-salted FQN.
(asserts! (is-eq (len hashed-salted-fqn) HASH160LEN) ERR-HASH-MALFORMED)
;; Ensures that the amount of STX specified to burn is greater than zero.
(asserts! (> stx-to-burn u0) ERR-STX-BURNT-INSUFFICIENT)
;; Check if the same hashed-salted-fqn has been used before
(asserts! (is-none (map-get? name-single-preorder hashed-salted-fqn)) ERR-PREORDERED-BEFORE)
;; Transfers the specified amount of stx to the BNS contract to burn on register
(try! (stx-transfer? stx-to-burn tx-sender .BNS-V2))
;; Records the preorder in the 'name-preorders' map.
(map-set name-preorders
{ hashed-salted-fqn: hashed-salted-fqn, buyer: tx-sender }
{ created-at: burn-block-height, stx-burned: stx-to-burn, claimed: false}
)