Kind Realm (renderable)
Name item
Namespace akkadia / beta
Exported functions 18
Module gno.land/r/akkadia/beta/item
gno 0.9 item.gno gno
⧉
1 package item 2 3 import ( 4 "chain/runtime/unsafe" 5 "strconv" 6 7 "gno.land/p/akkadia/beta/accesscontrol" 8 BalanceOf (owner string, tokenID string) int64
Burn (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, from string, tokenID string, amount int64)
BurnFromRealm (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, from string, tokenID string, amount int64)
GetListLimit () int
GetOwnedCount (owner string) int
IsApprovedForAll (owner string, operator string) bool
IsMinterRealm (addr string) bool
ListByOwner (owner string, page int, count int) []map[string]string
Render (iURL string) string
SafeMint (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, recipient string, tokenID string, amount int64)
SafeMintFromRealm (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, recipient string, tokenID string, amount int64)
SafeTransferFrom (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, from string, to string, tokenID string, amount int64)
SetApprovalForAll (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, operator string, approved bool)
SetListLimit (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, limit int)
SetMinterRealm (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, pkgPath string)
TotalSupply (tokenID string) int64
UnsetMinterRealm (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, pkgPath string)
Uri () string
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.
"gno.land/p/akkadia/beta/grc1155"
9 "gno.land/p/nt/bptree/v0"
10 "gno.land/r/akkadia/beta/admin"
11 )
12
13 const (
14 maxInt64 = int64 ( 9223372036854775807 )
15 )
16
17 var (
18 itemToken = grc1155.NewBasicGRC1155Token( "" )
19 itemSupplies *bptree.BPTree
20 ownerTokenIDs *bptree.BPTree
21 )
22
23 func init() { resetItemState() }
24
25 func resetItemState() {
26 itemToken = grc1155.NewBasicGRC1155Token( "" )
27 itemSupplies = bptree.NewBPTree32()
28 ownerTokenIDs = bptree.NewBPTree32()
29 minterRealms = bptree.NewBPTree32()
30 listLimit = 100
31 }
32
33 func SafeMint(cur realm, recipient address, tokenID string , amount int64 ) {
34 executor := accesscontrol.MustGetAdminOrOperatorCaller( 0 , cur, admin.IsAdmin, admin.IsOperator)
35 assertItemNoCoins()
36 mintItem(cross(cur), executor, recipient, tokenID, amount)
37 }
38
39 func SafeMintFromRealm(cur realm, recipient address, tokenID string , amount int64 ) {
40 executor := mustGetMinterRealmCaller( 0 , cur)
41 if unsafe.OriginCaller() != recipient {
42 panic( "item recipient must be origin caller" )
43 }
44 mintItem(cross(cur), executor, recipient, tokenID, amount)
45 }
46
47 func Uri() string { return itemToken.Uri() }
48 func IsApprovedForAll(owner, operator address) bool {
49 return itemToken.IsApprovedForAll(owner, operator)
50 }
51
52 func SetApprovalForAll(cur realm, operator address, approved bool ) {
53 caller := accesscontrol.MustGetUserCaller( 0 , cur)
54 assertItemNoCoins()
55 if err := itemToken.SetApprovalForAll(caller, operator, approved); err != nil {
56 panic( "item operator approval failed: " + err.Error())
57 }
58 }
59
60 func SafeTransferFrom(cur realm, from, to address, tokenID string , amount int64 ) {
61 caller := accesscontrol.MustGetUserCaller( 0 , cur)
62 assertItemNoCoins()
63 assertItemTokenID(tokenID)
64 assertItemAmount(amount, "transfer" )
65 if err := itemToken.SafeTransferFrom(caller, from, to, grc1155.TokenID(tokenID), amount); err != nil {
66 panic( "item transfer failed: " + err.Error())
67 }
68 if from != to {
69 addOwnerTokenID(to, tokenID)
70 if BalanceOf(from, tokenID) == 0 {
71 removeOwnerTokenID(from, tokenID)
72 }
73 }
74 }
75
76 func BalanceOf(owner address, tokenID string ) int64 {
77 if !owner.IsValid() {
78 panic( "invalid item owner" )
79 }
80 assertItemTokenID(tokenID)
81 balance, err := itemToken.BalanceOf(owner, grc1155.TokenID(tokenID))
82 if err != nil {
83 panic( "item balance query failed: " + err.Error())
84 }
85 return balance
86 }
87
88 func TotalSupply(tokenID string ) int64 {
89 assertItemTokenID(tokenID)
90 value := itemSupplies.Get(tokenID)
91 if value == nil {
92 return 0
93 }
94 return value.( int64 )
95 }
96
97 func GetOwnedCount(owner address) int {
98 if !owner.IsValid() {
99 panic( "invalid item owner" )
100 }
101 ids, found := getOwnerTokenIDs(owner)
102 if !found {
103 return 0
104 }
105 return ids.Size()
106 }
107
108 func ListByOwner(owner address, page, count int ) [] map [ string ] string {
109 if !owner.IsValid() {
110 panic( "invalid item owner" )
111 }
112 assertItemListPageCount(page, count)
113 ids, found := getOwnerTokenIDs(owner)
114 if !found {
115 return [] map [ string ] string {}
116 }
117 result := [] map [ string ] string {}
118 ids.IterateByOffset((page- 1 )*count, count, func (tokenID string , _ any ) bool {
119 result = append(result, map [ string ] string {
120 "tokenId" : tokenID,
121 "amount" : strconv.FormatInt(BalanceOf(owner, tokenID), 10 ),
122 })
123 return false
124 })
125 return result
126 }
127
128 func Burn(cur realm, from address, tokenID string , amount int64 ) {
129 caller := accesscontrol.MustGetUserCaller( 0 , cur)
130 assertItemNoCoins()
131 assertItemTokenID(tokenID)
132 if caller != from && !itemToken.IsApprovedForAll(from, caller) {
133 panic( "item owner or approved operator required" )
134 }
135 assertItemAmount(amount, "burn" )
136 burnItem(cross(cur), caller, from, tokenID, amount)
137 }
138
139 func BurnFromRealm(cur realm, from address, tokenID string , amount int64 ) {
140 caller := mustGetMinterRealmCaller( 0 , cur)
141 if unsafe.OriginCaller() != from {
142 panic( "item owner must be origin caller" )
143 }
144 assertItemTokenID(tokenID)
145 assertItemAmount(amount, "burn" )
146 burnItem(cross(cur), caller, from, tokenID, amount)
147 }
148
149 func mintItem(cur realm, executor, recipient address, tokenID string , amount int64 ) {
150 assertItemTokenID(tokenID)
151 if !recipient.IsValid() || recipient == cur.Address() {
152 panic( "invalid item recipient" )
153 }
154 if amount <= 0 {
155 panic( "item amount must be positive" )
156 }
157 supply := TotalSupply(tokenID)
158 if supply > maxInt64-amount {
159 panic( "item amount overflow" )
160 }
161 if err := itemToken.SafeMint(executor, recipient, grc1155.TokenID(tokenID), amount); err != nil {
162 panic( "item mint failed: " + err.Error())
163 }
164 itemSupplies.Set(tokenID, supply+amount)
165 addOwnerTokenID(recipient, tokenID)
166 }
167
168 func burnItem(cur realm, operator, from address, tokenID string , amount int64 ) {
169 supply := TotalSupply(tokenID)
170 if supply < amount {
171 panic( "item burn amount exceeds supply" )
172 }
173 if err := itemToken.Burn(operator, from, grc1155.TokenID(tokenID), amount); err != nil {
174 panic( "item burn failed: " + err.Error())
175 }
176 itemSupplies.Set(tokenID, supply-amount)
177 if BalanceOf(from, tokenID) == 0 {
178 removeOwnerTokenID(from, tokenID)
179 }
180 }
181
182 func mustGetMinterRealmCaller(_ int , rlm realm) address {
183 accesscontrol.AssertCurrentRealm( 0 , rlm)
184 prev := rlm.Previous()
185 if prev.IsUserCall() {
186 panic( "user calls not allowed: function must be called by a realm" )
187 }
188 caller := prev.Address()
189 if !IsMinterRealm(caller) {
190 panic( "minter realm required" )
191 }
192 return caller
193 }
194
195 func assertItemNoCoins() {
196 if len(unsafe.OriginSend()) != 0 {
197 panic( "attached coins not allowed" )
198 }
199 }
200
201 func assertItemTokenID(tokenID string ) {
202 if tokenID == "" {
203 panic( "token id is required" )
204 }
205 }
206
207 func assertItemAmount(amount int64 , action string ) {
208 if amount <= 0 {
209 panic( "item " + action + " amount must be positive" )
210 }
211 }
212
213 func assertItemListPageCount(page, count int ) {
214 if page < 1 {
215 panic( "page must be at least 1" )
216 }
217 if count < 1 {
218 panic( "count must be at least 1" )
219 }
220 if count > listLimit {
221 panic( "count exceeds listLimit (max: " + strconv.Itoa(listLimit) + ")" )
222 }
223 }
224
225 func addOwnerTokenID(owner address, tokenID string ) {
226 value := ownerTokenIDs.Get(owner.String())
227 var ids *bptree.BPTree
228 if value != nil {
229 ids = value.(*bptree.BPTree)
230 } else {
231 ids = bptree.NewBPTree32()
232 ownerTokenIDs.Set(owner.String(), ids)
233 }
234 ids.Set(tokenID, true )
235 }
236
237 func removeOwnerTokenID(owner address, tokenID string ) {
238 ids, found := getOwnerTokenIDs(owner)
239 if !found {
240 return
241 }
242 ids.Remove(tokenID)
243 }
244
245 func getOwnerTokenIDs(owner address) (*bptree.BPTree, bool ) {
246 value := ownerTokenIDs.Get(owner.String())
247 if value == nil {
248 return nil , false
249 }
250 return value.(*bptree.BPTree), true
251 }
252