Kind Realm (renderable)
Name item
Namespace akkadia / beta
Exported functions 18
Module gno.land/r/akkadia/beta/item
gno 0.9 item_test.gno gno
⧉
1 package item 2 3 import ( 4 "chain" 5 "testing" 6 7 "gno.land/p/nt/testutils/v0" 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/nt/uassert/v0"
9 "gno.land/r/akkadia/beta/admin"
10 )
11
12 var itemTest = struct {
13 Admin, Operator, Owner, Other address
14 SetupDone bool
15 }{
16 Admin: testutils.TestAddress( "itemAdmin" ),
17 Operator: testutils.TestAddress( "itemOperator" ),
18 Owner: testutils.TestAddress( "itemOwner" ),
19 Other: testutils.TestAddress( "itemOther" ),
20 }
21
22 func setupItemTest(cur realm, t *testing.T) {
23 t.Helper()
24 resetItemState()
25 testing.SetOriginSend(chain.Coins{})
26 if itemTest.SetupDone {
27 return
28 }
29 originalAdmin := admin.GetAdmin()
30 testing.SetOriginCaller(originalAdmin)
31 testing.SetRealm(testing.NewUserRealm(originalAdmin))
32 admin.TransferAdmin(cross(cur), itemTest.Admin)
33 testing.SetOriginCaller(itemTest.Admin)
34 testing.SetRealm(testing.NewUserRealm(itemTest.Admin))
35 admin.AcceptAdmin(cross(cur))
36 admin.SetOperator(cross(cur), itemTest.Operator)
37 itemTest.SetupDone = true
38 }
39
40 func TestSafeMintTracksSupply(cur realm, t *testing.T) {
41 setupItemTest(cross(cur), t)
42 testing.SetOriginCaller(itemTest.Operator)
43 testing.SetRealm(testing.NewUserRealm(itemTest.Operator))
44 SafeMint(cross(cur), itemTest.Owner, "42" , 5 )
45 uassert.Equal(t, int64 ( 5 ), BalanceOf(itemTest.Owner, "42" ))
46 uassert.Equal(t, int64 ( 5 ), TotalSupply( "42" ))
47 SafeMint(cross(cur), itemTest.Owner, "42" , 1 )
48 SafeMint(cross(cur), itemTest.Other, "42" , 2 )
49 uassert.Equal(t, int64 ( 6 ), BalanceOf(itemTest.Owner, "42" ))
50 uassert.Equal(t, int64 ( 2 ), BalanceOf(itemTest.Other, "42" ))
51 uassert.Equal(t, int64 ( 8 ), TotalSupply( "42" ))
52 }
53
54 func TestItemTokenIDAcceptsOpaqueStrings(cur realm, t *testing.T) {
55 setupItemTest(cross(cur), t)
56 testing.SetOriginCaller(itemTest.Operator)
57 testing.SetRealm(testing.NewUserRealm(itemTest.Operator))
58 SafeMint(cross(cur), itemTest.Owner, "0" , 1 )
59 SafeMint(cross(cur), itemTest.Owner, "4294967295" , 2 )
60 SafeMint(cross(cur), itemTest.Owner, "sword" , 3 )
61 uassert.Equal(t, int64 ( 1 ), BalanceOf(itemTest.Owner, "0" ))
62 uassert.Equal(t, int64 ( 2 ), TotalSupply( "4294967295" ))
63 uassert.Equal(t, int64 ( 3 ), TotalSupply( "sword" ))
64 uassert.AbortsWithMessage(t, cur, "token id is required" , func () {
65 SafeMint(cross(cur), itemTest.Owner, "" , 1 )
66 })
67 }
68
69 func TestItemTransferAndBurnUpdateSupply(cur realm, t *testing.T) {
70 setupItemTest(cross(cur), t)
71 testing.SetOriginCaller(itemTest.Operator)
72 testing.SetRealm(testing.NewUserRealm(itemTest.Operator))
73 SafeMint(cross(cur), itemTest.Owner, "42" , 5 )
74 testing.SetOriginCaller(itemTest.Owner)
75 testing.SetRealm(testing.NewUserRealm(itemTest.Owner))
76 SafeTransferFrom(cross(cur), itemTest.Owner, itemTest.Other, "42" , 2 )
77 Burn(cross(cur), itemTest.Owner, "42" , 1 )
78 uassert.Equal(t, int64 ( 2 ), BalanceOf(itemTest.Owner, "42" ))
79 uassert.Equal(t, int64 ( 2 ), BalanceOf(itemTest.Other, "42" ))
80 uassert.Equal(t, int64 ( 4 ), TotalSupply( "42" ))
81 }
82
83 func TestItemApprovalAllowsTransferAndBurn(cur realm, t *testing.T) {
84 setupItemTest(cross(cur), t)
85 testing.SetOriginCaller(itemTest.Operator)
86 testing.SetRealm(testing.NewUserRealm(itemTest.Operator))
87 SafeMint(cross(cur), itemTest.Owner, "42" , 5 )
88 testing.SetOriginCaller(itemTest.Owner)
89 testing.SetRealm(testing.NewUserRealm(itemTest.Owner))
90 SetApprovalForAll(cross(cur), itemTest.Other, true )
91 testing.SetOriginCaller(itemTest.Other)
92 testing.SetRealm(testing.NewUserRealm(itemTest.Other))
93 SafeTransferFrom(cross(cur), itemTest.Owner, itemTest.Admin, "42" , 2 )
94 Burn(cross(cur), itemTest.Owner, "42" , 1 )
95 uassert.Equal(t, int64 ( 2 ), BalanceOf(itemTest.Owner, "42" ))
96 uassert.Equal(t, int64 ( 2 ), BalanceOf(itemTest.Admin, "42" ))
97 uassert.Equal(t, int64 ( 4 ), TotalSupply( "42" ))
98 }
99
100 func TestSafeMintSecurity(cur realm, t *testing.T) {
101 setupItemTest(cross(cur), t)
102 testing.SetOriginCaller(itemTest.Owner)
103 testing.SetRealm(testing.NewUserRealm(itemTest.Owner))
104 uassert.AbortsWithMessage(t, cur, "admin or operator access required" , func () {
105 SafeMint(cross(cur), itemTest.Owner, "1" , 1 )
106 })
107 testing.SetOriginCaller(itemTest.Operator)
108 testing.SetRealm(testing.NewCodeRealm( "gno.land/r/example/item_relay" ))
109 uassert.AbortsWithMessage(t, cur, "admin or operator access required" , func () {
110 SafeMint(cross(cur), itemTest.Owner, "1" , 1 )
111 })
112 testing.SetRealm(testing.NewUserRealm(itemTest.Operator))
113 testing.SetOriginSend(chain.Coins{{ "ugnot" , 1 }})
114 uassert.AbortsWithMessage(t, cur, "attached coins not allowed" , func () {
115 SafeMint(cross(cur), itemTest.Owner, "1" , 1 )
116 })
117 }
118
119 func TestItemOwnedList(cur realm, t *testing.T) {
120 setupItemTest(cross(cur), t)
121 testing.SetOriginCaller(itemTest.Operator)
122 testing.SetRealm(testing.NewUserRealm(itemTest.Operator))
123 uassert.Equal(t, 0 , GetOwnedCount(itemTest.Owner))
124 uassert.Equal(t, 0 , len(ListByOwner(itemTest.Owner, 1 , 10 )))
125 uassert.PanicsWithMessage(t, cur, "invalid item owner" , func () {
126 GetOwnedCount(address( "" ))
127 })
128 uassert.PanicsWithMessage(t, cur, "page must be at least 1" , func () {
129 ListByOwner(itemTest.Owner, 0 , 1 )
130 })
131 uassert.PanicsWithMessage(t, cur, "count must be at least 1" , func () {
132 ListByOwner(itemTest.Owner, 1 , 0 )
133 })
134 uassert.PanicsWithMessage(t, cur, "count exceeds listLimit (max: 100)" , func () {
135 ListByOwner(itemTest.Owner, 1 , 101 )
136 })
137 uassert.Equal(t, 100 , GetListLimit())
138
139 SafeMint(cross(cur), itemTest.Owner, "10" , 5 )
140 SafeMint(cross(cur), itemTest.Owner, "20" , 3 )
141 SafeMint(cross(cur), itemTest.Owner, "30" , 1 )
142 uassert.Equal(t, 3 , GetOwnedCount(itemTest.Owner))
143 page1 := ListByOwner(itemTest.Owner, 1 , 2 )
144 uassert.Equal(t, 2 , len(page1))
145 uassert.Equal(t, "10" , page1[ 0 ][ "tokenId" ])
146 uassert.Equal(t, "5" , page1[ 0 ][ "amount" ])
147 uassert.Equal(t, "20" , page1[ 1 ][ "tokenId" ])
148 page2 := ListByOwner(itemTest.Owner, 2 , 2 )
149 uassert.Equal(t, 1 , len(page2))
150 uassert.Equal(t, "30" , page2[ 0 ][ "tokenId" ])
151 uassert.Equal(t, 0 , len(ListByOwner(itemTest.Owner, 3 , 2 )))
152 page1[ 0 ][ "amount" ] = "hacked"
153 uassert.Equal(t, "5" , ListByOwner(itemTest.Owner, 1 , 1 )[ 0 ][ "amount" ])
154
155 testing.SetOriginCaller(itemTest.Owner)
156 testing.SetRealm(testing.NewUserRealm(itemTest.Owner))
157 SafeTransferFrom(cross(cur), itemTest.Owner, itemTest.Other, "10" , 2 )
158 uassert.Equal(t, 3 , GetOwnedCount(itemTest.Owner))
159 uassert.Equal(t, 1 , GetOwnedCount(itemTest.Other))
160 uassert.Equal(t, "3" , ListByOwner(itemTest.Owner, 1 , 10 )[ 0 ][ "amount" ])
161 uassert.Equal(t, "2" , ListByOwner(itemTest.Other, 1 , 10 )[ 0 ][ "amount" ])
162 SafeTransferFrom(cross(cur), itemTest.Owner, itemTest.Other, "10" , 3 )
163 uassert.Equal(t, 2 , GetOwnedCount(itemTest.Owner))
164 uassert.Equal(t, 1 , GetOwnedCount(itemTest.Other))
165 Burn(cross(cur), itemTest.Owner, "20" , 3 )
166 uassert.Equal(t, 1 , GetOwnedCount(itemTest.Owner))
167 uassert.Equal(t, "30" , ListByOwner(itemTest.Owner, 1 , 10 )[ 0 ][ "tokenId" ])
168
169 testing.SetOriginCaller(itemTest.Operator)
170 testing.SetRealm(testing.NewUserRealm(itemTest.Operator))
171 SafeMint(cross(cur), itemTest.Owner, "30" , 2 )
172 uassert.Equal(t, 1 , GetOwnedCount(itemTest.Owner))
173 uassert.Equal(t, "3" , ListByOwner(itemTest.Owner, 1 , 10 )[ 0 ][ "amount" ])
174 }
175
176 func TestSetListLimit(cur realm, t *testing.T) {
177 setupItemTest(cross(cur), t)
178
179 testing.SetOriginCaller(itemTest.Admin)
180 testing.SetRealm(testing.NewUserRealm(itemTest.Admin))
181 SetListLimit(cross(cur), 50 )
182 uassert.Equal(t, 50 , GetListLimit())
183
184 SetListLimit(cross(cur), 1 )
185 uassert.PanicsWithMessage(t, cur, "count exceeds listLimit (max: 1)" , func () {
186 ListByOwner(itemTest.Owner, 1 , 2 )
187 })
188
189 uassert.AbortsWithMessage(t, cur, "limit must be at least 1" , func () {
190 SetListLimit(cross(cur), 0 )
191 })
192 uassert.AbortsWithMessage(t, cur, "limit must be at least 1" , func () {
193 SetListLimit(cross(cur), - 1 )
194 })
195
196 testing.SetOriginCaller(itemTest.Operator)
197 testing.SetRealm(testing.NewUserRealm(itemTest.Operator))
198 uassert.AbortsWithMessage(t, cur, "admin access required" , func () {
199 SetListLimit(cross(cur), 50 )
200 })
201
202 testing.SetOriginCaller(itemTest.Owner)
203 testing.SetRealm(testing.NewUserRealm(itemTest.Owner))
204 uassert.AbortsWithMessage(t, cur, "admin access required" , func () {
205 SetListLimit(cross(cur), 50 )
206 })
207
208 testing.SetOriginCaller(itemTest.Admin)
209 testing.SetRealm(testing.NewCodeRealm( "gno.land/r/example/item_admin_relay" ))
210 uassert.AbortsWithMessage(t, cur, "admin access required" , func () {
211 SetListLimit(cross(cur), 50 )
212 })
213 }
214
215 func TestSetMinterRealm(cur realm, t *testing.T) {
216 setupItemTest(cross(cur), t)
217 minterPath := "gno.land/r/example/item_minter"
218 minter := testing.NewCodeRealm(minterPath)
219 minterAddr := minter.Address()
220
221 uassert.Equal(t, minterAddr.String(), chain.PackageAddress(minterPath).String())
222 uassert.Equal(t, false , IsMinterRealm(minterAddr))
223
224 testing.SetOriginCaller(itemTest.Operator)
225 testing.SetRealm(testing.NewUserRealm(itemTest.Operator))
226 uassert.AbortsWithMessage(t, cur, "admin access required" , func () {
227 SetMinterRealm(cross(cur), minterPath)
228 })
229
230 testing.SetOriginCaller(itemTest.Admin)
231 testing.SetRealm(testing.NewUserRealm(itemTest.Admin))
232 uassert.AbortsWithMessage(t, cur, "package path is required" , func () {
233 SetMinterRealm(cross(cur), "" )
234 })
235 uassert.AbortsWithMessage(t, cur, "invalid package path" , func () {
236 SetMinterRealm(cross(cur), "gno.land/p/akkadia/beta/item" )
237 })
238 SetMinterRealm(cross(cur), minterPath)
239 uassert.Equal(t, true , IsMinterRealm(minterAddr))
240 SetMinterRealm(cross(cur), minterPath)
241 uassert.Equal(t, true , IsMinterRealm(minterAddr))
242
243 UnsetMinterRealm(cross(cur), minterPath)
244 uassert.Equal(t, false , IsMinterRealm(minterAddr))
245 uassert.AbortsWithMessage(t, cur, "package path is not a minter realm" , func () {
246 UnsetMinterRealm(cross(cur), minterPath)
247 })
248 uassert.AbortsWithMessage(t, cur, "package path is required" , func () {
249 UnsetMinterRealm(cross(cur), "" )
250 })
251
252 testing.SetRealm(testing.NewCodeRealm( "gno.land/r/example/item_admin_relay" ))
253 uassert.AbortsWithMessage(t, cur, "admin access required" , func () {
254 SetMinterRealm(cross(cur), minterPath)
255 })
256 }
257
258 func TestSafeMintFromRealm(cur realm, t *testing.T) {
259 setupItemTest(cross(cur), t)
260 minter := testing.NewCodeRealm( "gno.land/r/example/item_minter" )
261 unregistered := testing.NewCodeRealm( "gno.land/r/example/item_minter_other" )
262
263 testing.SetOriginCaller(itemTest.Owner)
264 testing.SetRealm(testing.NewUserRealm(itemTest.Owner))
265 uassert.AbortsWithMessage(t, cur, "user calls not allowed: function must be called by a realm" , func () {
266 SafeMintFromRealm(cross(cur), itemTest.Owner, "1" , 1 )
267 })
268
269 testing.SetRealm(unregistered)
270 uassert.AbortsWithMessage(t, cur, "minter realm required" , func () {
271 SafeMintFromRealm(cross(cur), itemTest.Owner, "1" , 1 )
272 })
273
274 testing.SetOriginCaller(itemTest.Admin)
275 testing.SetRealm(testing.NewUserRealm(itemTest.Admin))
276 SetMinterRealm(cross(cur), "gno.land/r/example/item_minter" )
277
278 testing.SetOriginCaller(itemTest.Owner)
279 testing.SetRealm(minter)
280 SafeMintFromRealm(cross(cur), itemTest.Owner, "7" , 3 )
281 uassert.Equal(t, int64 ( 3 ), BalanceOf(itemTest.Owner, "7" ))
282 uassert.Equal(t, int64 ( 3 ), TotalSupply( "7" ))
283 uassert.Equal(t, 1 , GetOwnedCount(itemTest.Owner))
284
285 uassert.AbortsWithMessage(t, cur, "item recipient must be origin caller" , func () {
286 SafeMintFromRealm(cross(cur), itemTest.Other, "8" , 1 )
287 })
288 uassert.Equal(t, int64 ( 0 ), TotalSupply( "8" ))
289
290 testing.SetOriginSend(chain.Coins{{ "ugnot" , 1 }})
291 SafeMintFromRealm(cross(cur), itemTest.Owner, "9" , 1 )
292 testing.SetOriginSend(chain.Coins{})
293 uassert.Equal(t, int64 ( 1 ), BalanceOf(itemTest.Owner, "9" ))
294 }
295
296 func TestBurnFromRealm(cur realm, t *testing.T) {
297 setupItemTest(cross(cur), t)
298 minter := testing.NewCodeRealm( "gno.land/r/example/item_minter" )
299
300 testing.SetOriginCaller(itemTest.Operator)
301 testing.SetRealm(testing.NewUserRealm(itemTest.Operator))
302 SafeMint(cross(cur), itemTest.Owner, "42" , 5 )
303
304 testing.SetOriginCaller(itemTest.Admin)
305 testing.SetRealm(testing.NewUserRealm(itemTest.Admin))
306 SetMinterRealm(cross(cur), "gno.land/r/example/item_minter" )
307
308 testing.SetOriginCaller(itemTest.Owner)
309 testing.SetRealm(testing.NewUserRealm(itemTest.Owner))
310 uassert.AbortsWithMessage(t, cur, "user calls not allowed: function must be called by a realm" , func () {
311 BurnFromRealm(cross(cur), itemTest.Owner, "42" , 1 )
312 })
313
314 testing.SetRealm(minter)
315 uassert.AbortsWithMessage(t, cur, "item owner must be origin caller" , func () {
316 BurnFromRealm(cross(cur), itemTest.Other, "42" , 1 )
317 })
318 uassert.Equal(t, int64 ( 5 ), BalanceOf(itemTest.Owner, "42" ))
319
320 BurnFromRealm(cross(cur), itemTest.Owner, "42" , 2 )
321 uassert.Equal(t, int64 ( 3 ), BalanceOf(itemTest.Owner, "42" ))
322 uassert.Equal(t, int64 ( 3 ), TotalSupply( "42" ))
323
324 uassert.AbortsWithMessage(t, cur, "item amount must be positive" , func () {
325 SafeMintFromRealm(cross(cur), itemTest.Owner, "99" , 0 )
326 })
327 uassert.Equal(t, int64 ( 3 ), BalanceOf(itemTest.Owner, "42" ))
328 uassert.Equal(t, int64 ( 3 ), TotalSupply( "42" ))
329 uassert.Equal(t, int64 ( 0 ), TotalSupply( "99" ))
330 uassert.Equal(t, 1 , GetOwnedCount(itemTest.Owner))
331
332 testing.SetOriginCaller(itemTest.Admin)
333 testing.SetRealm(testing.NewUserRealm(itemTest.Admin))
334 UnsetMinterRealm(cross(cur), "gno.land/r/example/item_minter" )
335 testing.SetOriginCaller(itemTest.Owner)
336 testing.SetRealm(minter)
337 uassert.AbortsWithMessage(t, cur, "minter realm required" , func () {
338 BurnFromRealm(cross(cur), itemTest.Owner, "42" , 1 )
339 })
340 uassert.Equal(t, int64 ( 3 ), BalanceOf(itemTest.Owner, "42" ))
341 }
342