Skip to content

Commit 2eb6cde

Browse files
authored
fix: fix broken x/foundation invariant on treasury (#946)
* TruncateDecimal first * Refactor CollectFoundationTax * Update tests * Refactor tests * Update CHANGELOG.md * Apply feedbacks on the PR * Revert the changes in CollectFoundationTax's signature * Ensure the behavior does not change
1 parent b948bbd commit 2eb6cde

File tree

6 files changed

+48
-41
lines changed

6 files changed

+48
-41
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
4949
* (swagger) [\#898](https://github.com/line/lbm-sdk/pull/898) fix a bug not added `lbm.tx.v1beta1.Service/GetBlockWithTxs` in swagger
5050
* (x/collection) [\#911](https://github.com/line/lbm-sdk/pull/911) Add missing command(TxCmdModify) for CLI
5151
* (x/foundation) [\#922](https://github.com/line/lbm-sdk/pull/922) Propagate events in x/foundation through sdk.Results
52+
* (x/foundation) [\#946](https://github.com/line/lbm-sdk/pull/946) Fix broken x/foundation invariant on treasury
5253

5354
### Removed
5455

x/foundation/expected_keepers.go

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ type (
1717
BankKeeper interface {
1818
GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
1919

20-
SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) error
2120
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
2221
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
2322
}

x/foundation/keeper/internal/abci_test.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import (
99
func (s *KeeperTestSuite) TestBeginBlocker() {
1010
ctx, _ := s.ctx.CacheContext()
1111

12+
taxRatio := sdk.MustNewDecFromStr("0.123456789")
1213
s.impl.SetParams(ctx, foundation.Params{
13-
FoundationTax: sdk.MustNewDecFromStr("0.5"),
14+
FoundationTax: taxRatio,
1415
})
1516

1617
before := s.impl.GetTreasury(ctx)
@@ -20,10 +21,14 @@ func (s *KeeperTestSuite) TestBeginBlocker() {
2021
// collect
2122
internal.BeginBlocker(ctx, s.impl)
2223

24+
tax := sdk.NewDecFromInt(s.balance).MulTruncate(taxRatio).TruncateInt()
25+
// ensure the behavior does not change
26+
s.Require().Equal(sdk.NewInt(121932631), tax)
27+
28+
expectedAfter := s.balance.Add(tax)
2329
after := s.impl.GetTreasury(ctx)
2430
s.Require().Equal(1, len(after))
25-
// s.balance + s.balance * 0.5
26-
s.Require().Equal(sdk.NewDecFromInt(s.balance.Add(s.balance.Quo(sdk.NewInt(2)))), after[0].Amount)
31+
s.Require().Equal(sdk.NewDecFromInt(expectedAfter), after[0].Amount)
2732
}
2833

2934
func (s *KeeperTestSuite) TestEndBlocker() {

x/foundation/keeper/internal/keeper_test.go

+21-19
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ type KeeperTestSuite struct {
2323
suite.Suite
2424
ctx sdk.Context
2525

26-
app *simapp.SimApp
27-
keeper keeper.Keeper
28-
impl internal.Keeper
26+
bankKeeper foundation.BankKeeper
27+
keeper keeper.Keeper
28+
impl internal.Keeper
29+
2930
queryServer foundation.QueryServer
3031
msgServer foundation.MsgServer
3132
proposalHandler govtypes.Handler
@@ -54,18 +55,19 @@ func newMsgCreateDog(name string) sdk.Msg {
5455

5556
func (s *KeeperTestSuite) SetupTest() {
5657
checkTx := false
57-
s.app = simapp.Setup(checkTx)
58-
testdata.RegisterInterfaces(s.app.InterfaceRegistry())
59-
testdata.RegisterMsgServer(s.app.MsgServiceRouter(), testdata.MsgServerImpl{})
58+
app := simapp.Setup(checkTx)
59+
testdata.RegisterInterfaces(app.InterfaceRegistry())
60+
testdata.RegisterMsgServer(app.MsgServiceRouter(), testdata.MsgServerImpl{})
6061

61-
s.ctx = s.app.BaseApp.NewContext(checkTx, tmproto.Header{})
62-
s.keeper = s.app.FoundationKeeper
62+
s.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{})
63+
s.bankKeeper = app.BankKeeper
64+
s.keeper = app.FoundationKeeper
6365
s.impl = internal.NewKeeper(
64-
s.app.AppCodec(),
65-
s.app.GetKey(foundation.ModuleName),
66-
s.app.MsgServiceRouter(),
67-
s.app.AccountKeeper,
68-
s.app.BankKeeper,
66+
app.AppCodec(),
67+
app.GetKey(foundation.ModuleName),
68+
app.MsgServiceRouter(),
69+
app.AccountKeeper,
70+
app.BankKeeper,
6971
authtypes.FeeCollectorName,
7072
foundation.DefaultConfig(),
7173
foundation.DefaultAuthority().String(),
@@ -106,14 +108,14 @@ func (s *KeeperTestSuite) SetupTest() {
106108
s.Require().NoError(err)
107109
s.impl.SetFoundationInfo(s.ctx, info)
108110

109-
s.balance = sdk.NewInt(1000000)
111+
s.balance = sdk.NewInt(987654321)
110112
s.impl.SetPool(s.ctx, foundation.Pool{
111113
Treasury: sdk.NewDecCoinsFromCoins(sdk.NewCoin(sdk.DefaultBondDenom, s.balance)),
112114
})
113115
holders := []sdk.AccAddress{
114116
s.stranger,
115-
s.app.AccountKeeper.GetModuleAccount(s.ctx, foundation.TreasuryName).GetAddress(),
116-
s.app.AccountKeeper.GetModuleAccount(s.ctx, authtypes.FeeCollectorName).GetAddress(),
117+
app.AccountKeeper.GetModuleAccount(s.ctx, foundation.TreasuryName).GetAddress(),
118+
app.AccountKeeper.GetModuleAccount(s.ctx, authtypes.FeeCollectorName).GetAddress(),
117119
}
118120
for _, holder := range holders {
119121
amount := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, s.balance))
@@ -123,11 +125,11 @@ func (s *KeeperTestSuite) SetupTest() {
123125
// because x/bank already has dependency on x/mint, and we must have dependency
124126
// on x/bank, it's OK to use x/mint here.
125127
minterName := minttypes.ModuleName
126-
err := s.app.BankKeeper.MintCoins(s.ctx, minterName, amount)
128+
err := app.BankKeeper.MintCoins(s.ctx, minterName, amount)
127129
s.Require().NoError(err)
128130

129-
minter := s.app.AccountKeeper.GetModuleAccount(s.ctx, minterName).GetAddress()
130-
err = s.app.BankKeeper.SendCoins(s.ctx, minter, holder, amount)
131+
minter := app.AccountKeeper.GetModuleAccount(s.ctx, minterName).GetAddress()
132+
err = app.BankKeeper.SendCoins(s.ctx, minter, holder, amount)
131133
s.Require().NoError(err)
132134
}
133135

x/foundation/keeper/internal/treasury.go

+5-13
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,16 @@ import (
77
)
88

99
func (k Keeper) CollectFoundationTax(ctx sdk.Context) error {
10-
// fetch and clear the collected fees for the fund, since this is
11-
// called in BeginBlock, collected fees will be from the previous block
12-
feeCollector := k.authKeeper.GetModuleAccount(ctx, k.feeCollectorName)
13-
feesCollectedInt := k.bankKeeper.GetAllBalances(ctx, feeCollector.GetAddress())
10+
feeCollector := k.authKeeper.GetModuleAccount(ctx, k.feeCollectorName).GetAddress()
11+
feesCollectedInt := k.bankKeeper.GetAllBalances(ctx, feeCollector)
1412
feesCollected := sdk.NewDecCoinsFromCoins(feesCollectedInt...)
1513

1614
// calculate the tax
1715
taxRatio := k.GetFoundationTax(ctx)
18-
tax := feesCollected.MulDecTruncate(taxRatio)
16+
tax, _ := feesCollected.MulDecTruncate(taxRatio).TruncateDecimal()
1917

20-
// update foundation treasury
21-
pool := k.GetPool(ctx)
22-
pool.Treasury = pool.Treasury.Add(tax...)
23-
k.SetPool(ctx, pool)
24-
25-
// collect tax to the foundation treasury
26-
amount, _ := tax.TruncateDecimal()
27-
if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, k.feeCollectorName, foundation.TreasuryName, amount); err != nil {
18+
// collect the tax
19+
if err := k.FundTreasury(ctx, feeCollector, tax); err != nil {
2820
return err
2921
}
3022

x/foundation/keeper/internal/treasury_test.go

+13-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package internal_test
22

33
import (
44
sdk "github.com/line/lbm-sdk/types"
5+
authtypes "github.com/line/lbm-sdk/x/auth/types"
6+
"github.com/line/lbm-sdk/x/foundation"
57
)
68

79
func (s *KeeperTestSuite) TestFundTreasury() {
@@ -32,13 +34,16 @@ func (s *KeeperTestSuite) TestFundTreasury() {
3234
}
3335
s.Require().NoError(err)
3436

35-
after := s.impl.GetTreasury(ctx)
36-
s.Require().Equal(before.Add(sdk.NewDecCoinsFromCoins(amount...)...), after)
37+
expectedAfter := before.Add(sdk.NewDecCoinsFromCoins(amount...)...)
38+
poolAfter := s.impl.GetTreasury(ctx)
39+
s.Require().Equal(sdk.NewDecCoins(expectedAfter...), sdk.NewDecCoins(poolAfter...))
40+
balanceAfter := sdk.NewDecCoinsFromCoins(s.bankKeeper.GetAllBalances(ctx, authtypes.NewModuleAddress(foundation.TreasuryName))...)
41+
s.Require().Equal(sdk.NewDecCoins(expectedAfter...), sdk.NewDecCoins(balanceAfter...))
3742
})
3843
}
3944
}
4045

41-
func (s *KeeperTestSuite) TestWithDrawFromTreasury() {
46+
func (s *KeeperTestSuite) TestWithdrawFromTreasury() {
4247
testCases := map[string]struct {
4348
amount sdk.Int
4449
valid bool
@@ -66,8 +71,11 @@ func (s *KeeperTestSuite) TestWithDrawFromTreasury() {
6671
}
6772
s.Require().NoError(err)
6873

69-
after := s.impl.GetTreasury(ctx)
70-
s.Require().Equal(before.Sub(sdk.NewDecCoinsFromCoins(amount...)), after)
74+
expectedAfter := before.Sub(sdk.NewDecCoinsFromCoins(amount...))
75+
poolAfter := s.impl.GetTreasury(ctx)
76+
s.Require().Equal(sdk.NewDecCoins(expectedAfter...), sdk.NewDecCoins(poolAfter...))
77+
balanceAfter := sdk.NewDecCoinsFromCoins(s.bankKeeper.GetAllBalances(ctx, authtypes.NewModuleAddress(foundation.TreasuryName))...)
78+
s.Require().Equal(sdk.NewDecCoins(expectedAfter...), sdk.NewDecCoins(balanceAfter...))
7179
})
7280
}
7381
}

0 commit comments

Comments
 (0)