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}