treasury_test.gno
9.01 Kb ยท 332 lines
1package test
2
3import (
4 "chain"
5 "chain/banker"
6 "chain/runtime"
7 "sort"
8 "strings"
9 "testing"
10
11 "gno.land/p/demo/tokens/grc20"
12 "gno.land/p/nt/fqname"
13 "gno.land/p/nt/testutils"
14 trs_pkg "gno.land/p/nt/treasury"
15 "gno.land/p/nt/uassert"
16
17 "gno.land/r/demo/defi/grc20reg"
18 "gno.land/r/gov/dao"
19 "gno.land/r/gov/dao/v3/impl"
20 "gno.land/r/gov/dao/v3/treasury"
21)
22
23var (
24 user1Addr = testutils.TestAddress("g1user1")
25 user2Addr = testutils.TestAddress("g1user2")
26 treasuryAddr = chain.PackageAddress("gno.land/r/gov/dao/v3/treasury")
27 allowedRealm = testing.NewCodeRealm("gno.land/r/test/allowed")
28 notAllowedRealm = testing.NewCodeRealm("gno.land/r/test/notallowed")
29 mintAmount = int64(1000)
30)
31
32// Define a dummy trs_pkg.Payment type for testing purposes.
33type dummyPayment struct {
34 bankerID string
35 str string
36}
37
38var _ trs_pkg.Payment = (*dummyPayment)(nil)
39
40func (dp *dummyPayment) BankerID() string { return dp.bankerID }
41func (dp *dummyPayment) String() string { return dp.str }
42
43func init() {
44 // Register allowed Realm path.
45 dao.UpdateImpl(cross, dao.UpdateRequest{
46 DAO: impl.NewGovDAO(),
47 AllowedDAOs: []string{allowedRealm.PkgPath()},
48 })
49}
50
51func ugnotCoins(t *testing.T, amount int64) chain.Coins {
52 t.Helper()
53
54 // Create a new coin with the ugnot denomination.
55 return chain.NewCoins(chain.NewCoin("ugnot", amount))
56}
57
58func ugnotBalance(t *testing.T, addr address) int64 {
59 t.Helper()
60
61 // Get the balance of ugnot coins for the given address.
62 banker_ := banker.NewBanker(banker.BankerTypeReadonly)
63 coins := banker_.GetCoins(addr)
64
65 return coins.AmountOf("ugnot")
66}
67
68// Define a keyedToken type to hold the token and its key.
69type keyedToken struct {
70 key string
71 token *grc20.Token
72}
73
74func registerGRC20Tokens(t *testing.T, tokenNames []string, toMint address) []keyedToken {
75 t.Helper()
76
77 var (
78 keyedTokens = make([]keyedToken, 0, len(tokenNames))
79 keys = make([]string, 0, len(tokenNames))
80 )
81
82 for _, name := range tokenNames {
83 // Create the token.
84 symbol := strings.ToUpper(name)
85 token, ledger := grc20.NewToken(name, symbol, 0)
86
87 // Register the token.
88 grc20reg.Register(cross, token, symbol)
89
90 // Mint tokens to the specified address.
91 ledger.Mint(toMint, mintAmount)
92
93 // Add the token and key to the lists.
94 key := fqname.Construct(runtime.CurrentRealm().PkgPath(), symbol)
95 keyedTokens = append(keyedTokens, keyedToken{key: key, token: token})
96 keys = append(keys, key)
97 }
98
99 // Set the token keys in the treasury.
100 treasury.SetTokenKeys(cross, keys)
101
102 return keyedTokens
103}
104
105func TestAllowedDAOs(t *testing.T) {
106 // Set the current Realm to the not allowed one.
107 testing.SetRealm(notAllowedRealm)
108
109 // Define a dummy payment to test sending.
110 dummyP := &dummyPayment{bankerID: "Dummy"}
111
112 // Try to send, it should abort because the Realm is not allowed.
113 uassert.AbortsWithMessage(
114 t,
115 "this Realm is not allowed to send payment: "+notAllowedRealm.PkgPath(),
116 func() { treasury.Send(cross, dummyP) },
117 )
118
119 // Set the current Realm to the allowed one.
120 testing.SetRealm(allowedRealm)
121
122 // Try to send, it should not abort because the Realm is allowed,
123 // but because the dummy banker ID is not registered.
124 uassert.AbortsWithMessage(
125 t,
126 "banker not found: "+dummyP.BankerID(),
127 func() { treasury.Send(cross, dummyP) },
128 )
129}
130
131func TestRegisteredBankers(t *testing.T) {
132 // Set the current Realm to the allowed one.
133 testing.SetRealm(allowedRealm)
134
135 // Define the expected banker IDs.
136 expectedBankerIDs := []string{
137 trs_pkg.CoinsBanker{}.ID(),
138 trs_pkg.GRC20Banker{}.ID(),
139 }
140
141 // Get the registered bankers from the treasury and compare their lengths.
142 registeredBankerIDs := treasury.ListBankerIDs()
143 uassert.Equal(t, len(registeredBankerIDs), len(expectedBankerIDs))
144
145 // Sort both slices then compare them.
146 sort.StringSlice(expectedBankerIDs).Sort()
147 sort.StringSlice(registeredBankerIDs).Sort()
148
149 for i := range expectedBankerIDs {
150 uassert.Equal(t, expectedBankerIDs[i], registeredBankerIDs[i])
151 }
152
153 // Test HasBanker method.
154 for _, bankerID := range expectedBankerIDs {
155 uassert.True(t, treasury.HasBanker(bankerID))
156 }
157 uassert.False(t, treasury.HasBanker("UnknownBankerID"))
158
159 // Test Address method.
160 for _, bankerID := range expectedBankerIDs {
161 // The two bankers used for now should have the treasury Realm address.
162 uassert.Equal(t, treasury.Address(bankerID), treasuryAddr.String())
163 }
164}
165
166func TestSendGRC20Payment(t *testing.T) {
167 // Set the current Realm to the allowed one.
168 testing.SetRealm(allowedRealm)
169
170 // Try to send a GRC20 payment with a not registered token, it should abort.
171 uassert.AbortsWithMessage(
172 t,
173 "failed to send payment: GRC20 token not found: UNKNOW",
174 func() {
175 treasury.Send(cross, trs_pkg.NewGRC20Payment("UNKNOW", 100, user1Addr))
176 },
177 )
178
179 // Create 3 GRC20 tokens and register them.
180 keyedTokens := registerGRC20Tokens(
181 t,
182 []string{"TestToken0", "TestToken1", "TestToken2"},
183 treasuryAddr,
184 )
185
186 const txAmount = 42
187
188 // For each token-user pair.
189 for i, userAddr := range []address{user1Addr, user2Addr} {
190 for _, keyed := range keyedTokens {
191 // Check that the treasury has the expected balance before sending.
192 uassert.Equal(t, keyed.token.BalanceOf(treasuryAddr), mintAmount-int64(txAmount*i))
193
194 // Check that the user has no balance before sending.
195 uassert.Equal(t, keyed.token.BalanceOf(userAddr), int64(0))
196
197 // Try to send a GRC20 payment with a registered token, it should not abort.
198 uassert.NotAborts(t, func() {
199 treasury.Send(
200 cross,
201 trs_pkg.NewGRC20Payment(
202 keyed.key,
203 txAmount,
204 userAddr,
205 ),
206 )
207 })
208
209 // Check that the user has the expected balance after sending.
210 uassert.Equal(t, keyed.token.BalanceOf(userAddr), int64(txAmount))
211
212 // Check that the treasury has the expected balance after sending.
213 uassert.Equal(t, keyed.token.BalanceOf(treasuryAddr), mintAmount-int64(txAmount*(i+1)))
214 }
215 }
216
217 // Get the GRC20Banker ID.
218 grc20BankerID := trs_pkg.GRC20Banker{}.ID()
219
220 // Test Balances method for the GRC20Banker.
221 balances := treasury.Balances(grc20BankerID)
222 uassert.Equal(t, len(balances), len(keyedTokens))
223
224 compared := 0
225 for _, balance := range balances {
226 for _, keyed := range keyedTokens {
227 if balance.Denom == keyed.key {
228 uassert.Equal(t, balance.Amount, keyed.token.BalanceOf(treasuryAddr))
229 compared++
230 }
231 }
232 }
233 uassert.Equal(t, compared, len(keyedTokens))
234
235 // Check the history of the GRC20Banker.
236 history := treasury.History(grc20BankerID, 1, 10)
237 uassert.Equal(t, len(history), 6)
238
239 // Try to send a dummy payment with the GRC20 banker ID, it should abort.
240 uassert.AbortsWithMessage(
241 t,
242 "failed to send payment: invalid payment type",
243 func() {
244 treasury.Send(cross, &dummyPayment{bankerID: grc20BankerID})
245 },
246 )
247
248 // Try to send a GRC20 payment without enough balance, it should abort.
249 uassert.AbortsWithMessage(
250 t,
251 "failed to send payment: insufficient balance",
252 func() {
253 treasury.Send(
254 cross,
255 trs_pkg.NewGRC20Payment(
256 keyedTokens[0].key,
257 mintAmount*42, // Try to send more than the treasury has.
258 user1Addr,
259 ),
260 )
261 },
262 )
263
264 // Check the history of the GRC20Banker.
265 history = treasury.History(grc20BankerID, 1, 10)
266 uassert.Equal(t, len(history), 6)
267}
268
269func TestSendCoinPayment(t *testing.T) {
270 // Set the current Realm to the allowed one.
271 testing.SetRealm(allowedRealm)
272
273 // Issue initial ugnot coins to the treasury address.
274 testing.IssueCoins(treasuryAddr, ugnotCoins(t, mintAmount))
275
276 // Get the CoinsBanker ID.
277 bankerID := trs_pkg.CoinsBanker{}.ID()
278
279 // Define helper function to check balances and history.
280 var (
281 expectedTreasuryBalance = mintAmount
282 expectedUser1Balance = int64(0)
283 expectedUser2Balance = int64(0)
284 expectedHistoryLen = 0
285 checkHistoryAndBalances = func() {
286 t.Helper()
287
288 uassert.Equal(t, ugnotBalance(t, treasuryAddr), expectedTreasuryBalance)
289 uassert.Equal(t, ugnotBalance(t, user1Addr), expectedUser1Balance)
290 uassert.Equal(t, ugnotBalance(t, user2Addr), expectedUser2Balance)
291
292 // Check treasury.Balances returned value.
293 balances := treasury.Balances(bankerID)
294 uassert.Equal(t, len(balances), 1)
295 uassert.Equal(t, balances[0].Denom, "ugnot")
296 uassert.Equal(t, balances[0].Amount, expectedTreasuryBalance)
297
298 // Check treasury.History returned value.
299 history := treasury.History(bankerID, 1, expectedHistoryLen+1)
300 uassert.Equal(t, len(history), expectedHistoryLen)
301 }
302 )
303
304 // Check initial balances and history.
305 checkHistoryAndBalances()
306
307 const txAmount = int64(42)
308
309 // Treasury send coins.
310 for i := int64(0); i < 3; i++ {
311 // Send ugnot coins to user1 and user2.
312 uassert.NotAborts(t, func() {
313 treasury.Send(
314 cross,
315 trs_pkg.NewCoinsPayment(ugnotCoins(t, txAmount), user1Addr),
316 )
317 treasury.Send(
318 cross,
319 trs_pkg.NewCoinsPayment(ugnotCoins(t, txAmount), user2Addr),
320 )
321 })
322
323 // Update expected balances and history length.
324 expectedTreasuryBalance = mintAmount - txAmount*2*(i+1)
325 expectedUser1Balance = txAmount * (i + 1)
326 expectedUser2Balance = expectedUser1Balance
327 expectedHistoryLen = int(2 * (i + 1))
328
329 // Check balances and history after sending.
330 checkHistoryAndBalances()
331 }
332}