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}