vault_test.gno
15.43 Kb · 318 lines
1package game_vault
2
3import (
4 "chain"
5 "strconv"
6 "strings"
7 "testing"
8
9 "gno.land/p/nt/uassert/v0"
10)
11
12func TestParticipationProcessFundingAndSettlement(cur realm, t *testing.T) {
13 vaultTest.Setup(cross(cur), t)
14 poolID := vaultTest.CreatePool(cross(cur), "pool:1")
15 processID := vaultTest.CreateParticipationProcess(cross(cur), "participation:1", "pool:1", 25)
16
17 firstFundID := vaultTest.DepositParticipation(cross(cur), vaultTest.Player1, processID, "participant:1", "payment:1", 25)
18 secondFundID := vaultTest.DepositParticipation(cross(cur), vaultTest.Player1, processID, "participant:1", "payment:2", 25)
19 vaultTest.DepositParticipation(cross(cur), vaultTest.Player2, processID, "participant:1", "payment:1", 25)
20
21 uassert.Equal(t, firstFundID, GetParticipationFundID(processID, vaultTest.Player1, "payment:1"))
22 uassert.Equal(t, 2, GetParticipationFundCount(processID, vaultTest.Player1, "participant:1"))
23 ids := ListParticipationFundIDs(processID, vaultTest.Player1, "participant:1", 1, 10)
24 uassert.Equal(t, 2, len(ids))
25 uassert.Equal(t, secondFundID, ids[0])
26 uassert.Equal(t, firstFundID, ids[1])
27
28 testing.SetOriginCaller(vaultTest.Operator)
29 testing.SetRealm(testing.NewUserRealm(vaultTest.Operator))
30 testing.SetOriginSend(chain.Coins{})
31 CloseParticipationProcess(cross(cur), processID)
32 CommitParticipationProcess(cross(cur), processID, "commit:1")
33 uassert.Equal(t, int(ParticipationProcessStatusCommitted), int(GetParticipationProcess(processID).Status))
34 processView := GetParticipationProcessByKey("participation:1")
35 uassert.Equal(t, "pool:1", processView.RewardPoolKey)
36 uassert.Equal(t, int(ParticipationFundStatusCommitted), int(GetParticipationFundEffectiveStatus(firstFundID)))
37 uassert.Equal(t, int64(75), GetRewardPool(poolID).Balance)
38
39 vaultTest.DepositSystemFunding(cross(cur), poolID, "system:1", 25)
40 testing.SetOriginCaller(vaultTest.Operator)
41 testing.SetRealm(testing.NewUserRealm(vaultTest.Operator))
42 testing.SetOriginSend(chain.Coins{})
43 LockRewardPool(cross(cur), "pool:1")
44 DistributeReward(cross(cur), "pool:1", "distribution:1", vaultTest.Player2.String(), "100")
45 distributionView := GetRewardDistributionByOperationKey("distribution:1")
46 uassert.Equal(t, "pool:1", distributionView.PoolKey)
47 SettleRewardPool(cross(cur), "pool:1")
48 uassert.Equal(t, int(RewardPoolStatusSettled), int(GetRewardPoolByKey("pool:1").Status))
49}
50
51func TestListParticipationProcessStates(cur realm, t *testing.T) {
52 vaultTest.Setup(cross(cur), t)
53 vaultTest.CreatePool(cross(cur), "pool:process-states")
54 processID := vaultTest.CreateParticipationProcess(cross(cur), "process:states", "pool:process-states", 25)
55
56 states := ListParticipationProcessStates("process:missing", "process:states")
57 uassert.Equal(t, 2, len(states))
58 uassert.Equal(t, "0", states[0]["processId"])
59 uassert.Equal(t, strconv.FormatUint(processID, 10), states[1]["processId"])
60 uassert.Equal(t, "pool:process-states", states[1]["rewardPoolKey"])
61 uassert.Equal(t, "25", states[1]["participationFee"])
62}
63
64func TestListParticipationFundStates(cur realm, t *testing.T) {
65 vaultTest.Setup(cross(cur), t)
66 vaultTest.CreatePool(cross(cur), "pool:fund-states")
67 processID := vaultTest.CreateParticipationProcess(cross(cur), "process:fund-states", "pool:fund-states", 25)
68 fundID := vaultTest.DepositParticipation(cross(cur), vaultTest.Player1, processID, "participation:1", "payment:1", 25)
69
70 states := ListParticipationFundStates(
71 strconv.FormatUint(processID, 10), vaultTest.Player1.String(), "payment:missing",
72 strconv.FormatUint(processID, 10), vaultTest.Player1.String(), "payment:1",
73 )
74 uassert.Equal(t, 2, len(states))
75 uassert.Equal(t, "0", states[0]["fundId"])
76 uassert.Equal(t, strconv.FormatUint(fundID, 10), states[1]["fundId"])
77 uassert.Equal(t, strconv.Itoa(int(ParticipationFundStatusHeld)), states[1]["fundEffectiveStatus"])
78}
79
80func TestParticipationStateQueriesRejectInvalidBatch(cur realm, t *testing.T) {
81 uassert.PanicsWithMessage(t, cur, "participation fund value count mismatch", func() {
82 ListParticipationFundStates("1", vaultTest.Player1.String())
83 })
84
85 processKeys := []string{}
86 fundValues := []string{}
87 for index := 0; index <= gameVaultList; index++ {
88 processKeys = append(processKeys, "process:1")
89 fundValues = append(fundValues, "1", vaultTest.Player1.String(), "payment:1")
90 }
91 uassert.PanicsWithMessage(t, cur, "count exceeds game vault list limit", func() {
92 ListParticipationProcessStates(processKeys...)
93 })
94 uassert.PanicsWithMessage(t, cur, "count exceeds game vault list limit", func() {
95 ListParticipationFundStates(fundValues...)
96 })
97}
98
99func TestListEntryRefundStates(cur realm, t *testing.T) {
100 vaultTest.Setup(cross(cur), t)
101 processID := vaultTest.CreateEntryProcess(cross(cur), "entry:states", 25)
102 fundID := vaultTest.DepositEntry(cross(cur), vaultTest.Player1, processID, "participation:1", "entry:1", 25)
103
104 states := ListEntryRefundStates(
105 "entry:missing,entry:states,entry:states,entry:states",
106 strings.Repeat(vaultTest.Player1.String()+",", 3)+vaultTest.Player1.String(),
107 "entry:1,entry:missing,entry:1,entry:1",
108 )
109 uassert.Equal(t, 4, len(states))
110 uassert.Equal(t, "entry:missing", states[0]["requestedProcessKey"])
111 uassert.Equal(t, "0", states[0]["processId"])
112 uassert.Equal(t, "0", states[0]["fundId"])
113 uassert.Equal(t, strconv.FormatUint(processID, 10), states[1]["processId"])
114 uassert.Equal(t, "0", states[1]["fundId"])
115 uassert.Equal(t, "25", states[2]["entryFee"])
116 uassert.Equal(t, strconv.FormatUint(fundID, 10), states[2]["fundId"])
117 uassert.Equal(t, vaultTest.Player1.String(), states[2]["fundOwner"])
118 uassert.Equal(t, "entry:1", states[2]["fundEntryKey"])
119 uassert.Equal(t, "participation:1", states[2]["participationKey"])
120 uassert.Equal(t, "false", states[2]["fundRefunded"])
121 states[2]["fundOwner"] = "changed"
122 uassert.Equal(t, vaultTest.Player1.String(), states[3]["fundOwner"])
123 uassert.Equal(t, vaultTest.Player1, GetEntryFund(fundID).Owner)
124
125 testing.SetOriginCaller(vaultTest.Operator)
126 testing.SetRealm(testing.NewUserRealm(vaultTest.Operator))
127 testing.SetOriginSend(chain.Coins{})
128 RefundEntryFund(cross(cur), fundID, "refund:entry-states")
129 states = ListEntryRefundStates("entry:states", vaultTest.Player1.String(), "entry:1")
130 uassert.Equal(t, "true", states[0]["fundRefunded"])
131 uassert.Equal(t, "25", states[0]["fundAmount"])
132}
133
134func TestPaymentStateQueriesCSV(cur realm, t *testing.T) {
135 vaultTest.Setup(cross(cur), t)
136 queries := []struct {
137 query func(string, string, string) []map[string]string
138 mismatch string
139 keyName string
140 }{
141 {ListEntryRefundStates, "entry refund value count mismatch", "entry key"},
142 {ListParticipationPaymentStates, "participation payment value count mismatch", "payment key"},
143 }
144 for _, item := range queries {
145 uassert.Equal(t, 0, len(item.query("", "", "")))
146 uassert.PanicsWithMessage(t, cur, item.mismatch, func() {
147 item.query("missing,missing", vaultTest.Player1.String(), "key")
148 })
149 uassert.PanicsWithMessage(t, cur, "process key length must be between 1 and 128", func() {
150 item.query("", vaultTest.Player1.String(), "key")
151 })
152 uassert.PanicsWithMessage(t, cur, "invalid participation owner", func() {
153 item.query("missing", "invalid", "key")
154 })
155 uassert.PanicsWithMessage(t, cur, item.keyName+" length must be between 1 and 128", func() {
156 item.query("missing", vaultTest.Player1.String(), "")
157 })
158 uassert.PanicsWithMessage(t, cur, "process key length must be between 1 and 128", func() {
159 item.query("missing,", vaultTest.Player1.String()+",", "key,")
160 })
161 uassert.PanicsWithMessage(t, cur, "process key length must be between 1 and 128", func() {
162 item.query("missing,,missing", strings.Repeat(vaultTest.Player1.String()+",", 2)+vaultTest.Player1.String(), "key,key,key")
163 })
164 processes := strings.Repeat("missing,", gameVaultList-1) + "missing"
165 owners := strings.Repeat(vaultTest.Player1.String()+",", gameVaultList-1) + vaultTest.Player1.String()
166 keys := strings.Repeat("key,", gameVaultList-1) + "key"
167 uassert.Equal(t, gameVaultList, len(item.query(processes, owners, keys)))
168 uassert.PanicsWithMessage(t, cur, "count exceeds game vault list limit", func() {
169 item.query(processes+",missing", owners+","+vaultTest.Player1.String(), keys+",key")
170 })
171 }
172}
173
174func TestListParticipationPaymentStates(cur realm, t *testing.T) {
175 vaultTest.Setup(cross(cur), t)
176 vaultTest.CreatePool(cross(cur), "pool:payment-states")
177 processID := vaultTest.CreateParticipationProcess(cross(cur), "process:states", "pool:payment-states", 25)
178 fundID := vaultTest.DepositParticipation(cross(cur), vaultTest.Player1, processID, "participation:1", "payment:1", 25)
179 states := ListParticipationPaymentStates(
180 "process:missing,process:states,process:states,process:states",
181 strings.Repeat(vaultTest.Player1.String()+",", 3)+vaultTest.Player1.String(),
182 "payment:1,payment:missing,payment:1,payment:1",
183 )
184 uassert.Equal(t, 4, len(states))
185 uassert.Equal(t, "process:missing", states[0]["requestedProcessKey"])
186 uassert.Equal(t, "0", states[0]["processId"])
187 uassert.Equal(t, "0", states[0]["fundId"])
188 uassert.Equal(t, strconv.FormatUint(processID, 10), states[1]["processId"])
189 uassert.Equal(t, "0", states[1]["fundId"])
190 uassert.Equal(t, "25", states[2]["participationFee"])
191 uassert.Equal(t, strconv.FormatUint(fundID, 10), states[2]["fundId"])
192 uassert.Equal(t, "payment:1", states[2]["fundPaymentKey"])
193 uassert.Equal(t, "participation:1", states[2]["participationKey"])
194 uassert.Equal(t, "1", states[2]["fundEffectiveStatus"])
195 states[2]["fundOwner"] = "changed"
196 uassert.Equal(t, vaultTest.Player1.String(), states[3]["fundOwner"])
197 uassert.Equal(t, vaultTest.Player1, GetParticipationFund(fundID).Owner)
198
199 testing.SetOriginCaller(vaultTest.Operator)
200 testing.SetRealm(testing.NewUserRealm(vaultTest.Operator))
201 testing.SetOriginSend(chain.Coins{})
202 RefundParticipationFund(cross(cur), fundID, "refund:payment-states")
203 states = ListParticipationPaymentStates("process:states", vaultTest.Player1.String(), "payment:1")
204 uassert.Equal(t, "true", states[0]["fundRefunded"])
205 uassert.Equal(t, "3", states[0]["fundEffectiveStatus"])
206 CloseParticipationProcess(cross(cur), processID)
207 CommitParticipationProcess(cross(cur), processID, "commit:payment-states")
208 states = ListParticipationPaymentStates("process:states", vaultTest.Player1.String(), "payment:1")
209 uassert.Equal(t, "3", states[0]["processStatus"])
210 uassert.Equal(t, "3", states[0]["fundEffectiveStatus"])
211}
212
213func TestParticipationPaymentValidation(cur realm, t *testing.T) {
214 vaultTest.Setup(cross(cur), t)
215 vaultTest.CreatePool(cross(cur), "pool:validation")
216 processID := vaultTest.CreateParticipationProcess(cross(cur), "participation:validation", "pool:validation", 25)
217
218 uassert.AbortsWithMessage(t, cur, "exact payment required: expected 25ugnot, got 24ugnot", func() {
219 vaultTest.DepositParticipation(cross(cur), vaultTest.Player1, processID, "participant:1", "payment:under", 24)
220 })
221 uassert.AbortsWithMessage(t, cur, "exact payment required: expected 25ugnot, got 26ugnot", func() {
222 vaultTest.DepositParticipation(cross(cur), vaultTest.Player1, processID, "participant:1", "payment:over", 26)
223 })
224 testing.SetOriginCaller(vaultTest.Player1)
225 testing.SetRealm(testing.NewUserRealm(vaultTest.Player1))
226 wrongDenom := chain.Coins{{"utest", 25}}
227 testing.IssueCoins(chain.PackageAddress("gno.land/r/akkadia/beta/game_vault"), wrongDenom)
228 testing.SetOriginSend(wrongDenom)
229 uassert.AbortsWithMessage(t, cur, "exact payment required: expected 25ugnot, got 25utest", func() {
230 DepositParticipation(cross(cur), processID, "participant:1", "payment:wrong-denom")
231 })
232 vaultTest.DepositParticipation(cross(cur), vaultTest.Player1, processID, "participant:1", "payment:1", 25)
233 uassert.AbortsWithMessage(t, cur, "payment key already processed", func() {
234 vaultTest.DepositParticipation(cross(cur), vaultTest.Player1, processID, "participant:2", "payment:1", 25)
235 })
236}
237
238func TestVaultRejectsUnexpectedCoinsAndOverflow(cur realm, t *testing.T) {
239 vaultTest.Setup(cross(cur), t)
240 testing.SetOriginCaller(vaultTest.Operator)
241 testing.SetRealm(testing.NewUserRealm(vaultTest.Operator))
242 coins := chain.Coins{{"ugnot", 1}}
243 testing.IssueCoins(chain.PackageAddress("gno.land/r/akkadia/beta/game_vault"), coins)
244 testing.SetOriginSend(coins)
245 uassert.AbortsWithMessage(t, cur, "attached coins not allowed", func() {
246 CreateRewardPool(cross(cur), "pool:coins", vaultTest.GameWorldID)
247 })
248
249 vaultTest.CreatePool(cross(cur), "pool:overflow")
250 processID := vaultTest.CreateParticipationProcess(cross(cur), "participation:overflow", "pool:overflow", 1)
251 accountedUgnotTotal = maxInt64
252 uassert.AbortsWithMessage(t, cur, "vault fund amount overflow", func() {
253 vaultTest.DepositParticipation(cross(cur), vaultTest.Player1, processID, "participant:1", "payment:overflow", 1)
254 })
255}
256
257func TestVaultRejectsMissingGameWorld(cur realm, t *testing.T) {
258 vaultTest.Setup(cross(cur), t)
259 testing.SetOriginCaller(vaultTest.Operator)
260 testing.SetRealm(testing.NewUserRealm(vaultTest.Operator))
261 testing.SetOriginSend(chain.Coins{})
262
263 uassert.AbortsWithMessage(t, cur, "game world not found: 2", func() {
264 CreateRewardPool(cross(cur), "pool:missing-world", vaultTest.GameWorldID+1)
265 })
266}
267
268func TestParticipationProcessRequiresRewardPoolKey(cur realm, t *testing.T) {
269 vaultTest.Setup(cross(cur), t)
270 uassert.AbortsWithMessage(t, cur, "reward pool not found: pool:missing", func() {
271 vaultTest.CreateParticipationProcess(cross(cur), "participation:missing", "pool:missing", 10)
272 })
273}
274
275func TestEntryProcessFundingAndRefund(cur realm, t *testing.T) {
276 vaultTest.Setup(cross(cur), t)
277 processID := vaultTest.CreateEntryProcess(cross(cur), "entry:1", 10)
278
279 firstFundID := vaultTest.DepositEntry(cross(cur), vaultTest.Player1, processID, "participant:1", "entry:1", 10)
280 secondFundID := vaultTest.DepositEntry(cross(cur), vaultTest.Player1, processID, "participant:1", "entry:2", 10)
281 vaultTest.DepositEntry(cross(cur), vaultTest.Player2, processID, "participant:1", "entry:1", 10)
282
283 uassert.Equal(t, firstFundID, GetEntryFundID(processID, vaultTest.Player1, "entry:1"))
284 uassert.Equal(t, 2, GetEntryFundCount(processID, vaultTest.Player1, "participant:1"))
285 ids := ListEntryFundIDs(processID, vaultTest.Player1, "participant:1", 1, 10)
286 uassert.Equal(t, 2, len(ids))
287 uassert.Equal(t, secondFundID, ids[0])
288 uassert.Equal(t, firstFundID, ids[1])
289
290 testing.SetOriginCaller(vaultTest.Operator)
291 testing.SetRealm(testing.NewUserRealm(vaultTest.Operator))
292 testing.SetOriginSend(chain.Coins{})
293 CloseEntryProcess(cross(cur), processID)
294 RefundEntryFund(cross(cur), firstFundID, "entry-refund:1")
295 uassert.Equal(t, int(EntryFundStatusRefunded), int(GetEntryFundStatus(firstFundID)))
296 uassert.Equal(t, int64(20), GetEntryProcess(processID).HeldBalance)
297}
298
299func TestEntryProcessValidationAndCancel(cur realm, t *testing.T) {
300 vaultTest.Setup(cross(cur), t)
301 uassert.AbortsWithMessage(t, cur, "entry fee must be positive", func() {
302 vaultTest.CreateEntryProcess(cross(cur), "entry:free", 0)
303 })
304 processID := vaultTest.CreateEntryProcess(cross(cur), "entry:cancel", 10)
305 vaultTest.DepositEntry(cross(cur), vaultTest.Player1, processID, "participant:1", "entry:1", 10)
306 uassert.AbortsWithMessage(t, cur, "entry key already processed", func() {
307 vaultTest.DepositEntry(cross(cur), vaultTest.Player1, processID, "participant:2", "entry:1", 10)
308 })
309
310 testing.SetOriginCaller(vaultTest.Operator)
311 testing.SetRealm(testing.NewUserRealm(vaultTest.Operator))
312 testing.SetOriginSend(chain.Coins{})
313 CancelEntryProcess(cross(cur), processID)
314 uassert.Equal(t, int(EntryProcessStatusCanceled), int(GetEntryProcess(processID).Status))
315 uassert.AbortsWithMessage(t, cur, "entry process is not open", func() {
316 vaultTest.DepositEntry(cross(cur), vaultTest.Player2, processID, "participant:2", "entry:2", 10)
317 })
318}