operator_faucet_test.gno
16.32 Kb · 525 lines
1package admin
2
3import (
4 "testing"
5
6 "chain"
7 "chain/banker"
8 "chain/runtime"
9
10 "gno.land/p/nt/uassert/v0"
11)
12
13const (
14 testFaucetFundAmount int64 = 1000000
15)
16
17type faucetTestHelper struct{}
18
19var faucetTest = &faucetTestHelper{}
20
21func TestSetFaucetTargetAmount(cur realm, t *testing.T) {
22 tests := []struct {
23 name string
24 originCaller address
25 realm runtime.Realm
26 amount int64
27 shouldPanic bool
28 panicMsg string
29 }{
30 {"admin sets target amount", testAdmin, testing.NewUserRealm(testAdmin), 1000000, false, ""},
31 {"unauthorized", unauthorizedUser, testing.NewUserRealm(unauthorizedUser), 1000000, true, "admin access required"},
32 {"zero amount", testAdmin, testing.NewUserRealm(testAdmin), 0, true, "faucet target amount must be positive"},
33 {"negative amount", testAdmin, testing.NewUserRealm(testAdmin), -1, true, "faucet target amount must be positive"},
34 }
35
36 for _, tt := range tests {
37 setupCommonAdminTests(cur, t)
38 testing.SetOriginCaller(tt.originCaller)
39 testing.SetRealm(tt.realm)
40
41 if tt.shouldPanic {
42 uassert.AbortsWithMessage(t, cur, tt.panicMsg, func() {
43 SetFaucetTargetAmount(cross(cur), tt.amount)
44 })
45 uassert.Equal(t, int64(0), GetFaucetTargetAmount())
46 continue
47 }
48
49 SetFaucetTargetAmount(cross(cur), tt.amount)
50 uassert.Equal(t, tt.amount, GetFaucetTargetAmount())
51 }
52}
53
54func TestRequestFaucetTransfersDeficit(cur realm, t *testing.T) {
55 setupCommonAdminTests(cur, t)
56
57 adminRealm := adminRealmAddr()
58 adminBefore := adminUgnotBalance(adminRealm)
59 operatorBefore := adminUgnotBalance(testOperator)
60 expectedTransfer := int64(300000)
61 faucetTest.FundAdmin(testFaucetFundAmount)
62
63 testing.SetOriginCaller(testAdmin)
64 testing.SetRealm(testing.NewUserRealm(testAdmin))
65 SetOperator(cross(cur), testOperator)
66 SetFaucetTargetAmount(cross(cur), operatorBefore+expectedTransfer)
67
68 testing.SetOriginCaller(testOperator)
69 testing.SetRealm(testing.NewUserRealm(testOperator))
70 transferred := RequestFaucet(cross(cur))
71
72 uassert.Equal(t, expectedTransfer, transferred)
73 uassert.Equal(t, operatorBefore+expectedTransfer, adminUgnotBalance(testOperator))
74 uassert.Equal(t, adminBefore+testFaucetFundAmount-expectedTransfer, adminUgnotBalance(adminRealm))
75}
76
77func TestRequestFaucetForTransfersDeficit(cur realm, t *testing.T) {
78 setupCommonAdminTests(cur, t)
79
80 adminRealm := adminRealmAddr()
81 adminBefore := adminUgnotBalance(adminRealm)
82 operatorBefore := adminUgnotBalance(testOperator)
83 expectedTransfer := int64(300000)
84 faucetTest.FundAdmin(testFaucetFundAmount)
85
86 testing.SetOriginCaller(testAdmin)
87 testing.SetRealm(testing.NewUserRealm(testAdmin))
88 SetOperator(cross(cur), testOperator)
89 SetFaucetTargetAmount(cross(cur), operatorBefore+expectedTransfer)
90 transferred := RequestFaucetFor(cross(cur), testOperator)
91
92 uassert.Equal(t, expectedTransfer, transferred)
93 uassert.Equal(t, operatorBefore+expectedTransfer, adminUgnotBalance(testOperator))
94 uassert.Equal(t, adminBefore+testFaucetFundAmount-expectedTransfer, adminUgnotBalance(adminRealm))
95}
96
97func TestRequestFaucetsTransfersDeficits(cur realm, t *testing.T) {
98 setupCommonAdminTests(cur, t)
99
100 testing.SetOriginCaller(testAdmin)
101 testing.SetRealm(testing.NewUserRealm(testAdmin))
102 UnsetOperator(cross(cur), testAdmin)
103 SetOperator(cross(cur), testOperator)
104 SetOperator(cross(cur), testUser)
105 SetOperator(cross(cur), testUser2)
106
107 adminRealm := adminRealmAddr()
108 adminBefore := adminUgnotBalance(adminRealm)
109 operatorBefore := adminUgnotBalance(testOperator)
110 userBefore := adminUgnotBalance(testUser)
111 user2Before := adminUgnotBalance(testUser2)
112 targetAmount := maxInt64(operatorBefore, maxInt64(userBefore, user2Before)) + 300000
113 if user2Before < targetAmount {
114 faucetTest.Issue(testUser2, targetAmount-user2Before)
115 user2Before = targetAmount
116 }
117 operatorDeficit := targetAmount - operatorBefore
118 userDeficit := targetAmount - userBefore
119 expectedTransfer := operatorDeficit + userDeficit
120 faucetTest.FundAdmin(expectedTransfer)
121
122 testing.SetOriginCaller(testAdmin)
123 testing.SetRealm(testing.NewUserRealm(testAdmin))
124 SetFaucetTargetAmount(cross(cur), targetAmount)
125 transferred := RequestFaucets(cross(cur))
126
127 uassert.Equal(t, expectedTransfer, transferred)
128 uassert.Equal(t, targetAmount, adminUgnotBalance(testOperator))
129 uassert.Equal(t, targetAmount, adminUgnotBalance(testUser))
130 uassert.Equal(t, user2Before, adminUgnotBalance(testUser2))
131 uassert.Equal(t, adminBefore, adminUgnotBalance(adminRealm))
132}
133
134func TestRequestFaucetsReturnsZeroWithoutDeficits(cur realm, t *testing.T) {
135 setupCommonAdminTests(cur, t)
136
137 testing.SetOriginCaller(testAdmin)
138 testing.SetRealm(testing.NewUserRealm(testAdmin))
139 UnsetOperator(cross(cur), testAdmin)
140 SetOperator(cross(cur), testOperator)
141 SetOperator(cross(cur), testUser)
142
143 operatorBefore := adminUgnotBalance(testOperator)
144 userBefore := adminUgnotBalance(testUser)
145 targetAmount := maxInt64(operatorBefore, userBefore)
146 if operatorBefore < targetAmount {
147 faucetTest.Issue(testOperator, targetAmount-operatorBefore)
148 }
149 if userBefore < targetAmount {
150 faucetTest.Issue(testUser, targetAmount-userBefore)
151 }
152 if targetAmount <= 0 {
153 targetAmount = 1
154 faucetTest.Issue(testOperator, targetAmount)
155 faucetTest.Issue(testUser, targetAmount)
156 }
157
158 adminBefore := adminUgnotBalance(adminRealmAddr())
159 testing.SetOriginCaller(testAdmin)
160 testing.SetRealm(testing.NewUserRealm(testAdmin))
161 SetFaucetTargetAmount(cross(cur), targetAmount)
162 transferred := RequestFaucets(cross(cur))
163
164 uassert.Equal(t, int64(0), transferred)
165 uassert.Equal(t, adminBefore, adminUgnotBalance(adminRealmAddr()))
166}
167
168func TestRequestFaucetRejectsInvalidRequest(cur realm, t *testing.T) {
169 tests := []struct {
170 name string
171 setup func(cur realm) (address, runtime.Realm)
172 panicMsg string
173 }{
174 {
175 name: "non-operator direct caller",
176 setup: func(cur realm) (address, runtime.Realm) {
177 testing.SetOriginCaller(testAdmin)
178 testing.SetRealm(testing.NewUserRealm(testAdmin))
179 SetFaucetTargetAmount(cross(cur), 1000000)
180 faucetTest.FundAdmin(testFaucetFundAmount)
181 return unauthorizedUser, testing.NewUserRealm(unauthorizedUser)
182 },
183 panicMsg: "operator access required",
184 },
185 {
186 name: "operator balance already reaches target",
187 setup: func(cur realm) (address, runtime.Realm) {
188 operatorBalance := adminUgnotBalance(testOperator)
189 if operatorBalance == 0 {
190 faucetTest.Issue(testOperator, 1)
191 operatorBalance = 1
192 }
193 testing.SetOriginCaller(testAdmin)
194 testing.SetRealm(testing.NewUserRealm(testAdmin))
195 SetOperator(cross(cur), testOperator)
196 SetFaucetTargetAmount(cross(cur), operatorBalance)
197 faucetTest.FundAdmin(testFaucetFundAmount)
198 return testOperator, testing.NewUserRealm(testOperator)
199 },
200 panicMsg: "operator balance is not below faucet target",
201 },
202 {
203 name: "admin realm balance is insufficient",
204 setup: func(cur realm) (address, runtime.Realm) {
205 adminBalance := adminUgnotBalance(adminRealmAddr())
206 testing.SetOriginCaller(testAdmin)
207 testing.SetRealm(testing.NewUserRealm(testAdmin))
208 SetOperator(cross(cur), testOperator)
209 SetFaucetTargetAmount(cross(cur), adminUgnotBalance(testOperator)+adminBalance+1)
210 return testOperator, testing.NewUserRealm(testOperator)
211 },
212 panicMsg: "admin realm balance is insufficient",
213 },
214 {
215 name: "operator origin through code realm",
216 setup: func(cur realm) (address, runtime.Realm) {
217 testing.SetOriginCaller(testAdmin)
218 testing.SetRealm(testing.NewUserRealm(testAdmin))
219 SetOperator(cross(cur), testOperator)
220 SetFaucetTargetAmount(cross(cur), adminUgnotBalance(testOperator)+1)
221 faucetTest.FundAdmin(testFaucetFundAmount)
222 return testOperator, testing.NewCodeRealm("gno.land/r/akkadia/beta/operator_faucet_relay")
223 },
224 panicMsg: "contract calls not allowed: function must be called directly by user",
225 },
226 {
227 name: "target amount is not configured",
228 setup: func(cur realm) (address, runtime.Realm) {
229 testing.SetOriginCaller(testAdmin)
230 testing.SetRealm(testing.NewUserRealm(testAdmin))
231 SetOperator(cross(cur), testOperator)
232 faucetTest.FundAdmin(testFaucetFundAmount)
233 return testOperator, testing.NewUserRealm(testOperator)
234 },
235 panicMsg: "faucet target amount must be positive",
236 },
237 }
238
239 for _, tt := range tests {
240 setupCommonAdminTests(cur, t)
241 caller, rlm := tt.setup(cur)
242 testing.SetOriginCaller(caller)
243 testing.SetRealm(rlm)
244
245 uassert.AbortsWithMessage(t, cur, tt.panicMsg, func() {
246 RequestFaucet(cross(cur))
247 })
248 }
249}
250
251func TestRequestFaucetForRejectsInvalidRequest(cur realm, t *testing.T) {
252 tests := []struct {
253 name string
254 setup func(cur realm) (address, runtime.Realm, address)
255 panicMsg string
256 }{
257 {
258 name: "non-admin caller",
259 setup: func(cur realm) (address, runtime.Realm, address) {
260 testing.SetOriginCaller(testAdmin)
261 testing.SetRealm(testing.NewUserRealm(testAdmin))
262 SetOperator(cross(cur), testOperator)
263 SetFaucetTargetAmount(cross(cur), 1000000)
264 faucetTest.FundAdmin(testFaucetFundAmount)
265 return unauthorizedUser, testing.NewUserRealm(unauthorizedUser), testOperator
266 },
267 panicMsg: "admin access required",
268 },
269 {
270 name: "non-operator target",
271 setup: func(cur realm) (address, runtime.Realm, address) {
272 testing.SetOriginCaller(testAdmin)
273 testing.SetRealm(testing.NewUserRealm(testAdmin))
274 SetFaucetTargetAmount(cross(cur), 1000000)
275 faucetTest.FundAdmin(testFaucetFundAmount)
276 return testAdmin, testing.NewUserRealm(testAdmin), unauthorizedUser
277 },
278 panicMsg: "operator access required",
279 },
280 {
281 name: "operator balance already reaches target",
282 setup: func(cur realm) (address, runtime.Realm, address) {
283 operatorBalance := adminUgnotBalance(testOperator)
284 if operatorBalance == 0 {
285 faucetTest.Issue(testOperator, 1)
286 operatorBalance = 1
287 }
288 testing.SetOriginCaller(testAdmin)
289 testing.SetRealm(testing.NewUserRealm(testAdmin))
290 SetOperator(cross(cur), testOperator)
291 SetFaucetTargetAmount(cross(cur), operatorBalance)
292 faucetTest.FundAdmin(testFaucetFundAmount)
293 return testAdmin, testing.NewUserRealm(testAdmin), testOperator
294 },
295 panicMsg: "operator balance is not below faucet target",
296 },
297 {
298 name: "admin realm balance is insufficient",
299 setup: func(cur realm) (address, runtime.Realm, address) {
300 adminBalance := adminUgnotBalance(adminRealmAddr())
301 testing.SetOriginCaller(testAdmin)
302 testing.SetRealm(testing.NewUserRealm(testAdmin))
303 SetOperator(cross(cur), testOperator)
304 SetFaucetTargetAmount(cross(cur), adminUgnotBalance(testOperator)+adminBalance+1)
305 return testAdmin, testing.NewUserRealm(testAdmin), testOperator
306 },
307 panicMsg: "admin realm balance is insufficient",
308 },
309 {
310 name: "target amount is not configured",
311 setup: func(cur realm) (address, runtime.Realm, address) {
312 testing.SetOriginCaller(testAdmin)
313 testing.SetRealm(testing.NewUserRealm(testAdmin))
314 SetOperator(cross(cur), testOperator)
315 faucetTest.FundAdmin(testFaucetFundAmount)
316 return testAdmin, testing.NewUserRealm(testAdmin), testOperator
317 },
318 panicMsg: "faucet target amount must be positive",
319 },
320 }
321
322 for _, tt := range tests {
323 setupCommonAdminTests(cur, t)
324 caller, rlm, operator := tt.setup(cur)
325 testing.SetOriginCaller(caller)
326 testing.SetRealm(rlm)
327
328 uassert.AbortsWithMessage(t, cur, tt.panicMsg, func() {
329 RequestFaucetFor(cross(cur), operator)
330 })
331 }
332}
333
334func TestRequestFaucetsRejectsInvalidRequest(cur realm, t *testing.T) {
335 tests := []struct {
336 name string
337 setup func(cur realm) (address, runtime.Realm)
338 panicMsg string
339 }{
340 {
341 name: "non-admin caller",
342 setup: func(cur realm) (address, runtime.Realm) {
343 testing.SetOriginCaller(testAdmin)
344 testing.SetRealm(testing.NewUserRealm(testAdmin))
345 SetOperator(cross(cur), testOperator)
346 SetFaucetTargetAmount(cross(cur), adminUgnotBalance(testOperator)+1)
347 faucetTest.FundAdmin(testFaucetFundAmount)
348 return unauthorizedUser, testing.NewUserRealm(unauthorizedUser)
349 },
350 panicMsg: "admin access required",
351 },
352 {
353 name: "admin realm balance is insufficient",
354 setup: func(cur realm) (address, runtime.Realm) {
355 adminBalance := adminUgnotBalance(adminRealmAddr())
356 testing.SetOriginCaller(testAdmin)
357 testing.SetRealm(testing.NewUserRealm(testAdmin))
358 SetOperator(cross(cur), testOperator)
359 SetFaucetTargetAmount(cross(cur), adminUgnotBalance(testOperator)+adminBalance+1)
360 return testAdmin, testing.NewUserRealm(testAdmin)
361 },
362 panicMsg: "admin realm balance is insufficient",
363 },
364 {
365 name: "target amount is not configured",
366 setup: func(cur realm) (address, runtime.Realm) {
367 testing.SetOriginCaller(testAdmin)
368 testing.SetRealm(testing.NewUserRealm(testAdmin))
369 SetOperator(cross(cur), testOperator)
370 faucetTest.FundAdmin(testFaucetFundAmount)
371 return testAdmin, testing.NewUserRealm(testAdmin)
372 },
373 panicMsg: "faucet target amount must be positive",
374 },
375 }
376
377 for _, tt := range tests {
378 setupCommonAdminTests(cur, t)
379 caller, rlm := tt.setup(cur)
380 testing.SetOriginCaller(caller)
381 testing.SetRealm(rlm)
382
383 uassert.AbortsWithMessage(t, cur, tt.panicMsg, func() {
384 RequestFaucets(cross(cur))
385 })
386 }
387}
388
389func TestWithdrawTransfersAdminRealmBalance(cur realm, t *testing.T) {
390 setupCommonAdminTests(cur, t)
391
392 adminRealm := adminRealmAddr()
393 adminBefore := adminUgnotBalance(adminRealm)
394 recipientBefore := adminUgnotBalance(testUser)
395 withdrawAmount := int64(200000)
396 faucetTest.FundAdmin(withdrawAmount)
397
398 testing.SetOriginCaller(testAdmin)
399 testing.SetRealm(testing.NewUserRealm(testAdmin))
400 transferred := Withdraw(cross(cur), testUser, withdrawAmount)
401
402 uassert.Equal(t, withdrawAmount, transferred)
403 uassert.Equal(t, recipientBefore+withdrawAmount, adminUgnotBalance(testUser))
404 uassert.Equal(t, adminBefore, adminUgnotBalance(adminRealm))
405}
406
407type withdrawRejectContext struct {
408 caller address
409 recipient address
410 amount int64
411 adminBefore int64
412 recipientBefore int64
413 checkRecipient bool
414}
415
416func TestWithdrawRejectsInvalidRequest(cur realm, t *testing.T) {
417 tests := []struct {
418 name string
419 setup func() withdrawRejectContext
420 panicMsg string
421 }{
422 {
423 name: "non-admin caller",
424 setup: func() withdrawRejectContext {
425 faucetTest.FundAdmin(1)
426 return withdrawRejectContext{
427 caller: unauthorizedUser,
428 recipient: testUser,
429 amount: 1,
430 }
431 },
432 panicMsg: "admin access required",
433 },
434 {
435 name: "invalid recipient",
436 setup: func() withdrawRejectContext {
437 faucetTest.FundAdmin(1)
438 return withdrawRejectContext{
439 caller: testAdmin,
440 recipient: address(""),
441 amount: 1,
442 }
443 },
444 panicMsg: "invalid address",
445 },
446 {
447 name: "zero amount",
448 setup: func() withdrawRejectContext {
449 faucetTest.FundAdmin(1)
450 return withdrawRejectContext{
451 caller: testAdmin,
452 recipient: testUser,
453 amount: 0,
454 }
455 },
456 panicMsg: "amount must be greater than 0",
457 },
458 {
459 name: "negative amount",
460 setup: func() withdrawRejectContext {
461 faucetTest.FundAdmin(1)
462 return withdrawRejectContext{
463 caller: testAdmin,
464 recipient: testUser,
465 amount: -1,
466 }
467 },
468 panicMsg: "amount must be greater than 0",
469 },
470 {
471 name: "admin realm balance is insufficient",
472 setup: func() withdrawRejectContext {
473 return withdrawRejectContext{
474 caller: testAdmin,
475 recipient: testUser,
476 amount: adminUgnotBalance(adminRealmAddr()) + 1,
477 }
478 },
479 panicMsg: "admin realm balance is insufficient",
480 },
481 }
482
483 for _, tt := range tests {
484 setupCommonAdminTests(cur, t)
485 ctx := tt.setup()
486 ctx.adminBefore = adminUgnotBalance(adminRealmAddr())
487 ctx.checkRecipient = ctx.recipient.IsValid()
488 if ctx.checkRecipient {
489 ctx.recipientBefore = adminUgnotBalance(ctx.recipient)
490 }
491 testing.SetOriginCaller(ctx.caller)
492 testing.SetRealm(testing.NewUserRealm(ctx.caller))
493
494 uassert.AbortsWithMessage(t, cur, tt.panicMsg, func() {
495 Withdraw(cross(cur), ctx.recipient, ctx.amount)
496 })
497 uassert.Equal(t, ctx.adminBefore, adminUgnotBalance(adminRealmAddr()))
498 if ctx.checkRecipient {
499 uassert.Equal(t, ctx.recipientBefore, adminUgnotBalance(ctx.recipient))
500 }
501 }
502}
503
504func adminUgnotBalance(addr address) int64 {
505 bnk := banker.NewReadonlyBanker()
506 return bnk.GetCoins(addr).AmountOf("ugnot")
507}
508
509func (h *faucetTestHelper) FundAdmin(amount int64) {
510 h.Issue(adminRealmAddr(), amount)
511}
512
513func (h *faucetTestHelper) Issue(addr address, amount int64) {
514 if amount <= 0 {
515 return
516 }
517 testing.IssueCoins(addr, chain.Coins{{"ugnot", amount}})
518}
519
520func maxInt64(a int64, b int64) int64 {
521 if a > b {
522 return a
523 }
524 return b
525}