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

operator_faucet.gno

4.14 Kb · 172 lines
  1package admin
  2
  3import (
  4	"chain"
  5	"chain/banker"
  6
  7	"gno.land/p/akkadia/beta/accesscontrol"
  8)
  9
 10const (
 11	SetFaucetTargetAmountEvent = "SetFaucetTargetAmount"
 12	RequestFaucetEvent         = "RequestFaucet"
 13	RequestFaucetsEvent        = "RequestFaucets"
 14	WithdrawEvent              = "Withdraw"
 15)
 16
 17var (
 18	faucetTargetAmount int64
 19)
 20
 21func SetFaucetTargetAmount(cur realm, amount int64) {
 22	accesscontrol.AssertIsAdmin(0, cur, IsAdmin)
 23	assertPositiveFaucetTarget(amount)
 24
 25	oldAmount := faucetTargetAmount
 26	faucetTargetAmount = amount
 27
 28	chain.Emit(
 29		SetFaucetTargetAmountEvent,
 30		"oldAmount", int64ToString(oldAmount),
 31		"newAmount", int64ToString(amount),
 32	)
 33}
 34
 35func GetFaucetTargetAmount() int64 {
 36	return faucetTargetAmount
 37}
 38
 39func RequestFaucet(cur realm) int64 {
 40	caller := mustGetFaucetCaller(0, cur)
 41	assertPositiveFaucetTarget(faucetTargetAmount)
 42
 43	return sendFaucetDeficit(cur, caller, true)
 44}
 45
 46func RequestFaucetFor(cur realm, operator address) int64 {
 47	accesscontrol.AssertIsAdmin(0, cur, IsAdmin)
 48	assertPositiveFaucetTarget(faucetTargetAmount)
 49	assertFaucetOperator(operator)
 50
 51	return sendFaucetDeficit(cur, operator, true)
 52}
 53
 54func RequestFaucets(cur realm) int64 {
 55	accesscontrol.AssertIsAdmin(0, cur, IsAdmin)
 56	assertPositiveFaucetTarget(faucetTargetAmount)
 57
 58	bnk := banker.NewBanker(banker.BankerTypeRealmSend, cur)
 59	operators := GetOperators()
 60	deficitOperators := []address{}
 61	deficits := []int64{}
 62	totalAmount := int64(0)
 63
 64	for _, operator := range operators {
 65		deficit := getFaucetDeficit(bnk, operator)
 66		if deficit <= 0 {
 67			continue
 68		}
 69
 70		deficitOperators = append(deficitOperators, operator)
 71		deficits = append(deficits, deficit)
 72		totalAmount += deficit
 73	}
 74
 75	if totalAmount == 0 {
 76		return 0
 77	}
 78
 79	assertAdminRealmBalance(bnk, cur.Address(), totalAmount)
 80	for i, operator := range deficitOperators {
 81		sendAdminRealmUgnot(bnk, cur.Address(), operator, deficits[i])
 82		emitRequestFaucet(operator, deficits[i])
 83	}
 84
 85	chain.Emit(
 86		RequestFaucetsEvent,
 87		"amount", int64ToString(totalAmount),
 88		"targetAmount", int64ToString(faucetTargetAmount),
 89	)
 90
 91	return totalAmount
 92}
 93
 94func Withdraw(cur realm, recipient address, amount int64) int64 {
 95	accesscontrol.AssertIsAdmin(0, cur, IsAdmin)
 96	assertValidAddress(recipient)
 97	assertPositiveUgnotAmount(amount)
 98
 99	bnk := banker.NewBanker(banker.BankerTypeRealmSend, cur)
100	realmAddr := cur.Address()
101	assertAdminRealmBalance(bnk, realmAddr, amount)
102	sendAdminRealmUgnot(bnk, realmAddr, recipient, amount)
103
104	chain.Emit(
105		WithdrawEvent,
106		"recipient", recipient.String(),
107		"amount", int64ToString(amount),
108	)
109
110	return amount
111}
112
113func sendFaucetDeficit(cur realm, operator address, panicIfFunded bool) int64 {
114	bnk := banker.NewBanker(banker.BankerTypeRealmSend, cur)
115	amount := getFaucetDeficit(bnk, operator)
116	if amount <= 0 {
117		if panicIfFunded {
118			panic("operator balance is not below faucet target")
119		}
120		return 0
121	}
122
123	realmAddr := cur.Address()
124	assertAdminRealmBalance(bnk, realmAddr, amount)
125	sendAdminRealmUgnot(bnk, realmAddr, operator, amount)
126	emitRequestFaucet(operator, amount)
127
128	return amount
129}
130
131func getFaucetDeficit(bnk banker.Banker, operator address) int64 {
132	operatorBalance := bnk.GetCoins(operator).AmountOf("ugnot")
133	if operatorBalance >= faucetTargetAmount {
134		return 0
135	}
136
137	return faucetTargetAmount - operatorBalance
138}
139
140func assertAdminRealmBalance(bnk banker.Banker, realmAddr address, amount int64) {
141	realmBalance := bnk.GetCoins(realmAddr).AmountOf("ugnot")
142	if realmBalance < amount {
143		panic("admin realm balance is insufficient")
144	}
145}
146
147func sendAdminRealmUgnot(bnk banker.Banker, realmAddr address, recipient address, amount int64) {
148	coins := chain.Coins{chain.Coin{"ugnot", amount}}
149	bnk.SendCoins(realmAddr, recipient, coins)
150}
151
152func emitRequestFaucet(operator address, amount int64) {
153	chain.Emit(
154		RequestFaucetEvent,
155		"operator", operator.String(),
156		"amount", int64ToString(amount),
157		"targetAmount", int64ToString(faucetTargetAmount),
158	)
159}
160
161func mustGetFaucetCaller(_ int, rlm realm) address {
162	caller := accesscontrol.MustGetUserCaller(0, rlm)
163	assertFaucetOperator(caller)
164	return caller
165}
166
167func assertFaucetOperator(operator address) {
168	assertValidAddress(operator)
169	if !IsOperator(operator) {
170		panic("operator access required")
171	}
172}