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.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}