mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-11-10 10:05:18 +00:00
Add x/community Lend proposals (#1425)
* implement & register x/community lend proposals * register proposals in x/community codec * allow x/community macc to receive funds * init lend from genesis in proposal tests * test CommunityLendWithdrawProposal * helpful comment on x/community keeper deps * use RouteKey in module.go
This commit is contained in:
parent
a7f3b7732b
commit
7c58fb5303
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,6 +10,7 @@
|
||||
|
||||
# Output of the go coverage tool
|
||||
*.out
|
||||
cover.html
|
||||
|
||||
# Exclude build files
|
||||
vendor
|
||||
|
52
app/app.go
52
app/app.go
@ -508,20 +508,6 @@ func NewApp(
|
||||
|
||||
app.evmutilKeeper.SetEvmKeeper(app.evmKeeper)
|
||||
|
||||
app.communityKeeper = communitykeeper.NewKeeper(
|
||||
app.accountKeeper,
|
||||
app.bankKeeper,
|
||||
)
|
||||
app.kavadistKeeper = kavadistkeeper.NewKeeper(
|
||||
appCodec,
|
||||
keys[kavadisttypes.StoreKey],
|
||||
kavadistSubspace,
|
||||
app.bankKeeper,
|
||||
app.accountKeeper,
|
||||
app.communityKeeper,
|
||||
app.loadBlockedMaccAddrs(),
|
||||
)
|
||||
|
||||
app.transferKeeper = ibctransferkeeper.NewKeeper(
|
||||
appCodec,
|
||||
keys[ibctransfertypes.StoreKey],
|
||||
@ -620,6 +606,23 @@ func NewApp(
|
||||
&savingsKeeper,
|
||||
communitytypes.ModuleAccountName,
|
||||
)
|
||||
|
||||
// x/community's deposit/withdraw to lend proposals depend on hard keeper.
|
||||
app.communityKeeper = communitykeeper.NewKeeper(
|
||||
app.accountKeeper,
|
||||
app.bankKeeper,
|
||||
hardKeeper,
|
||||
)
|
||||
app.kavadistKeeper = kavadistkeeper.NewKeeper(
|
||||
appCodec,
|
||||
keys[kavadisttypes.StoreKey],
|
||||
kavadistSubspace,
|
||||
app.bankKeeper,
|
||||
app.accountKeeper,
|
||||
app.communityKeeper,
|
||||
app.loadBlockedMaccAddrs(),
|
||||
)
|
||||
|
||||
app.kavamintKeeper = kavamintkeeper.NewKeeper(
|
||||
appCodec,
|
||||
keys[kavaminttypes.StoreKey],
|
||||
@ -694,6 +697,7 @@ func NewApp(
|
||||
AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.distrKeeper)).
|
||||
AddRoute(kavadisttypes.RouterKey, kavadist.NewCommunityPoolMultiSpendProposalHandler(app.kavadistKeeper)).
|
||||
AddRoute(earntypes.RouterKey, earn.NewCommunityPoolProposalHandler(app.earnKeeper)).
|
||||
AddRoute(communitytypes.RouterKey, community.NewCommunityPoolProposalHandler(app.communityKeeper)).
|
||||
AddRoute(committeetypes.RouterKey, committee.NewProposalHandler(app.committeeKeeper))
|
||||
app.govKeeper = govkeeper.NewKeeper(
|
||||
appCodec,
|
||||
@ -1046,14 +1050,22 @@ func (app *App) RegisterTendermintService(clientCtx client.Context) {
|
||||
// loadBlockedMaccAddrs returns a map indicating the blocked status of each module account address
|
||||
func (app *App) loadBlockedMaccAddrs() map[string]bool {
|
||||
modAccAddrs := app.ModuleAccountAddrs()
|
||||
kavadistMaccAddr := app.accountKeeper.GetModuleAddress(kavadisttypes.ModuleName)
|
||||
earnMaccAddr := app.accountKeeper.GetModuleAddress(earntypes.ModuleName)
|
||||
liquidMaccAddr := app.accountKeeper.GetModuleAddress(liquidtypes.ModuleName)
|
||||
kavadistFundMaccAddr := app.accountKeeper.GetModuleAddress(kavadisttypes.FundModuleAccount)
|
||||
allowedMaccs := map[string]bool{
|
||||
// kavadist
|
||||
app.accountKeeper.GetModuleAddress(kavadisttypes.ModuleName).String(): true,
|
||||
// earn
|
||||
app.accountKeeper.GetModuleAddress(earntypes.ModuleName).String(): true,
|
||||
// liquid
|
||||
app.accountKeeper.GetModuleAddress(liquidtypes.ModuleName).String(): true,
|
||||
// kavadist fund
|
||||
app.accountKeeper.GetModuleAddress(kavadisttypes.FundModuleAccount).String(): true,
|
||||
// community
|
||||
app.accountKeeper.GetModuleAddress(communitytypes.ModuleAccountName).String(): true,
|
||||
}
|
||||
|
||||
for addr := range modAccAddrs {
|
||||
// Set the kavadist and earn module account address as unblocked
|
||||
if addr == kavadistMaccAddr.String() || addr == earnMaccAddr.String() || addr == liquidMaccAddr.String() || addr == kavadistFundMaccAddr.String() {
|
||||
// Set allowed module accounts as unblocked
|
||||
if allowedMaccs[addr] {
|
||||
modAccAddrs[addr] = false
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/kava-labs/kava/x/community"
|
||||
"github.com/kava-labs/kava/x/community/testutil"
|
||||
"github.com/kava-labs/kava/x/community/types"
|
||||
)
|
||||
|
||||
type genesisTestSuite struct {
|
||||
@ -32,12 +31,8 @@ func (suite *genesisTestSuite) TestInitGenesis() {
|
||||
community.InitGenesis(suite.Ctx, suite.Keeper, accountKeeper)
|
||||
})
|
||||
|
||||
communityPoolAddress := accountKeeper.GetModuleAddress(types.ModuleAccountName)
|
||||
// hello, greppers!
|
||||
suite.Equal("kava17d2wax0zhjrrecvaszuyxdf5wcu5a0p4qlx3t5", communityPoolAddress.String())
|
||||
|
||||
// check for module account this way b/c GetModuleAccount creates if not existing.
|
||||
acc := accountKeeper.GetAccount(suite.Ctx, communityPoolAddress)
|
||||
acc := accountKeeper.GetAccount(suite.Ctx, suite.MaccAddress)
|
||||
suite.NotNil(acc)
|
||||
_, ok := acc.(authtypes.ModuleAccountI)
|
||||
suite.True(ok)
|
||||
|
24
x/community/handler.go
Normal file
24
x/community/handler.go
Normal file
@ -0,0 +1,24 @@
|
||||
package community
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
|
||||
"github.com/kava-labs/kava/x/community/keeper"
|
||||
"github.com/kava-labs/kava/x/community/types"
|
||||
)
|
||||
|
||||
// NewCommunityPoolProposalHandler handles x/community proposals.
|
||||
func NewCommunityPoolProposalHandler(k keeper.Keeper) govtypes.Handler {
|
||||
return func(ctx sdk.Context, content govtypes.Content) error {
|
||||
switch c := content.(type) {
|
||||
case *types.CommunityPoolLendDepositProposal:
|
||||
return keeper.HandleCommunityPoolLendDepositProposal(ctx, k, c)
|
||||
case *types.CommunityPoolLendWithdrawProposal:
|
||||
return keeper.HandleCommunityPoolLendWithdrawProposal(ctx, k, c)
|
||||
default:
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized community proposal content type: %T", c)
|
||||
}
|
||||
}
|
||||
}
|
@ -12,11 +12,12 @@ import (
|
||||
// Keeper of the community store
|
||||
type Keeper struct {
|
||||
bankKeeper types.BankKeeper
|
||||
hardKeeper types.HardKeeper
|
||||
moduleAddress sdk.AccAddress
|
||||
}
|
||||
|
||||
// NewKeeper creates a new community Keeper instance
|
||||
func NewKeeper(ak types.AccountKeeper, bk types.BankKeeper) Keeper {
|
||||
func NewKeeper(ak types.AccountKeeper, bk types.BankKeeper, hk types.HardKeeper) Keeper {
|
||||
// ensure community module account is set
|
||||
addr := ak.GetModuleAddress(types.ModuleAccountName)
|
||||
if addr == nil {
|
||||
@ -25,6 +26,7 @@ func NewKeeper(ak types.AccountKeeper, bk types.BankKeeper) Keeper {
|
||||
|
||||
return Keeper{
|
||||
bankKeeper: bk,
|
||||
hardKeeper: hk,
|
||||
moduleAddress: addr,
|
||||
}
|
||||
}
|
||||
|
17
x/community/keeper/proposal_handler.go
Normal file
17
x/community/keeper/proposal_handler.go
Normal file
@ -0,0 +1,17 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/kava-labs/kava/x/community/types"
|
||||
)
|
||||
|
||||
// HandleCommunityPoolLendDepositProposal is a handler for executing a passed community pool lend deposit proposal.
|
||||
func HandleCommunityPoolLendDepositProposal(ctx sdk.Context, k Keeper, p *types.CommunityPoolLendDepositProposal) error {
|
||||
return k.hardKeeper.Deposit(ctx, k.moduleAddress, p.Amount)
|
||||
}
|
||||
|
||||
// HandleCommunityPoolLendWithdrawProposal is a handler for executing a passed community pool lend withdraw proposal.
|
||||
func HandleCommunityPoolLendWithdrawProposal(ctx sdk.Context, k Keeper, p *types.CommunityPoolLendWithdrawProposal) error {
|
||||
return k.hardKeeper.Withdraw(ctx, k.moduleAddress, p.Amount)
|
||||
}
|
312
x/community/keeper/proposal_handler_test.go
Normal file
312
x/community/keeper/proposal_handler_test.go
Normal file
@ -0,0 +1,312 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/suite"
|
||||
abcitypes "github.com/tendermint/tendermint/abci/types"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
|
||||
"github.com/kava-labs/kava/app"
|
||||
"github.com/kava-labs/kava/x/community/keeper"
|
||||
"github.com/kava-labs/kava/x/community/testutil"
|
||||
"github.com/kava-labs/kava/x/community/types"
|
||||
hardkeeper "github.com/kava-labs/kava/x/hard/keeper"
|
||||
hardtypes "github.com/kava-labs/kava/x/hard/types"
|
||||
pricefeedtypes "github.com/kava-labs/kava/x/pricefeed/types"
|
||||
)
|
||||
|
||||
const chainID = "kavatest_2221-1"
|
||||
|
||||
func ukava(amt int64) sdk.Coins {
|
||||
return sdk.NewCoins(sdk.NewInt64Coin("ukava", amt))
|
||||
}
|
||||
func usdx(amt int64) sdk.Coins {
|
||||
return sdk.NewCoins(sdk.NewInt64Coin("usdx", amt))
|
||||
}
|
||||
func otherdenom(amt int64) sdk.Coins {
|
||||
return sdk.NewCoins(sdk.NewInt64Coin("other-denom", amt))
|
||||
}
|
||||
|
||||
type proposalTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
App app.TestApp
|
||||
Ctx sdk.Context
|
||||
Keeper keeper.Keeper
|
||||
MaccAddress sdk.AccAddress
|
||||
|
||||
hardKeeper hardkeeper.Keeper
|
||||
}
|
||||
|
||||
func TestProposalTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(proposalTestSuite))
|
||||
}
|
||||
|
||||
func (suite *proposalTestSuite) SetupTest() {
|
||||
app.SetSDKConfig()
|
||||
|
||||
genTime := tmtime.Now()
|
||||
|
||||
hardGS, pricefeedGS := testutil.NewLendGenesisBuilder().
|
||||
WithMarket("ukava", "kava:usd", sdk.OneDec()).
|
||||
WithMarket("usdx", "usdx:usd", sdk.OneDec()).
|
||||
Build()
|
||||
|
||||
tApp := app.NewTestApp()
|
||||
ctx := tApp.NewContext(true, tmproto.Header{
|
||||
Height: 1,
|
||||
Time: genTime,
|
||||
ChainID: chainID,
|
||||
})
|
||||
|
||||
tApp.InitializeFromGenesisStatesWithTimeAndChainID(
|
||||
genTime, chainID,
|
||||
app.GenesisState{hardtypes.ModuleName: tApp.AppCodec().MustMarshalJSON(&hardGS)},
|
||||
app.GenesisState{pricefeedtypes.ModuleName: tApp.AppCodec().MustMarshalJSON(&pricefeedGS)},
|
||||
)
|
||||
|
||||
suite.App = tApp
|
||||
suite.Ctx = ctx
|
||||
suite.Keeper = tApp.GetCommunityKeeper()
|
||||
suite.MaccAddress = tApp.GetAccountKeeper().GetModuleAddress(types.ModuleAccountName)
|
||||
suite.hardKeeper = suite.App.GetHardKeeper()
|
||||
|
||||
// give the community pool some funds
|
||||
// ukava
|
||||
err := suite.App.FundModuleAccount(suite.Ctx, types.ModuleAccountName, ukava(1e10))
|
||||
suite.NoError(err)
|
||||
|
||||
// usdx
|
||||
err = suite.App.FundModuleAccount(suite.Ctx, types.ModuleAccountName, usdx(1e10))
|
||||
suite.NoError(err)
|
||||
|
||||
// other-denom
|
||||
err = suite.App.FundModuleAccount(suite.Ctx, types.ModuleAccountName, otherdenom(1e10))
|
||||
suite.NoError(err)
|
||||
}
|
||||
|
||||
func (suite *proposalTestSuite) NextBlock() {
|
||||
newTime := suite.Ctx.BlockTime().Add(6 * time.Second)
|
||||
newHeight := suite.Ctx.BlockHeight() + 1
|
||||
|
||||
suite.App.EndBlocker(suite.Ctx, abcitypes.RequestEndBlock{})
|
||||
suite.Ctx = suite.Ctx.WithBlockTime(newTime).WithBlockHeight(newHeight).WithChainID(chainID)
|
||||
suite.App.BeginBlocker(suite.Ctx, abcitypes.RequestBeginBlock{})
|
||||
}
|
||||
|
||||
func (suite *proposalTestSuite) TestCommunityLendDepositProposal() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
proposals []*types.CommunityPoolLendDepositProposal
|
||||
expectedErr string
|
||||
expectedDeposits []sdk.Coins
|
||||
}{
|
||||
{
|
||||
name: "valid - one proposal, one denom",
|
||||
proposals: []*types.CommunityPoolLendDepositProposal{
|
||||
{Amount: ukava(1e8)},
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedDeposits: []sdk.Coins{ukava(1e8)},
|
||||
},
|
||||
{
|
||||
name: "valid - one proposal, multiple denoms",
|
||||
proposals: []*types.CommunityPoolLendDepositProposal{
|
||||
{Amount: ukava(1e8).Add(usdx(1e8)...)},
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedDeposits: []sdk.Coins{ukava(1e8).Add(usdx(1e8)...)},
|
||||
},
|
||||
{
|
||||
name: "valid - multiple proposals, same denom",
|
||||
proposals: []*types.CommunityPoolLendDepositProposal{
|
||||
{Amount: ukava(1e8)},
|
||||
{Amount: ukava(1e9)},
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedDeposits: []sdk.Coins{ukava(1e8 + 1e9)},
|
||||
},
|
||||
{
|
||||
name: "valid - multiple proposals, different denoms",
|
||||
proposals: []*types.CommunityPoolLendDepositProposal{
|
||||
{Amount: ukava(1e8)},
|
||||
{Amount: usdx(1e8)},
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedDeposits: []sdk.Coins{ukava(1e8).Add(usdx(1e8)...)},
|
||||
},
|
||||
{
|
||||
name: "invalid - insufficient balance",
|
||||
proposals: []*types.CommunityPoolLendDepositProposal{
|
||||
{
|
||||
Description: "more coins than i have!",
|
||||
Amount: ukava(1e11),
|
||||
},
|
||||
},
|
||||
expectedErr: "insufficient funds",
|
||||
expectedDeposits: []sdk.Coins{},
|
||||
},
|
||||
{
|
||||
name: "invalid - invalid lend deposit (unsupported denom)",
|
||||
proposals: []*types.CommunityPoolLendDepositProposal{
|
||||
{Amount: otherdenom(1e9)},
|
||||
},
|
||||
expectedErr: "invalid deposit denom",
|
||||
expectedDeposits: []sdk.Coins{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest()
|
||||
|
||||
for _, proposal := range tc.proposals {
|
||||
err := keeper.HandleCommunityPoolLendDepositProposal(suite.Ctx, suite.Keeper, proposal)
|
||||
if tc.expectedErr == "" {
|
||||
suite.NoError(err)
|
||||
} else {
|
||||
suite.ErrorContains(err, tc.expectedErr)
|
||||
}
|
||||
}
|
||||
|
||||
deposits := suite.hardKeeper.GetDepositsByUser(suite.Ctx, suite.MaccAddress)
|
||||
suite.Len(deposits, len(tc.expectedDeposits), "expected a deposit to lend")
|
||||
for _, amt := range tc.expectedDeposits {
|
||||
suite.Equal(amt, deposits[0].Amount, "expected amount to match")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *proposalTestSuite) TestCommunityLendWithdrawProposal() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
initialDeposit sdk.Coins
|
||||
proposals []*types.CommunityPoolLendWithdrawProposal
|
||||
expectedErr string
|
||||
expectedWithdrawal sdk.Coins
|
||||
}{
|
||||
{
|
||||
// in the week it would take a proposal to pass, the position would have grown
|
||||
// to withdraw the entire position, it'd be safest to set a very high withdraw
|
||||
name: "valid - requesting withdrawal of more than total will withdraw all",
|
||||
initialDeposit: ukava(1e9),
|
||||
proposals: []*types.CommunityPoolLendWithdrawProposal{
|
||||
{Amount: ukava(1e12)},
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedWithdrawal: ukava(1e9),
|
||||
},
|
||||
{
|
||||
name: "valid - single proposal, single denom, full withdrawal",
|
||||
initialDeposit: ukava(1e9),
|
||||
proposals: []*types.CommunityPoolLendWithdrawProposal{
|
||||
{Amount: ukava(1e9)},
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedWithdrawal: ukava(1e9),
|
||||
},
|
||||
{
|
||||
name: "valid - single proposal, multiple denoms, full withdrawal",
|
||||
initialDeposit: ukava(1e9).Add(usdx(1e9)...),
|
||||
proposals: []*types.CommunityPoolLendWithdrawProposal{
|
||||
{Amount: ukava(1e9).Add(usdx(1e9)...)},
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedWithdrawal: ukava(1e9).Add(usdx(1e9)...),
|
||||
},
|
||||
{
|
||||
name: "valid - single proposal, partial withdrawal",
|
||||
initialDeposit: ukava(1e9).Add(usdx(1e9)...),
|
||||
proposals: []*types.CommunityPoolLendWithdrawProposal{
|
||||
{Amount: ukava(1e8).Add(usdx(1e9)...)},
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedWithdrawal: ukava(1e8).Add(usdx(1e9)...),
|
||||
},
|
||||
{
|
||||
name: "valid - multiple proposals, full withdrawal",
|
||||
initialDeposit: ukava(1e9).Add(usdx(1e9)...),
|
||||
proposals: []*types.CommunityPoolLendWithdrawProposal{
|
||||
{Amount: ukava(1e9)},
|
||||
{Amount: usdx(1e9)},
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedWithdrawal: ukava(1e9).Add(usdx(1e9)...),
|
||||
},
|
||||
{
|
||||
name: "valid - multiple proposals, partial withdrawal",
|
||||
initialDeposit: ukava(1e9).Add(usdx(1e9)...),
|
||||
proposals: []*types.CommunityPoolLendWithdrawProposal{
|
||||
{Amount: ukava(1e8)},
|
||||
{Amount: usdx(1e8)},
|
||||
},
|
||||
expectedErr: "",
|
||||
expectedWithdrawal: ukava(1e8).Add(usdx(1e8)...),
|
||||
},
|
||||
{
|
||||
name: "invalid - nonexistent position, has no deposits",
|
||||
initialDeposit: sdk.NewCoins(),
|
||||
proposals: []*types.CommunityPoolLendWithdrawProposal{
|
||||
{Amount: ukava(1e8)},
|
||||
},
|
||||
expectedErr: "deposit not found",
|
||||
expectedWithdrawal: sdk.NewCoins(),
|
||||
},
|
||||
{
|
||||
name: "invalid - nonexistent position, has deposits of different denom",
|
||||
initialDeposit: ukava(1e8),
|
||||
proposals: []*types.CommunityPoolLendWithdrawProposal{
|
||||
{Amount: usdx(1e8)},
|
||||
},
|
||||
expectedErr: "no coins of this type deposited",
|
||||
expectedWithdrawal: sdk.NewCoins(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest()
|
||||
|
||||
// setup initial deposit
|
||||
if !tc.initialDeposit.IsZero() {
|
||||
deposit := types.NewCommunityPoolLendDepositProposal("initial deposit", "has coins", tc.initialDeposit)
|
||||
err := keeper.HandleCommunityPoolLendDepositProposal(suite.Ctx, suite.Keeper, deposit)
|
||||
suite.NoError(err, "unexpected error while seeding lend deposit")
|
||||
}
|
||||
|
||||
beforeBalance := suite.Keeper.GetModuleAccountBalance(suite.Ctx)
|
||||
|
||||
// run the proposals
|
||||
for i, proposal := range tc.proposals {
|
||||
fmt.Println("submitting proposal ", i, " ", suite.Ctx.ChainID())
|
||||
err := keeper.HandleCommunityPoolLendWithdrawProposal(suite.Ctx, suite.Keeper, proposal)
|
||||
if tc.expectedErr == "" {
|
||||
suite.NoError(err)
|
||||
} else {
|
||||
suite.ErrorContains(err, tc.expectedErr)
|
||||
}
|
||||
|
||||
suite.NextBlock()
|
||||
}
|
||||
|
||||
// expect funds to be removed from hard deposit
|
||||
expectedRemaining := tc.initialDeposit.Sub(tc.expectedWithdrawal)
|
||||
deposits := suite.hardKeeper.GetDepositsByUser(suite.Ctx, suite.MaccAddress)
|
||||
if expectedRemaining.IsZero() {
|
||||
suite.Len(deposits, 0, "expected all deposits to be withdrawn")
|
||||
} else {
|
||||
suite.Len(deposits, 1, "expected user to have remaining deposit")
|
||||
suite.Equal(expectedRemaining, deposits[0].Amount)
|
||||
}
|
||||
|
||||
// expect funds to be distributed back to community pool
|
||||
suite.App.CheckBalance(suite.T(), suite.Ctx, suite.MaccAddress, beforeBalance.Add(tc.expectedWithdrawal...))
|
||||
})
|
||||
}
|
||||
}
|
@ -109,7 +109,7 @@ func (am AppModule) Route() sdk.Route { return sdk.Route{} }
|
||||
|
||||
// QuerierRoute module querier route name
|
||||
// Deprecated: unused but necessary to fulfill AppModule interface
|
||||
func (AppModule) QuerierRoute() string { return "" }
|
||||
func (AppModule) QuerierRoute() string { return types.RouterKey }
|
||||
|
||||
// LegacyQuerierHandler returns no sdk.Querier.
|
||||
// Deprecated: unused but necessary to fulfill AppModule interface
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/kava-labs/kava/app"
|
||||
"github.com/kava-labs/kava/x/community/keeper"
|
||||
"github.com/kava-labs/kava/x/community/types"
|
||||
)
|
||||
|
||||
// Test suite used for all community tests
|
||||
@ -17,6 +18,8 @@ type Suite struct {
|
||||
App app.TestApp
|
||||
Ctx sdk.Context
|
||||
Keeper keeper.Keeper
|
||||
|
||||
MaccAddress sdk.AccAddress
|
||||
}
|
||||
|
||||
// The default state used by each test
|
||||
@ -30,6 +33,10 @@ func (suite *Suite) SetupTest() {
|
||||
suite.App = tApp
|
||||
suite.Ctx = ctx
|
||||
suite.Keeper = tApp.GetCommunityKeeper()
|
||||
communityPoolAddress := tApp.GetAccountKeeper().GetModuleAddress(types.ModuleAccountName)
|
||||
// hello, greppers!
|
||||
suite.Equal("kava17d2wax0zhjrrecvaszuyxdf5wcu5a0p4qlx3t5", communityPoolAddress.String())
|
||||
suite.MaccAddress = communityPoolAddress
|
||||
}
|
||||
|
||||
// CreateFundedAccount creates a random account and mints `coins` to it.
|
||||
|
60
x/community/testutil/pricefeed_genesis_builder.go
Normal file
60
x/community/testutil/pricefeed_genesis_builder.go
Normal file
@ -0,0 +1,60 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
hardtypes "github.com/kava-labs/kava/x/hard/types"
|
||||
pricefeedtypes "github.com/kava-labs/kava/x/pricefeed/types"
|
||||
)
|
||||
|
||||
// lendGenesisBuilder builds the Hard and Pricefeed genesis states for setting up Kava Lend
|
||||
type lendGenesisBuilder struct {
|
||||
hardMarkets []hardtypes.MoneyMarket
|
||||
pfMarkets []pricefeedtypes.Market
|
||||
prices []pricefeedtypes.PostedPrice
|
||||
}
|
||||
|
||||
func NewLendGenesisBuilder() lendGenesisBuilder {
|
||||
return lendGenesisBuilder{}
|
||||
}
|
||||
|
||||
func (b lendGenesisBuilder) Build() (hardtypes.GenesisState, pricefeedtypes.GenesisState) {
|
||||
hardGS := hardtypes.DefaultGenesisState()
|
||||
hardGS.Params.MoneyMarkets = b.hardMarkets
|
||||
|
||||
pricefeedGS := pricefeedtypes.DefaultGenesisState()
|
||||
pricefeedGS.Params.Markets = b.pfMarkets
|
||||
pricefeedGS.PostedPrices = b.prices
|
||||
return hardGS, pricefeedGS
|
||||
}
|
||||
|
||||
func (b lendGenesisBuilder) WithMarket(denom, spotMarketId string, price sdk.Dec) lendGenesisBuilder {
|
||||
// add hard money market
|
||||
b.hardMarkets = append(b.hardMarkets,
|
||||
hardtypes.NewMoneyMarket(
|
||||
denom,
|
||||
hardtypes.NewBorrowLimit(false, sdk.NewDec(1e15), sdk.MustNewDecFromStr("0.6")),
|
||||
spotMarketId,
|
||||
sdk.NewInt(1e6),
|
||||
hardtypes.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")),
|
||||
sdk.MustNewDecFromStr("0.05"),
|
||||
sdk.ZeroDec(),
|
||||
),
|
||||
)
|
||||
|
||||
// add pricefeed
|
||||
b.pfMarkets = append(b.pfMarkets,
|
||||
pricefeedtypes.Market{MarketID: spotMarketId, BaseAsset: denom, QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true},
|
||||
)
|
||||
b.prices = append(b.prices,
|
||||
pricefeedtypes.PostedPrice{
|
||||
MarketID: spotMarketId,
|
||||
OracleAddress: sdk.AccAddress{},
|
||||
Price: price,
|
||||
Expiry: time.Now().Add(100 * time.Hour),
|
||||
},
|
||||
)
|
||||
|
||||
return b
|
||||
}
|
@ -6,6 +6,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/types/msgservice"
|
||||
|
||||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
@ -13,6 +14,8 @@ import (
|
||||
// RegisterLegacyAminoCodec registers all the necessary types and interfaces for the module.
|
||||
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
|
||||
cdc.RegisterConcrete(&MsgFundCommunityPool{}, "community/MsgFundCommunityPool", nil)
|
||||
cdc.RegisterConcrete(&CommunityPoolLendDepositProposal{}, "kava/CommunityPoolLendDepositProposal", nil)
|
||||
cdc.RegisterConcrete(&CommunityPoolLendWithdrawProposal{}, "kava/CommunityPoolLendWithdrawProposal", nil)
|
||||
}
|
||||
|
||||
// RegisterInterfaces registers proto messages under their interfaces for unmarshalling,
|
||||
@ -21,6 +24,10 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
|
||||
registry.RegisterImplementations((*sdk.Msg)(nil),
|
||||
&MsgFundCommunityPool{},
|
||||
)
|
||||
registry.RegisterImplementations((*govtypes.Content)(nil),
|
||||
&CommunityPoolLendDepositProposal{},
|
||||
&CommunityPoolLendWithdrawProposal{},
|
||||
)
|
||||
|
||||
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
|
||||
}
|
||||
|
@ -18,3 +18,9 @@ type BankKeeper interface {
|
||||
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
|
||||
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
|
||||
}
|
||||
|
||||
// HardKeeper defines the contract needed to be fulfilled for Kava Lend dependencies.
|
||||
type HardKeeper interface {
|
||||
Deposit(ctx sdk.Context, depositor sdk.AccAddress, coins sdk.Coins) error
|
||||
Withdraw(ctx sdk.Context, depositor sdk.AccAddress, coins sdk.Coins) error
|
||||
}
|
||||
|
@ -7,6 +7,9 @@ const (
|
||||
// ModuleAccountName is the name of the module's account
|
||||
ModuleAccountName = ModuleName
|
||||
|
||||
// RouterKey is the top-level router key for the module
|
||||
RouterKey = ModuleName
|
||||
|
||||
// Query endpoints supported by community
|
||||
QueryBalance = "balance"
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user