Search Apps Documentation Source Content File Folder Download Copy Actions Download

operator_faucet.gno

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