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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

vault.gno

6.29 Kb · 231 lines
  1package game_vault
  2
  3import (
  4	"chain/runtime/unsafe"
  5	"strconv"
  6
  7	"gno.land/p/akkadia/beta/accesscontrol"
  8	"gno.land/r/akkadia/beta/admin"
  9	gameworld "gno.land/r/akkadia/beta/game_world"
 10)
 11
 12const (
 13	maxInt64      = int64(9223372036854775807)
 14	maxUint64     = uint64(18446744073709551615)
 15	gameVaultList = 100
 16)
 17
 18type RewardPoolStatus int
 19
 20const (
 21	RewardPoolStatusInvalid RewardPoolStatus = iota
 22	RewardPoolStatusOpen
 23	RewardPoolStatusLocked
 24	RewardPoolStatusSettled
 25	RewardPoolStatusCanceled
 26)
 27
 28type RewardPool struct {
 29	ID                          uint64
 30	PoolKey                     string
 31	GameWorldID                 uint64
 32	Status                      RewardPoolStatus
 33	ParticipationCommittedTotal int64
 34	SystemFundedTotal           int64
 35	SystemRefundedTotal         int64
 36	DistributedTotal            int64
 37	Balance                     int64
 38	DistributionCount           uint64
 39}
 40
 41type RewardPoolView struct {
 42	PoolKey                     string
 43	GameWorldID                 uint64
 44	Status                      RewardPoolStatus
 45	ParticipationCommittedTotal int64
 46	DistributedTotal            int64
 47	Balance                     int64
 48	DistributionCount           uint64
 49}
 50
 51func CreateRewardPool(cur realm, poolKey string, gameWorldID uint64) uint64 {
 52	accesscontrol.MustGetAdminOrOperatorCaller(0, cur, admin.IsAdmin, admin.IsOperator)
 53	assertNoAttachedCoins()
 54	assertKeyLength(poolKey, "pool key")
 55	if rewardPoolIDs.Has(poolKey) {
 56		panic("reward pool key already exists")
 57	}
 58	assertGameWorldExists(gameWorldID)
 59	if latestRewardPoolID == maxUint64 {
 60		panic("reward pool id exhausted")
 61	}
 62
 63	latestRewardPoolID++
 64	poolID := latestRewardPoolID
 65	treeSet(rewardPools, poolID, RewardPool{
 66		ID:          poolID,
 67		PoolKey:     poolKey,
 68		GameWorldID: gameWorldID,
 69		Status:      RewardPoolStatusOpen,
 70	})
 71	rewardPoolIDs.Set(poolKey, poolID)
 72	getOrCreateIDSet(gameWorldRewardPoolIDs, gameWorldID).Set(uint64Key(poolID), true)
 73	return poolID
 74}
 75
 76func LockRewardPool(cur realm, poolKey string) {
 77	accesscontrol.MustGetAdminOrOperatorCaller(0, cur, admin.IsAdmin, admin.IsOperator)
 78	assertNoAttachedCoins()
 79	poolID, pool := mustGetRewardPoolByKey(poolKey)
 80	if pool.Status == RewardPoolStatusLocked {
 81		return
 82	}
 83	if pool.Status != RewardPoolStatusOpen {
 84		panic("reward pool cannot be locked")
 85	}
 86	pool.Status = RewardPoolStatusLocked
 87	treeSet(rewardPools, poolID, pool)
 88}
 89
 90func CancelRewardPool(cur realm, poolKey string) {
 91	accesscontrol.MustGetAdminOrOperatorCaller(0, cur, admin.IsAdmin, admin.IsOperator)
 92	assertNoAttachedCoins()
 93	poolID, pool := mustGetRewardPoolByKey(poolKey)
 94	if pool.Status == RewardPoolStatusCanceled {
 95		return
 96	}
 97	if pool.Status != RewardPoolStatusOpen {
 98		panic("reward pool cannot be canceled")
 99	}
100	if pool.ParticipationCommittedTotal != 0 || pool.DistributedTotal != 0 {
101		panic("reward pool with committed funds cannot be canceled")
102	}
103	pool.Status = RewardPoolStatusCanceled
104	treeSet(rewardPools, poolID, pool)
105}
106
107func SettleRewardPool(cur realm, poolKey string) {
108	accesscontrol.MustGetAdminOrOperatorCaller(0, cur, admin.IsAdmin, admin.IsOperator)
109	assertNoAttachedCoins()
110	poolID, pool := mustGetRewardPoolByKey(poolKey)
111	if pool.Status == RewardPoolStatusSettled {
112		return
113	}
114	if pool.Status != RewardPoolStatusLocked {
115		panic("reward pool must be locked before settlement")
116	}
117	if pool.Balance != 0 {
118		panic("reward pool balance must be zero before settlement")
119	}
120	pool.Status = RewardPoolStatusSettled
121	treeSet(rewardPools, poolID, pool)
122}
123
124func GetRewardPoolID(poolKey string) uint64 {
125	assertKeyLength(poolKey, "pool key")
126	value, found := stringGet(rewardPoolIDs, poolKey)
127	if !found {
128		return 0
129	}
130	return value.(uint64)
131}
132
133func GetRewardPool(poolID uint64) RewardPool {
134	value, found := treeGet(rewardPools, poolID)
135	if !found {
136		panic("reward pool not found: " + strconv.FormatUint(poolID, 10))
137	}
138	return value.(RewardPool)
139}
140
141func GetRewardPoolByKey(poolKey string) RewardPoolView {
142	_, pool := mustGetRewardPoolByKey(poolKey)
143	return RewardPoolView{
144		PoolKey:                     pool.PoolKey,
145		GameWorldID:                 pool.GameWorldID,
146		Status:                      pool.Status,
147		ParticipationCommittedTotal: pool.ParticipationCommittedTotal,
148		DistributedTotal:            pool.DistributedTotal,
149		Balance:                     pool.Balance,
150		DistributionCount:           pool.DistributionCount,
151	}
152}
153
154func mustGetRewardPoolByKey(poolKey string) (uint64, RewardPool) {
155	poolID := GetRewardPoolID(poolKey)
156	if poolID == 0 {
157		panic("reward pool not found: " + poolKey)
158	}
159	return poolID, GetRewardPool(poolID)
160}
161
162func GetLatestRewardPoolID() uint64 { return latestRewardPoolID }
163
164func GetRewardPoolCountByGameWorld(gameWorldID uint64) int {
165	ids, found := getIDSet(gameWorldRewardPoolIDs, gameWorldID)
166	if !found {
167		return 0
168	}
169	return ids.Size()
170}
171
172func ListRewardPoolIDsByGameWorld(gameWorldID uint64, page, count int) []uint64 {
173	ids, _ := getIDSet(gameWorldRewardPoolIDs, gameWorldID)
174	return listIDs(ids, page, count)
175}
176
177func assertGameWorldExists(gameWorldID uint64) {
178	if !gameworld.HasGameWorld(gameWorldID) {
179		panic("game world not found: " + strconv.FormatUint(gameWorldID, 10))
180	}
181}
182
183func assertNoAttachedCoins() {
184	if len(unsafe.OriginSend()) != 0 {
185		panic("attached coins not allowed")
186	}
187}
188
189func assertExactUgnotPayment(expected int64) {
190	coins := unsafe.OriginSend()
191	if len(coins) != 1 || coins[0].Denom != "ugnot" || coins[0].Amount != expected {
192		panic("exact payment required: expected " + strconv.FormatInt(expected, 10) + "ugnot, got " + coins.String())
193	}
194}
195
196func getAttachedUgnotDeposit() int64 {
197	coins := unsafe.OriginSend()
198	if len(coins) != 1 || coins[0].Denom != "ugnot" || coins[0].Amount <= 0 {
199		panic("positive ugnot deposit required")
200	}
201	return coins[0].Amount
202}
203
204func assertKeyLength(value, name string) {
205	if len(value) < 1 || len(value) > 128 {
206		panic(name + " length must be between 1 and 128")
207	}
208}
209
210func assertPageCount(page, count int) {
211	if page < 1 {
212		panic("page must be at least 1")
213	}
214	if count < 1 {
215		panic("count must be at least 1")
216	}
217	if count > gameVaultList {
218		panic("count exceeds game vault list limit")
219	}
220}
221
222func assertNewOperationKey(operationKey string) {
223	assertKeyLength(operationKey, "operation key")
224	if processedOperationKeys.Has(operationKey) {
225		panic("operation key already processed")
226	}
227}
228
229func HasProcessedOperationKey(operationKey string) bool {
230	return processedOperationKeys.Has(operationKey)
231}