update lend proposals to use community pool (#1460)

* point community pool lend proposals at fee pool

* update community pool lend proposal tests

* remove unused begin blocker

* increase test coverage

* fix x/community proposal comments
This commit is contained in:
Robert Pirtle 2023-01-26 15:27:41 -08:00 committed by GitHub
parent b26e12a579
commit d05484cf88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 27 deletions

View File

@ -1,12 +0,0 @@
package community
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/community/keeper"
abci "github.com/tendermint/tendermint/abci/types"
)
// BeginBlocker runs at the start of every block.
func BeginBlocker(ctx sdk.Context, _ abci.RequestBeginBlock, k keeper.Keeper) {
// TODO: process proposals here
}

View File

@ -61,3 +61,26 @@ func TestParseWithdrawProposal(t *testing.T) {
require.Equal(t, "Withdraw some KAVA from community pool to Lend!", proposal.Description) require.Equal(t, "Withdraw some KAVA from community pool to Lend!", proposal.Description)
require.Equal(t, expectedAmount, proposal.Amount) require.Equal(t, expectedAmount, proposal.Amount)
} }
func TestParseFileNoExists(t *testing.T) {
cdc := codec.NewAminoCodec(codec.NewLegacyAmino())
_, err := utils.ParseCommunityPoolLendDepositProposal(cdc, "not-a-file.json")
require.ErrorContains(t, err, "no such file or directory")
_, err = utils.ParseCommunityPoolLendWithdrawProposal(cdc, "not-a-file.json")
require.ErrorContains(t, err, "no such file or directory")
}
func TestParseFileMalformed(t *testing.T) {
cdc := codec.NewAminoCodec(codec.NewLegacyAmino())
malformed := testutil.WriteToNewTempFile(t, `
{
"title": "I'm malformed b/c there's no closing quote,
"description": "A description",
"amount": [{"denom": "ukava", "amount": "100000000000"}]
}
`)
_, err := utils.ParseCommunityPoolLendDepositProposal(cdc, malformed.Name())
require.ErrorContains(t, err, "invalid character")
_, err = utils.ParseCommunityPoolLendWithdrawProposal(cdc, malformed.Name())
require.ErrorContains(t, err, "invalid character")
}

View File

@ -12,8 +12,6 @@ import (
"github.com/kava-labs/kava/x/community/types" "github.com/kava-labs/kava/x/community/types"
) )
const legacyCommunityPoolAddr = "kava1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8m2splc"
type grpcQueryTestSuite struct { type grpcQueryTestSuite struct {
KeeperTestSuite KeeperTestSuite

View File

@ -8,10 +8,31 @@ import (
// HandleCommunityPoolLendDepositProposal is a handler for executing a passed community pool lend deposit proposal. // HandleCommunityPoolLendDepositProposal is a handler for executing a passed community pool lend deposit proposal.
func HandleCommunityPoolLendDepositProposal(ctx sdk.Context, k Keeper, p *types.CommunityPoolLendDepositProposal) error { func HandleCommunityPoolLendDepositProposal(ctx sdk.Context, k Keeper, p *types.CommunityPoolLendDepositProposal) error {
// move funds from community pool to x/community so hard position is held by this module.
err := k.distrKeeper.DistributeFromFeePool(ctx, p.Amount, k.moduleAddress)
if err != nil {
return err
}
// deposit funds into hard
return k.hardKeeper.Deposit(ctx, k.moduleAddress, p.Amount) return k.hardKeeper.Deposit(ctx, k.moduleAddress, p.Amount)
} }
// HandleCommunityPoolLendWithdrawProposal is a handler for executing a passed community pool lend withdraw proposal. // HandleCommunityPoolLendWithdrawProposal is a handler for executing a passed community pool lend withdraw proposal.
func HandleCommunityPoolLendWithdrawProposal(ctx sdk.Context, k Keeper, p *types.CommunityPoolLendWithdrawProposal) error { func HandleCommunityPoolLendWithdrawProposal(ctx sdk.Context, k Keeper, p *types.CommunityPoolLendWithdrawProposal) error {
return k.hardKeeper.Withdraw(ctx, k.moduleAddress, p.Amount) // hard allows attempting to withdraw more funds than there is a deposit for.
// this means the amount that gets withdrawn will not necessarily match the amount set in the proposal.
// to calculate how much is withdrawn, compare this module's balance before & after withdraw.
balanceBefore := k.bankKeeper.GetAllBalances(ctx, k.moduleAddress)
// withdraw funds from x/hard to this module account
err := k.hardKeeper.Withdraw(ctx, k.moduleAddress, p.Amount)
if err != nil {
return err
}
balanceAfter := k.bankKeeper.GetAllBalances(ctx, k.moduleAddress)
totalWithdrawn := balanceAfter.Sub(balanceBefore)
// send all withdrawn coins back to community pool
return k.distrKeeper.FundCommunityPool(ctx, totalWithdrawn, k.moduleAddress)
} }

View File

@ -78,16 +78,11 @@ func (suite *proposalTestSuite) SetupTest() {
// give the community pool some funds // give the community pool some funds
// ukava // ukava
err := suite.App.FundModuleAccount(suite.Ctx, types.ModuleAccountName, ukava(1e10)) suite.FundCommunityPool(ukava(1e10))
suite.NoError(err)
// usdx // usdx
err = suite.App.FundModuleAccount(suite.Ctx, types.ModuleAccountName, usdx(1e10)) suite.FundCommunityPool(usdx(1e10))
suite.NoError(err)
// other-denom // other-denom
err = suite.App.FundModuleAccount(suite.Ctx, types.ModuleAccountName, otherdenom(1e10)) suite.FundCommunityPool(otherdenom(1e10))
suite.NoError(err)
} }
func (suite *proposalTestSuite) NextBlock() { func (suite *proposalTestSuite) NextBlock() {
@ -99,6 +94,27 @@ func (suite *proposalTestSuite) NextBlock() {
suite.App.BeginBlocker(suite.Ctx, abcitypes.RequestBeginBlock{}) suite.App.BeginBlocker(suite.Ctx, abcitypes.RequestBeginBlock{})
} }
func (suite *proposalTestSuite) FundCommunityPool(coins sdk.Coins) {
// mint to ephemeral account
ephemeralAcc := app.RandomAddress()
suite.NoError(suite.App.FundAccount(suite.Ctx, ephemeralAcc, coins))
// fund community pool with newly minted coins
suite.NoError(suite.App.GetDistrKeeper().FundCommunityPool(suite.Ctx, coins, ephemeralAcc))
}
func (suite *proposalTestSuite) GetCommunityPoolBalance() sdk.Coins {
balance, change := suite.App.GetDistrKeeper().GetFeePoolCommunityCoins(suite.Ctx).TruncateDecimal()
// expect no decimal dust
suite.True(sdk.NewDecCoins().IsEqual(change), "expected no decimal dust in community pool")
return balance
}
func (suite *proposalTestSuite) CheckCommunityPoolBalance(expected sdk.Coins) {
actual := suite.GetCommunityPoolBalance()
// check that balance is expected
suite.True(expected.IsEqual(actual), fmt.Sprintf("unexpected balance in community pool\nexpected: %s\nactual: %s", expected, actual))
}
func (suite *proposalTestSuite) TestCommunityLendDepositProposal() { func (suite *proposalTestSuite) TestCommunityLendDepositProposal() {
testCases := []struct { testCases := []struct {
name string name string
@ -148,7 +164,7 @@ func (suite *proposalTestSuite) TestCommunityLendDepositProposal() {
Amount: ukava(1e11), Amount: ukava(1e11),
}, },
}, },
expectedErr: "insufficient funds", expectedErr: "community pool does not have sufficient coins to distribute",
expectedDeposits: []sdk.Coins{}, expectedDeposits: []sdk.Coins{},
}, },
{ {
@ -280,7 +296,7 @@ func (suite *proposalTestSuite) TestCommunityLendWithdrawProposal() {
suite.NoError(err, "unexpected error while seeding lend deposit") suite.NoError(err, "unexpected error while seeding lend deposit")
} }
beforeBalance := suite.Keeper.GetModuleAccountBalance(suite.Ctx) beforeBalance := suite.GetCommunityPoolBalance()
// run the proposals // run the proposals
for i, proposal := range tc.proposals { for i, proposal := range tc.proposals {
@ -306,7 +322,7 @@ func (suite *proposalTestSuite) TestCommunityLendWithdrawProposal() {
} }
// expect funds to be distributed back to community pool // expect funds to be distributed back to community pool
suite.App.CheckBalance(suite.T(), suite.Ctx, suite.MaccAddress, beforeBalance.Add(tc.expectedWithdrawal...)) suite.CheckCommunityPoolBalance(beforeBalance.Add(tc.expectedWithdrawal...))
}) })
} }
} }

View File

@ -27,5 +27,6 @@ type HardKeeper interface {
// DistributionKeeper defines the contract needed to be fulfilled for distribution dependencies. // DistributionKeeper defines the contract needed to be fulfilled for distribution dependencies.
type DistributionKeeper interface { type DistributionKeeper interface {
GetFeePoolCommunityCoins(ctx sdk.Context) sdk.DecCoins DistributeFromFeePool(ctx sdk.Context, amount sdk.Coins, receiveAddr sdk.AccAddress) error
FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error
} }