diff --git a/app/app_configure.go b/app/app_configure.go index 0e33039c75..9bff760115 100644 --- a/app/app_configure.go +++ b/app/app_configure.go @@ -104,6 +104,7 @@ func (app *AkashApp) setAkashKeepers() { app.keys[escrow.StoreKey], app.Keepers.Cosmos.Bank, app.Keepers.Akash.Take, + app.Keepers.Cosmos.Distr, ) app.Keepers.Akash.Deployment = deployment.NewKeeper( diff --git a/testutil/state/suite.go b/testutil/state/suite.go index 43a725797d..c9c04ac20b 100644 --- a/testutil/state/suite.go +++ b/testutil/state/suite.go @@ -4,6 +4,7 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/stretchr/testify/mock" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -46,6 +47,7 @@ type Keepers struct { Deployment dkeeper.IKeeper Provider pkeeper.IKeeper Bank *emocks.BankKeeper + Distr *emocks.DistrKeeper } // SetupTestSuite provides toolkit for accessing stores and keepers @@ -66,6 +68,15 @@ func SetupTestSuiteWithKeepers(t testing.TB, keepers Keepers) *TestSuite { keepers.Bank = bkeeper } + if keepers.Distr == nil { + dkeeper := &emocks.DistrKeeper{} + dkeeper. + On("GetFeePool", mock.Anything). + Return(distrtypes.FeePool{}) + dkeeper.On("SetFeePool", mock.Anything, mock.Anything). + Return() + } + app := app.Setup(false) if keepers.Audit == nil { @@ -77,7 +88,7 @@ func SetupTestSuiteWithKeepers(t testing.TB, keepers Keepers) *TestSuite { } if keepers.Escrow == nil { - keepers.Escrow = ekeeper.NewKeeper(etypes.ModuleCdc, app.GetKey(etypes.StoreKey), keepers.Bank, keepers.Take) + keepers.Escrow = ekeeper.NewKeeper(etypes.ModuleCdc, app.GetKey(etypes.StoreKey), keepers.Bank, keepers.Take, keepers.Distr) } if keepers.Market == nil { keepers.Market = mkeeper.NewKeeper(mtypes.ModuleCdc, app.GetKey(mtypes.StoreKey), app.GetSubspace(mtypes.ModuleName), keepers.Escrow) diff --git a/x/escrow/keeper/external.go b/x/escrow/keeper/external.go index 1f73f5f47d..e7f0907c6a 100644 --- a/x/escrow/keeper/external.go +++ b/x/escrow/keeper/external.go @@ -2,6 +2,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" ) //go:generate mockery --name BankKeeper --output ./mocks @@ -15,3 +16,9 @@ type BankKeeper interface { type TakeKeeper interface { SubtractFees(ctx sdk.Context, amt sdk.Coin) (sdk.Coin, sdk.Coin, error) } + +//go:generate mockery --name DistrKeeper --output ./mocks +type DistrKeeper interface { + GetFeePool(ctx sdk.Context) distrtypes.FeePool + SetFeePool(ctx sdk.Context, pool distrtypes.FeePool) +} diff --git a/x/escrow/keeper/keeper.go b/x/escrow/keeper/keeper.go index c767321f55..cd9bfd095c 100644 --- a/x/escrow/keeper/keeper.go +++ b/x/escrow/keeper/keeper.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" types "github.com/akash-network/akash-api/go/node/escrow/v1beta3" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" ) type AccountHook func(sdk.Context, types.Account) @@ -34,12 +35,13 @@ type Keeper interface { SavePayment(sdk.Context, types.FractionalPayment) } -func NewKeeper(cdc codec.BinaryCodec, skey sdk.StoreKey, bkeeper BankKeeper, tkeeper TakeKeeper) Keeper { +func NewKeeper(cdc codec.BinaryCodec, skey sdk.StoreKey, bkeeper BankKeeper, tkeeper TakeKeeper, dkeeper DistrKeeper) Keeper { return &keeper{ cdc: cdc, skey: skey, bkeeper: bkeeper, tkeeper: tkeeper, + dkeeper: dkeeper, } } @@ -48,6 +50,7 @@ type keeper struct { skey sdk.StoreKey bkeeper BankKeeper tkeeper TakeKeeper + dkeeper DistrKeeper hooks struct { onAccountClosed []AccountHook @@ -545,11 +548,9 @@ func (k *keeper) paymentWithdraw(ctx sdk.Context, obj *types.FractionalPayment) return err } - if !fee.IsZero() { - if err := k.bkeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, "community", sdk.NewCoins(fee)); err != nil { - ctx.Logger().Error("payment withdraw - fees", "err", err, "account", obj.AccountID, "payment", obj.PaymentID) - return err - } + if err := k.sendFeeToCommunityPool(ctx, fee); err != nil { + ctx.Logger().Error("payment withdraw - fees", "err", err, "account", obj.AccountID, "payment", obj.PaymentID) + return err } if !earnings.IsZero() { @@ -568,6 +569,26 @@ func (k *keeper) paymentWithdraw(ctx sdk.Context, obj *types.FractionalPayment) return nil } +func (k keeper) sendFeeToCommunityPool(ctx sdk.Context, fee sdk.Coin) error { + + if fee.IsZero() { + return nil + } + + // see https://github.com/cosmos/cosmos-sdk/blob/c2a07cea272a7878b5bc2ec160eb58ca83794214/x/distribution/keeper/keeper.go#L251-L263 + + if err := k.bkeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, distrtypes.ModuleName, sdk.NewCoins(fee)); err != nil { + return err + } + + pool := k.dkeeper.GetFeePool(ctx) + + pool.CommunityPool = pool.CommunityPool.Add(sdk.NewDecCoinFromCoin(fee)) + k.dkeeper.SetFeePool(ctx, pool) + + return nil +} + func accountSettleFullblocks( account types.Account, payments []types.FractionalPayment, diff --git a/x/escrow/keeper/mocks/distr_keeper.go b/x/escrow/keeper/mocks/distr_keeper.go new file mode 100644 index 0000000000..de24d87f79 --- /dev/null +++ b/x/escrow/keeper/mocks/distr_keeper.go @@ -0,0 +1,115 @@ +// Code generated by mockery v2.24.0. DO NOT EDIT. + +package mocks + +import ( + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + + mock "github.com/stretchr/testify/mock" + + types "github.com/cosmos/cosmos-sdk/types" +) + +// DistrKeeper is an autogenerated mock type for the DistrKeeper type +type DistrKeeper struct { + mock.Mock +} + +type DistrKeeper_Expecter struct { + mock *mock.Mock +} + +func (_m *DistrKeeper) EXPECT() *DistrKeeper_Expecter { + return &DistrKeeper_Expecter{mock: &_m.Mock} +} + +// GetFeePool provides a mock function with given fields: ctx +func (_m *DistrKeeper) GetFeePool(ctx types.Context) distributiontypes.FeePool { + ret := _m.Called(ctx) + + var r0 distributiontypes.FeePool + if rf, ok := ret.Get(0).(func(types.Context) distributiontypes.FeePool); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(distributiontypes.FeePool) + } + + return r0 +} + +// DistrKeeper_GetFeePool_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFeePool' +type DistrKeeper_GetFeePool_Call struct { + *mock.Call +} + +// GetFeePool is a helper method to define mock.On call +// - ctx types.Context +func (_e *DistrKeeper_Expecter) GetFeePool(ctx interface{}) *DistrKeeper_GetFeePool_Call { + return &DistrKeeper_GetFeePool_Call{Call: _e.mock.On("GetFeePool", ctx)} +} + +func (_c *DistrKeeper_GetFeePool_Call) Run(run func(ctx types.Context)) *DistrKeeper_GetFeePool_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.Context)) + }) + return _c +} + +func (_c *DistrKeeper_GetFeePool_Call) Return(_a0 distributiontypes.FeePool) *DistrKeeper_GetFeePool_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DistrKeeper_GetFeePool_Call) RunAndReturn(run func(types.Context) distributiontypes.FeePool) *DistrKeeper_GetFeePool_Call { + _c.Call.Return(run) + return _c +} + +// SetFeePool provides a mock function with given fields: ctx, pool +func (_m *DistrKeeper) SetFeePool(ctx types.Context, pool distributiontypes.FeePool) { + _m.Called(ctx, pool) +} + +// DistrKeeper_SetFeePool_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetFeePool' +type DistrKeeper_SetFeePool_Call struct { + *mock.Call +} + +// SetFeePool is a helper method to define mock.On call +// - ctx types.Context +// - pool distributiontypes.FeePool +func (_e *DistrKeeper_Expecter) SetFeePool(ctx interface{}, pool interface{}) *DistrKeeper_SetFeePool_Call { + return &DistrKeeper_SetFeePool_Call{Call: _e.mock.On("SetFeePool", ctx, pool)} +} + +func (_c *DistrKeeper_SetFeePool_Call) Run(run func(ctx types.Context, pool distributiontypes.FeePool)) *DistrKeeper_SetFeePool_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.Context), args[1].(distributiontypes.FeePool)) + }) + return _c +} + +func (_c *DistrKeeper_SetFeePool_Call) Return() *DistrKeeper_SetFeePool_Call { + _c.Call.Return() + return _c +} + +func (_c *DistrKeeper_SetFeePool_Call) RunAndReturn(run func(types.Context, distributiontypes.FeePool)) *DistrKeeper_SetFeePool_Call { + _c.Call.Return(run) + return _c +} + +type mockConstructorTestingTNewDistrKeeper interface { + mock.TestingT + Cleanup(func()) +} + +// NewDistrKeeper creates a new instance of DistrKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewDistrKeeper(t mockConstructorTestingTNewDistrKeeper) *DistrKeeper { + mock := &DistrKeeper{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +}