Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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}