From d56bb772310adaa461af667607e342f90b1de9b6 Mon Sep 17 00:00:00 2001 From: Ruaridh Date: Thu, 10 Jun 2021 14:35:44 +0100 Subject: [PATCH] Incentive Test Refactors (#908) * organise testing committee gen state * remove repeated test app initialization * minor fixes from linter in tests * move more setup to SetupApp * split up KeeperTestSuite for each reward type * simplify KeeperTestSuite * simplify PayoutKeeperSuite * simplify DelegatorRewardSuite * simplify SupplyRewardsSuite * simplify BorrowRewardsSuite * simplify USDXRewardsSuite * add auth genesis builder for easier test setup * migrate all incentive tests to auth builder * add incentive genesis builder for easier setup migrate hard incentive tests * migrate all tests to incentive builder * add hard genesis builder * small tidy ups * deduplicate initialTime from borrow tests * deduplicate initialtTime from supply tests * deduplicate initialTime from usdx and keeper tests * deduplicate initialTime in delgator tests * deduplicate genesis time in payout test * deduplicate test app initialization * make authGenesisBuilder available for all modules * remove unused pricefeed setup * export incentive genesis builder * remove commented out test cases * migrate cdp test to new test state builders * migrate vv payout tests to use new builders --- app/test_common.go | 164 +++-- x/incentive/keeper/cdp_test.go | 79 +-- x/incentive/keeper/integration_test.go | 290 +++++--- x/incentive/keeper/keeper_test.go | 88 +-- x/incentive/keeper/payout_test.go | 706 ++++++++----------- x/incentive/keeper/rewards_borrow_test.go | 448 ++++-------- x/incentive/keeper/rewards_delegator_test.go | 336 ++++----- x/incentive/keeper/rewards_supply_test.go | 434 ++++-------- x/incentive/keeper/rewards_usdx_test.go | 158 ++--- 9 files changed, 1162 insertions(+), 1541 deletions(-) diff --git a/app/test_common.go b/app/test_common.go index 5433754d..f7ca3b95 100644 --- a/app/test_common.go +++ b/app/test_common.go @@ -18,6 +18,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/auth/vesting" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/crisis" "github.com/cosmos/cosmos-sdk/x/distribution" @@ -42,6 +43,11 @@ import ( validatorvesting "github.com/kava-labs/kava/x/validator-vesting" ) +var ( + emptyTime time.Time + emptyChainID string +) + // TestApp is a simple wrapper around an App. It exposes internal keepers for use in integration tests. // This file also contains test helpers. Ideally they would be in separate package. // Basic Usage: @@ -92,55 +98,12 @@ func (tApp TestApp) GetSwapKeeper() swap.Keeper { return tApp.swapKeep // InitializeFromGenesisStates calls InitChain on the app using the default genesis state, overwitten with any passed in genesis states func (tApp TestApp) InitializeFromGenesisStates(genesisStates ...GenesisState) TestApp { - // Create a default genesis state and overwrite with provided values - genesisState := NewDefaultGenesisState() - for _, state := range genesisStates { - for k, v := range state { - genesisState[k] = v - } - } - - // Initialize the chain - stateBytes, err := codec.MarshalJSONIndent(tApp.cdc, genesisState) - if err != nil { - panic(err) - } - tApp.InitChain( - abci.RequestInitChain{ - Validators: []abci.ValidatorUpdate{}, - AppStateBytes: stateBytes, - }, - ) - tApp.Commit() - tApp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: tApp.LastBlockHeight() + 1}}) - return tApp + return tApp.InitializeFromGenesisStatesWithTimeAndChainID(emptyTime, emptyChainID, genesisStates...) } // InitializeFromGenesisStatesWithTime calls InitChain on the app using the default genesis state, overwitten with any passed in genesis states and genesis Time func (tApp TestApp) InitializeFromGenesisStatesWithTime(genTime time.Time, genesisStates ...GenesisState) TestApp { - // Create a default genesis state and overwrite with provided values - genesisState := NewDefaultGenesisState() - for _, state := range genesisStates { - for k, v := range state { - genesisState[k] = v - } - } - - // Initialize the chain - stateBytes, err := codec.MarshalJSONIndent(tApp.cdc, genesisState) - if err != nil { - panic(err) - } - tApp.InitChain( - abci.RequestInitChain{ - Time: genTime, - Validators: []abci.ValidatorUpdate{}, - AppStateBytes: stateBytes, - }, - ) - tApp.Commit() - tApp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: tApp.LastBlockHeight() + 1, Time: genTime}}) - return tApp + return tApp.InitializeFromGenesisStatesWithTimeAndChainID(genTime, emptyChainID, genesisStates...) } // InitializeFromGenesisStatesWithTimeAndChainID calls InitChain on the app using the default genesis state, overwitten with any passed in genesis states and genesis Time @@ -177,18 +140,6 @@ func (tApp TestApp) CheckBalance(t *testing.T, ctx sdk.Context, owner sdk.AccAdd require.Equal(t, expectedCoins, acc.GetCoins()) } -// Create a new auth genesis state from some addresses and coins. The state is returned marshalled into a map. -func NewAuthGenState(addresses []sdk.AccAddress, coins []sdk.Coins) GenesisState { - // Create GenAccounts - accounts := authexported.GenesisAccounts{} - for i := range addresses { - accounts = append(accounts, auth.NewBaseAccount(addresses[i], coins[i], nil, 0, 0)) - } - // Create the auth genesis state - authGenesis := auth.NewGenesisState(auth.DefaultParams(), accounts) - return GenesisState{auth.ModuleName: auth.ModuleCdc.MustMarshalJSON(authGenesis)} -} - // GeneratePrivKeyAddressPairsFromRand generates (deterministically) a total of n secp256k1 private keys and addresses. func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) { r := rand.New(rand.NewSource(12345)) // make the generation deterministic @@ -205,3 +156,102 @@ func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccA } return } + +// Create a new auth genesis state from some addresses and coins. The state is returned marshalled into a map. +func NewAuthGenState(addresses []sdk.AccAddress, coins []sdk.Coins) GenesisState { + // Create GenAccounts + accounts := authexported.GenesisAccounts{} + for i := range addresses { + accounts = append(accounts, auth.NewBaseAccount(addresses[i], coins[i], nil, 0, 0)) + } + // Create the auth genesis state + authGenesis := auth.NewGenesisState(auth.DefaultParams(), accounts) + return GenesisState{auth.ModuleName: auth.ModuleCdc.MustMarshalJSON(authGenesis)} +} + +// AuthGenesisBuilder is a tool for creating an auth genesis state. +// Helper methods create basic accounts types and add them to a default genesis state. +// All methods are immutable and return updated copies of the builder. +// The builder inherits from auth.GenesisState, so fields can be accessed directly if a helper method doesn't exist. +// +// Example: +// // create a single account genesis state +// builder := NewAuthGenesisBuilder().WithSimpleAccount(testUserAddress, testCoins) +// genesisState := builder.Build() +// +type AuthGenesisBuilder struct { + auth.GenesisState +} + +// NewAuthGenesisBuilder creates a AuthGenesisBuilder containing a default genesis state. +func NewAuthGenesisBuilder() AuthGenesisBuilder { + return AuthGenesisBuilder{ + GenesisState: auth.DefaultGenesisState(), + } +} + +// Build assembles and returns the final GenesisState +func (builder AuthGenesisBuilder) Build() auth.GenesisState { + return builder.GenesisState +} + +// BuildMarshalled assembles the final GenesisState and json encodes it into a generic genesis type. +func (builder AuthGenesisBuilder) BuildMarshalled() GenesisState { + return GenesisState{ + auth.ModuleName: auth.ModuleCdc.MustMarshalJSON(builder.Build()), + } +} + +// WithAccounts adds accounts of any type to the genesis state. +func (builder AuthGenesisBuilder) WithAccounts(account ...authexported.GenesisAccount) AuthGenesisBuilder { + builder.Accounts = append(builder.Accounts, account...) + return builder +} + +// WithSimpleAccount adds a standard account to the genesis state. +func (builder AuthGenesisBuilder) WithSimpleAccount(address sdk.AccAddress, balance sdk.Coins) AuthGenesisBuilder { + return builder.WithAccounts(auth.NewBaseAccount(address, balance, nil, 0, 0)) +} + +// WithSimpleModuleAccount adds a module account to the genesis state. +func (builder AuthGenesisBuilder) WithSimpleModuleAccount(moduleName string, balance sdk.Coins, permissions ...string) AuthGenesisBuilder { + account := supply.NewEmptyModuleAccount(moduleName, permissions...) + account.SetCoins(balance) + return builder.WithAccounts(account) +} + +// WithSimplePeriodicVestingAccount adds a periodic vesting account to the genesis state. +func (builder AuthGenesisBuilder) WithSimplePeriodicVestingAccount(address sdk.AccAddress, balance sdk.Coins, periods vesting.Periods, firstPeriodStartTimestamp int64) AuthGenesisBuilder { + baseAccount := auth.NewBaseAccount(address, balance, nil, 0, 0) + + originalVesting := sdk.NewCoins() + for _, p := range periods { + originalVesting = originalVesting.Add(p.Amount...) + } + + var totalPeriods int64 + for _, p := range periods { + totalPeriods += p.Length + } + endTime := firstPeriodStartTimestamp + totalPeriods + + baseVestingAccount, err := vesting.NewBaseVestingAccount(baseAccount, originalVesting, endTime) + if err != nil { + panic(err.Error()) + } + periodicVestingAccount := vesting.NewPeriodicVestingAccountRaw(baseVestingAccount, firstPeriodStartTimestamp, periods) + + return builder.WithAccounts(periodicVestingAccount) +} + +// WithEmptyValidatorVestingAccount adds a stub validator vesting account to the genesis state. +func (builder AuthGenesisBuilder) WithEmptyValidatorVestingAccount(address sdk.AccAddress) AuthGenesisBuilder { + // TODO create a validator vesting account builder and remove this method + bacc := auth.NewBaseAccount(address, nil, nil, 0, 0) + bva, err := vesting.NewBaseVestingAccount(bacc, nil, 1) + if err != nil { + panic(err.Error()) + } + account := validatorvesting.NewValidatorVestingAccountRaw(bva, 0, nil, sdk.ConsAddress{}, nil, 90) + return builder.WithAccounts(account) +} diff --git a/x/incentive/keeper/cdp_test.go b/x/incentive/keeper/cdp_test.go index 3839fe0f..dc1d8203 100644 --- a/x/incentive/keeper/cdp_test.go +++ b/x/incentive/keeper/cdp_test.go @@ -1,70 +1,69 @@ package keeper_test import ( + "testing" "time" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - cdptypes "github.com/kava-labs/kava/x/cdp/types" + "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/x/incentive/types" ) -func (suite *KeeperTestSuite) TestRiskyCDPsAccumulateRewards() { - suite.SetupWithGenState() - initialTime := suite.ctx.BlockTime() +func TestRiskyCDPsAccumulateRewards(t *testing.T) { + genesisTime := time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC) + _, addrs := app.GeneratePrivKeyAddressPairs(5) + + initialCollateral := c("bnb", 1_000_000_000) + user := addrs[0] + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(user, cs(initialCollateral)) - // Setup incentive state collateralType := "bnb-a" rewardsPerSecond := c(types.USDXMintingRewardDenom, 1_000_000) - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, collateralType, initialTime, initialTime.Add(4*oneYear), rewardsPerSecond)}, - nil, // hard rewards not needed - nil, - nil, // delegator rewards not needed - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - initialTime.Add(5*oneYear), + + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(genesisTime). + WithSimpleUSDXRewardPeriod(collateralType, rewardsPerSecond) + + tApp := app.NewTestApp() + tApp.InitializeFromGenesisStates( + authBuilder.BuildMarshalled(), + NewPricefeedGenStateMultiFromTime(genesisTime), + NewCDPGenStateMulti(), + incentBuilder.BuildMarshalled(), ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, collateralType, initialTime) - suite.keeper.SetUSDXMintingRewardFactor(suite.ctx, collateralType, sdk.ZeroDec()) + ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: genesisTime}) // Setup cdp state containing one CDP - cdpKeeper := suite.app.GetCDPKeeper() - initialCollateral := c("bnb", 1_000_000_000) - initialPrincipal := c("usdx", 100_000_000) - cdpKeeper.SetPreviousAccrualTime(suite.ctx, collateralType, suite.ctx.BlockTime()) - cdpKeeper.SetInterestFactor(suite.ctx, collateralType, sdk.OneDec()) - // add coins to user's address // TODO move this to auth genesis setup - sk := suite.app.GetSupplyKeeper() - sk.MintCoins(suite.ctx, cdptypes.ModuleName, cs(initialCollateral)) - sk.SendCoinsFromModuleToAccount(suite.ctx, cdptypes.ModuleName, suite.addrs[0], cs(initialCollateral)) - - err := cdpKeeper.AddCdp(suite.ctx, suite.addrs[0], initialCollateral, initialPrincipal, collateralType) - suite.Require().NoError(err) + cdpKeeper := tApp.GetCDPKeeper() + err := cdpKeeper.AddCdp(ctx, user, initialCollateral, c("usdx", 100_000_000), collateralType) + require.NoError(t, err) // Skip ahead two blocks to accumulate both interest and usdx reward for the cdp // Two blocks are required because the cdp begin blocker runs before incentive begin blocker. // In the first begin block the cdp is synced, which triggers its claim to sync. But no global rewards have accumulated yet so the sync does nothing. // Global rewards accumulate immediately after during the incentive begin blocker. // Rewards are added to the cdp's claim in the next block when the cdp is synced. - _ = suite.app.EndBlocker(suite.ctx, abci.RequestEndBlock{}) - suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(10 * time.Minute)) - _ = suite.app.BeginBlocker(suite.ctx, abci.RequestBeginBlock{}) // height and time in header are ignored by module begin blockers + _ = tApp.EndBlocker(ctx, abci.RequestEndBlock{}) + ctx = ctx.WithBlockTime(ctx.BlockTime().Add(10 * time.Minute)) + _ = tApp.BeginBlocker(ctx, abci.RequestBeginBlock{}) // height and time in header are ignored by module begin blockers - _ = suite.app.EndBlocker(suite.ctx, abci.RequestEndBlock{}) - suite.ctx = suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(10 * time.Minute)) - _ = suite.app.BeginBlocker(suite.ctx, abci.RequestBeginBlock{}) + _ = tApp.EndBlocker(ctx, abci.RequestEndBlock{}) + ctx = ctx.WithBlockTime(ctx.BlockTime().Add(10 * time.Minute)) + _ = tApp.BeginBlocker(ctx, abci.RequestBeginBlock{}) // check cdp rewards - cdp, found := cdpKeeper.GetCdpByOwnerAndCollateralType(suite.ctx, suite.addrs[0], collateralType) - suite.Require().True(found) + cdp, found := cdpKeeper.GetCdpByOwnerAndCollateralType(ctx, user, collateralType) + require.True(t, found) // This additional sync adds the rewards accumulated at the end of the last begin block. // They weren't added during the begin blocker as the incentive BB runs after the CDP BB. - suite.keeper.SynchronizeUSDXMintingReward(suite.ctx, cdp) - claim, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0]) - suite.Require().True(found) + incentiveKeeper := tApp.GetIncentiveKeeper() + incentiveKeeper.SynchronizeUSDXMintingReward(ctx, cdp) + claim, found := incentiveKeeper.GetUSDXMintingClaim(ctx, user) + require.True(t, found) // rewards are roughly rewardsPerSecond * secondsElapsed (10mins) * num blocks (2) - suite.Require().Equal(c(types.USDXMintingRewardDenom, 1_200_001_671), claim.Reward) + require.Equal(t, c(types.USDXMintingRewardDenom, 1_200_000_557), claim.Reward) } diff --git a/x/incentive/keeper/integration_test.go b/x/incentive/keeper/integration_test.go index 80bb29a7..9748c6b4 100644 --- a/x/incentive/keeper/integration_test.go +++ b/x/incentive/keeper/integration_test.go @@ -6,16 +6,25 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" - abci "github.com/tendermint/tendermint/abci/types" - tmtime "github.com/tendermint/tendermint/types/time" - "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/x/cdp" committeetypes "github.com/kava-labs/kava/x/committee/types" "github.com/kava-labs/kava/x/hard" + hardtypes "github.com/kava-labs/kava/x/hard/types" + "github.com/kava-labs/kava/x/incentive/types" "github.com/kava-labs/kava/x/pricefeed" ) +const ( + oneYear time.Duration = time.Hour * 24 * 365 +) + +// Avoid cluttering test cases with long function names +func i(in int64) sdk.Int { return sdk.NewInt(in) } +func d(str string) sdk.Dec { return sdk.MustNewDecFromStr(str) } +func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) } +func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) } + func NewCDPGenStateMulti() app.GenesisState { cdpGenesis := cdp.GenesisState{ Params: cdp.Params{ @@ -105,7 +114,7 @@ func NewCDPGenStateMulti() app.GenesisState { return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)} } -func NewPricefeedGenStateMulti() app.GenesisState { +func NewPricefeedGenStateMultiFromTime(t time.Time) app.GenesisState { pfGenesis := pricefeed.GenesisState{ Params: pricefeed.Params{ Markets: []pricefeed.Market{ @@ -122,82 +131,57 @@ func NewPricefeedGenStateMulti() app.GenesisState { MarketID: "kava:usd", OracleAddress: sdk.AccAddress{}, Price: sdk.MustNewDecFromStr("2.00"), - Expiry: time.Now().Add(1 * time.Hour), + Expiry: t.Add(1 * time.Hour), }, { MarketID: "btc:usd", OracleAddress: sdk.AccAddress{}, Price: sdk.MustNewDecFromStr("8000.00"), - Expiry: time.Now().Add(1 * time.Hour), + Expiry: t.Add(1 * time.Hour), }, { MarketID: "xrp:usd", OracleAddress: sdk.AccAddress{}, Price: sdk.MustNewDecFromStr("0.25"), - Expiry: time.Now().Add(1 * time.Hour), + Expiry: t.Add(1 * time.Hour), }, { MarketID: "bnb:usd", OracleAddress: sdk.AccAddress{}, Price: sdk.MustNewDecFromStr("17.25"), - Expiry: time.Now().Add(1 * time.Hour), + Expiry: t.Add(1 * time.Hour), }, { MarketID: "busd:usd", OracleAddress: sdk.AccAddress{}, Price: sdk.OneDec(), - Expiry: time.Now().Add(1 * time.Hour), + Expiry: t.Add(1 * time.Hour), }, { MarketID: "zzz:usd", OracleAddress: sdk.AccAddress{}, Price: sdk.MustNewDecFromStr("2.00"), - Expiry: time.Now().Add(1 * time.Hour), + Expiry: t.Add(1 * time.Hour), }, }, } return app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pfGenesis)} } -func NewHardGenStateMulti() app.GenesisState { - loanToValue, _ := sdk.NewDecFromStr("0.6") - borrowLimit := sdk.NewDec(1000000000000000) +func NewHardGenStateMulti(genTime time.Time) HardGenesisBuilder { + kavaMM := NewStandardMoneyMarket("ukava") + kavaMM.SpotMarketID = "kava:usd" + btcMM := NewStandardMoneyMarket("btcb") + btcMM.SpotMarketID = "btc:usd" - hardGS := hard.NewGenesisState(hard.NewParams( - hard.MoneyMarkets{ - hard.NewMoneyMarket("usdx", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "usdx:usd", sdk.NewInt(1000000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()), - hard.NewMoneyMarket("ukava", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "kava:usd", sdk.NewInt(1000000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()), - hard.NewMoneyMarket("bnb", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "bnb:usd", sdk.NewInt(1000000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()), - hard.NewMoneyMarket("btcb", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "btc:usd", sdk.NewInt(1000000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()), - hard.NewMoneyMarket("xrp", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "xrp:usd", sdk.NewInt(1000000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()), - hard.NewMoneyMarket("zzz", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "zzz:usd", sdk.NewInt(1000000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()), - }, - sdk.NewDec(10), - ), hard.DefaultAccumulationTimes, hard.DefaultDeposits, hard.DefaultBorrows, - hard.DefaultTotalSupplied, hard.DefaultTotalBorrowed, hard.DefaultTotalReserves, - ) - - return app.GenesisState{hard.ModuleName: hard.ModuleCdc.MustMarshalJSON(hardGS)} -} - -func NewAuthGenState(addresses []sdk.AccAddress, coins sdk.Coins) app.GenesisState { - coinsList := []sdk.Coins{} - for range addresses { - coinsList = append(coinsList, coins) - } - - // Load up our primary user address - if len(addresses) >= 4 { - coinsList[3] = sdk.NewCoins( - sdk.NewCoin("bnb", sdk.NewInt(1000000000000000)), - sdk.NewCoin("ukava", sdk.NewInt(1000000000000000)), - sdk.NewCoin("btcb", sdk.NewInt(1000000000000000)), - sdk.NewCoin("xrp", sdk.NewInt(1000000000000000)), - sdk.NewCoin("zzz", sdk.NewInt(1000000000000000)), - ) - } - - return app.NewAuthGenState(addresses, coinsList) + builder := NewHardGenesisBuilder().WithGenesisTime(genTime). + WithInitializedMoneyMarket(NewStandardMoneyMarket("usdx")). + WithInitializedMoneyMarket(kavaMM). + WithInitializedMoneyMarket(NewStandardMoneyMarket("bnb")). + WithInitializedMoneyMarket(btcMM). + WithInitializedMoneyMarket(NewStandardMoneyMarket("xrp")). + WithInitializedMoneyMarket(NewStandardMoneyMarket("zzz")) + return builder } func NewStakingGenesisState() app.GenesisState { @@ -208,37 +192,185 @@ func NewStakingGenesisState() app.GenesisState { } } -func (suite *KeeperTestSuite) SetupWithGenState() { - tApp := app.NewTestApp() - ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) - - tApp.InitializeFromGenesisStates( - NewAuthGenState(suite.getAllAddrs(), cs(c("ukava", 1_000_000_000))), - NewStakingGenesisState(), - NewPricefeedGenStateMulti(), - NewCDPGenStateMulti(), - NewHardGenStateMulti(), - ) - - // Set up a god committee - committeeModKeeper := tApp.GetCommitteeKeeper() - godCommittee := committeetypes.MemberCommittee{ - BaseCommittee: committeetypes.BaseCommittee{ - ID: 1, - Description: "This committee is for testing.", - Members: suite.addrs[:2], - Permissions: []committeetypes.Permission{committeetypes.GodPermission{}}, - VoteThreshold: d("0.667"), - ProposalDuration: time.Hour * 24 * 7, - TallyOption: committeetypes.FirstPastThePost, +func NewCommitteeGenesisState(members []sdk.AccAddress) app.GenesisState { + genState := committeetypes.DefaultGenesisState() + genState.Committees = committeetypes.Committees{ + committeetypes.MemberCommittee{ + BaseCommittee: committeetypes.BaseCommittee{ + ID: genState.NextProposalID, + Description: "This committee is for testing.", + Members: members, + Permissions: []committeetypes.Permission{committeetypes.GodPermission{}}, + VoteThreshold: d("0.667"), + ProposalDuration: time.Hour * 24 * 7, + TallyOption: committeetypes.FirstPastThePost, + }, }, } - committeeModKeeper.SetCommittee(ctx, godCommittee) - - suite.app = tApp - suite.ctx = ctx - suite.keeper = tApp.GetIncentiveKeeper() - suite.hardKeeper = tApp.GetHardKeeper() - suite.stakingKeeper = tApp.GetStakingKeeper() - suite.committeeKeeper = committeeModKeeper + genState.NextProposalID += 1 + return app.GenesisState{ + committeetypes.ModuleName: committeetypes.ModuleCdc.MustMarshalJSON(genState), + } +} + +// IncentiveGenesisBuilder is a tool for creating an incentive genesis state. +// Helper methods add values onto a default genesis state. +// All methods are immutable and return updated copies of the builder. +type IncentiveGenesisBuilder struct { + types.GenesisState + genesisTime time.Time +} + +func NewIncentiveGenesisBuilder() IncentiveGenesisBuilder { + return IncentiveGenesisBuilder{ + GenesisState: types.DefaultGenesisState(), + genesisTime: time.Time{}, + } +} + +func (builder IncentiveGenesisBuilder) Build() types.GenesisState { + return builder.GenesisState +} + +func (builder IncentiveGenesisBuilder) BuildMarshalled() app.GenesisState { + return app.GenesisState{ + types.ModuleName: types.ModuleCdc.MustMarshalJSON(builder.Build()), + } +} + +func (builder IncentiveGenesisBuilder) WithGenesisTime(time time.Time) IncentiveGenesisBuilder { + builder.genesisTime = time + builder.Params.ClaimEnd = time.Add(5 * oneYear) + return builder +} + +func (builder IncentiveGenesisBuilder) WithInitializedBorrowRewardPeriod(period types.MultiRewardPeriod) IncentiveGenesisBuilder { + builder.Params.HardBorrowRewardPeriods = append(builder.Params.HardBorrowRewardPeriods, period) + + accumulationTimeForPeriod := types.NewGenesisAccumulationTime(period.CollateralType, builder.genesisTime) + builder.HardBorrowAccumulationTimes = append(builder.HardBorrowAccumulationTimes, accumulationTimeForPeriod) + return builder +} + +func (builder IncentiveGenesisBuilder) WithSimpleBorrowRewardPeriod(ctype string, rewardsPerSecond sdk.Coins) IncentiveGenesisBuilder { + return builder.WithInitializedBorrowRewardPeriod(types.NewMultiRewardPeriod( + true, + ctype, + builder.genesisTime, + builder.genesisTime.Add(4*oneYear), + rewardsPerSecond, + )) +} +func (builder IncentiveGenesisBuilder) WithInitializedSupplyRewardPeriod(period types.MultiRewardPeriod) IncentiveGenesisBuilder { + // TODO this could set the start/end times on the period according to builder.genesisTime + // Then they could be created by a different builder + + builder.Params.HardSupplyRewardPeriods = append(builder.Params.HardSupplyRewardPeriods, period) + + accumulationTimeForPeriod := types.NewGenesisAccumulationTime(period.CollateralType, builder.genesisTime) + builder.HardSupplyAccumulationTimes = append(builder.HardSupplyAccumulationTimes, accumulationTimeForPeriod) + return builder +} + +func (builder IncentiveGenesisBuilder) WithSimpleSupplyRewardPeriod(ctype string, rewardsPerSecond sdk.Coins) IncentiveGenesisBuilder { + return builder.WithInitializedSupplyRewardPeriod(types.NewMultiRewardPeriod( + true, + ctype, + builder.genesisTime, + builder.genesisTime.Add(4*oneYear), + rewardsPerSecond, + )) +} +func (builder IncentiveGenesisBuilder) WithInitializedDelegatorRewardPeriod(period types.RewardPeriod) IncentiveGenesisBuilder { + builder.Params.HardDelegatorRewardPeriods = append(builder.Params.HardDelegatorRewardPeriods, period) + + accumulationTimeForPeriod := types.NewGenesisAccumulationTime(period.CollateralType, builder.genesisTime) + builder.HardDelegatorAccumulationTimes = append(builder.HardDelegatorAccumulationTimes, accumulationTimeForPeriod) + return builder +} + +func (builder IncentiveGenesisBuilder) WithSimpleDelegatorRewardPeriod(ctype string, rewardsPerSecond sdk.Coin) IncentiveGenesisBuilder { + return builder.WithInitializedDelegatorRewardPeriod(types.NewRewardPeriod( + true, + ctype, + builder.genesisTime, + builder.genesisTime.Add(4*oneYear), + rewardsPerSecond, + )) +} +func (builder IncentiveGenesisBuilder) WithInitializedUSDXRewardPeriod(period types.RewardPeriod) IncentiveGenesisBuilder { + builder.Params.USDXMintingRewardPeriods = append(builder.Params.USDXMintingRewardPeriods, period) + + accumulationTimeForPeriod := types.NewGenesisAccumulationTime(period.CollateralType, builder.genesisTime) + builder.USDXAccumulationTimes = append(builder.USDXAccumulationTimes, accumulationTimeForPeriod) + return builder +} + +func (builder IncentiveGenesisBuilder) WithSimpleUSDXRewardPeriod(ctype string, rewardsPerSecond sdk.Coin) IncentiveGenesisBuilder { + return builder.WithInitializedUSDXRewardPeriod(types.NewRewardPeriod( + true, + ctype, + builder.genesisTime, + builder.genesisTime.Add(4*oneYear), + rewardsPerSecond, + )) +} + +func (builder IncentiveGenesisBuilder) WithMultipliers(multipliers types.Multipliers) IncentiveGenesisBuilder { + builder.Params.ClaimMultipliers = multipliers + return builder +} + +// HardGenesisBuilder is a tool for creating a hard genesis state. +// Helper methods add values onto a default genesis state. +// All methods are immutable and return updated copies of the builder. +type HardGenesisBuilder struct { + hardtypes.GenesisState + genesisTime time.Time +} + +func NewHardGenesisBuilder() HardGenesisBuilder { + return HardGenesisBuilder{ + GenesisState: hardtypes.DefaultGenesisState(), + } +} +func (builder HardGenesisBuilder) Build() hardtypes.GenesisState { + return builder.GenesisState +} +func (builder HardGenesisBuilder) BuildMarshalled() app.GenesisState { + return app.GenesisState{ + hardtypes.ModuleName: hardtypes.ModuleCdc.MustMarshalJSON(builder.Build()), + } +} +func (builder HardGenesisBuilder) WithGenesisTime(genTime time.Time) HardGenesisBuilder { + builder.genesisTime = genTime + return builder +} +func (builder HardGenesisBuilder) WithInitializedMoneyMarket(market hard.MoneyMarket) HardGenesisBuilder { + builder.Params.MoneyMarkets = append(builder.Params.MoneyMarkets, market) + + builder.PreviousAccumulationTimes = append( + builder.PreviousAccumulationTimes, + hardtypes.NewGenesisAccumulationTime(market.Denom, builder.genesisTime, sdk.OneDec(), sdk.OneDec()), + ) + return builder +} +func (builder HardGenesisBuilder) WithMinBorrow(minUSDValue sdk.Dec) HardGenesisBuilder { + builder.Params.MinimumBorrowUSDValue = minUSDValue + return builder +} +func NewStandardMoneyMarket(denom string) hardtypes.MoneyMarket { + return hardtypes.NewMoneyMarket( + denom, + hard.NewBorrowLimit( + false, + sdk.NewDec(1e15), + d("0.6"), + ), + denom+":usd", + i(1e6), + hard.NewInterestRateModel(d("0.05"), d("2"), d("0.8"), d("10")), + d("0.05"), + sdk.ZeroDec(), + ) } diff --git a/x/incentive/keeper/keeper_test.go b/x/incentive/keeper/keeper_test.go index 146d7143..8628b14e 100644 --- a/x/incentive/keeper/keeper_test.go +++ b/x/incentive/keeper/keeper_test.go @@ -2,22 +2,14 @@ package keeper_test import ( "testing" + "time" "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" - "github.com/cosmos/cosmos-sdk/x/auth/vesting" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" - - abci "github.com/tendermint/tendermint/abci/types" - tmtime "github.com/tendermint/tendermint/types/time" "github.com/kava-labs/kava/app" - committeekeeper "github.com/kava-labs/kava/x/committee/keeper" - hardkeeper "github.com/kava-labs/kava/x/hard/keeper" "github.com/kava-labs/kava/x/incentive/keeper" "github.com/kava-labs/kava/x/incentive/types" ) @@ -26,58 +18,35 @@ import ( type KeeperTestSuite struct { suite.Suite - keeper keeper.Keeper - hardKeeper hardkeeper.Keeper - stakingKeeper stakingkeeper.Keeper - committeeKeeper committeekeeper.Keeper - app app.TestApp - ctx sdk.Context - addrs []sdk.AccAddress - validatorAddrs []sdk.ValAddress + keeper keeper.Keeper + + app app.TestApp + ctx sdk.Context + + genesisTime time.Time + addrs []sdk.AccAddress } -// The default state used by each test +// SetupTest is run automatically before each suite test func (suite *KeeperTestSuite) SetupTest() { config := sdk.GetConfig() app.SetBech32AddressPrefixes(config) - _, allAddrs := app.GeneratePrivKeyAddressPairs(10) - suite.addrs = allAddrs[:5] - for _, a := range allAddrs[5:] { - suite.validatorAddrs = append(suite.validatorAddrs, sdk.ValAddress(a)) - } + _, suite.addrs = app.GeneratePrivKeyAddressPairs(5) - tApp := app.NewTestApp() - ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) - - tApp.InitializeFromGenesisStates() - - suite.keeper = tApp.GetIncentiveKeeper() - suite.app = tApp - suite.ctx = ctx + suite.genesisTime = time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC) } -// getAllAddrs returns all user and validator addresses in the suite -func (suite *KeeperTestSuite) getAllAddrs() []sdk.AccAddress { - accAddrs := []sdk.AccAddress{} // initialize new slice to avoid accidental modifications to underlying - accAddrs = append(accAddrs, suite.addrs...) - for _, a := range suite.validatorAddrs { - accAddrs = append(accAddrs, sdk.AccAddress(a)) - } - return accAddrs -} +func (suite *KeeperTestSuite) SetupApp() { + suite.app = app.NewTestApp() -func (suite *KeeperTestSuite) getAccount(addr sdk.AccAddress) authexported.Account { - ak := suite.app.GetAccountKeeper() - return ak.GetAccount(suite.ctx, addr) -} + suite.keeper = suite.app.GetIncentiveKeeper() -func (suite *KeeperTestSuite) getModuleAccount(name string) supplyexported.ModuleAccountI { - sk := suite.app.GetSupplyKeeper() - return sk.GetModuleAccount(suite.ctx, name) + suite.ctx = suite.app.NewContext(true, abci.Header{Height: 1, Time: suite.genesisTime}) } func (suite *KeeperTestSuite) TestGetSetDeleteUSDXMintingClaim() { + suite.SetupApp() c := types.NewUSDXMintingClaim(suite.addrs[0], c("ukava", 1000000), types.RewardIndexes{types.NewRewardIndex("bnb-a", sdk.ZeroDec())}) _, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0]) suite.Require().False(found) @@ -95,6 +64,7 @@ func (suite *KeeperTestSuite) TestGetSetDeleteUSDXMintingClaim() { } func (suite *KeeperTestSuite) TestIterateUSDXMintingClaims() { + suite.SetupApp() for i := 0; i < len(suite.addrs); i++ { c := types.NewUSDXMintingClaim(suite.addrs[i], c("ukava", 100000), types.RewardIndexes{types.NewRewardIndex("bnb-a", sdk.ZeroDec())}) suite.Require().NotPanics(func() { @@ -112,28 +82,6 @@ func (suite *KeeperTestSuite) TestIterateUSDXMintingClaims() { suite.Require().Equal(len(suite.addrs), len(claims)) } -func createPeriodicVestingAccount(origVesting sdk.Coins, periods vesting.Periods, startTime, endTime int64) (*vesting.PeriodicVestingAccount, error) { - _, addr := app.GeneratePrivKeyAddressPairs(1) - bacc := auth.NewBaseAccountWithAddress(addr[0]) - bacc.Coins = origVesting - bva, err := vesting.NewBaseVestingAccount(&bacc, origVesting, endTime) - if err != nil { - return &vesting.PeriodicVestingAccount{}, err - } - pva := vesting.NewPeriodicVestingAccountRaw(bva, startTime, periods) - err = pva.Validate() - if err != nil { - return &vesting.PeriodicVestingAccount{}, err - } - return pva, nil -} - -// Avoid cluttering test cases with long function names -func i(in int64) sdk.Int { return sdk.NewInt(in) } -func d(str string) sdk.Dec { return sdk.MustNewDecFromStr(str) } -func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) } -func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) } - func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } diff --git a/x/incentive/keeper/payout_test.go b/x/incentive/keeper/payout_test.go index 7f146d76..4b848627 100644 --- a/x/incentive/keeper/payout_test.go +++ b/x/incentive/keeper/payout_test.go @@ -3,28 +3,91 @@ package keeper_test import ( "errors" "strings" + "testing" "time" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/auth/vesting" + supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" + "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/kava-labs/kava/app" + cdpkeeper "github.com/kava-labs/kava/x/cdp/keeper" cdptypes "github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/hard" + hardkeeper "github.com/kava-labs/kava/x/hard/keeper" + "github.com/kava-labs/kava/x/incentive/keeper" "github.com/kava-labs/kava/x/incentive/types" "github.com/kava-labs/kava/x/kavadist" validatorvesting "github.com/kava-labs/kava/x/validator-vesting" ) -func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaim() { +// Test suite used for all keeper tests +type PayoutTestSuite struct { + suite.Suite + + keeper keeper.Keeper + hardKeeper hardkeeper.Keeper + cdpKeeper cdpkeeper.Keeper + + app app.TestApp + ctx sdk.Context + + genesisTime time.Time + addrs []sdk.AccAddress +} + +// SetupTest is run automatically before each suite test +func (suite *PayoutTestSuite) SetupTest() { + config := sdk.GetConfig() + app.SetBech32AddressPrefixes(config) + + _, suite.addrs = app.GeneratePrivKeyAddressPairs(5) + + suite.genesisTime = time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC) +} + +func (suite *PayoutTestSuite) SetupApp() { + suite.app = app.NewTestApp() + + suite.keeper = suite.app.GetIncentiveKeeper() + suite.hardKeeper = suite.app.GetHardKeeper() + suite.cdpKeeper = suite.app.GetCDPKeeper() + + suite.ctx = suite.app.NewContext(true, abci.Header{Height: 1, Time: suite.genesisTime}) +} + +func (suite *PayoutTestSuite) SetupWithGenState(authBuilder app.AuthGenesisBuilder, incentBuilder IncentiveGenesisBuilder, hardBuilder HardGenesisBuilder) { + suite.SetupApp() + + suite.app.InitializeFromGenesisStatesWithTime( + suite.genesisTime, + authBuilder.BuildMarshalled(), + NewPricefeedGenStateMultiFromTime(suite.genesisTime), + NewCDPGenStateMulti(), + hardBuilder.BuildMarshalled(), + incentBuilder.BuildMarshalled(), + ) +} + +func (suite *PayoutTestSuite) getAccount(addr sdk.AccAddress) authexported.Account { + ak := suite.app.GetAccountKeeper() + return ak.GetAccount(suite.ctx, addr) +} + +func (suite *PayoutTestSuite) getModuleAccount(name string) supplyexported.ModuleAccountI { + sk := suite.app.GetSupplyKeeper() + return sk.GetModuleAccount(suite.ctx, name) +} + +func (suite *PayoutTestSuite) TestPayoutUSDXMintingClaim() { type args struct { ctype string rewardsPerSecond sdk.Coin - initialTime time.Time initialCollateral sdk.Coin initialPrincipal sdk.Coin multipliers types.Multipliers @@ -49,13 +112,12 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaim() { args{ ctype: "bnb-a", rewardsPerSecond: c("ukava", 122354), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), initialCollateral: c("bnb", 1000000000000), initialPrincipal: c("usdx", 10000000000), multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, multiplier: types.MultiplierName("large"), timeElapsed: 86400, - expectedBalance: cs(c("usdx", 10000000000), c("ukava", 11571385600)), + expectedBalance: cs(c("usdx", 10000000000), c("ukava", 10571385600)), expectedPeriods: vesting.Periods{vesting.Period{Length: 32918400, Amount: cs(c("ukava", 10571385600))}}, isPeriodicVestingAccount: true, }, @@ -69,7 +131,6 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaim() { args{ ctype: "bnb-a", rewardsPerSecond: c("ukava", 0), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), initialCollateral: c("bnb", 1000000000000), initialPrincipal: c("usdx", 10000000000), multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, @@ -87,39 +148,23 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaim() { } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + userAddr := suite.addrs[0] + authBulder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(userAddr, cs(tc.args.initialCollateral)). + WithSimpleModuleAccount(kavadist.ModuleName, cs(c("ukava", 1000000000000))) - // setup incentive state - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - tc.args.multipliers, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime) - suite.keeper.SetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec()) + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleUSDXRewardPeriod(tc.args.ctype, tc.args.rewardsPerSecond). + WithMultipliers(tc.args.multipliers) - // setup account state - sk := suite.app.GetSupplyKeeper() - err := sk.MintCoins(suite.ctx, cdptypes.ModuleName, sdk.NewCoins(tc.args.initialCollateral)) - suite.Require().NoError(err) - err = sk.SendCoinsFromModuleToAccount(suite.ctx, cdptypes.ModuleName, suite.addrs[0], sdk.NewCoins(tc.args.initialCollateral)) - suite.Require().NoError(err) - - // setup kavadist state - err = sk.MintCoins(suite.ctx, kavadist.ModuleName, cs(c("ukava", 1000000000000))) - suite.Require().NoError(err) + suite.SetupWithGenState(authBulder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) // setup cdp state - cdpKeeper := suite.app.GetCDPKeeper() - err = cdpKeeper.AddCdp(suite.ctx, suite.addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype) + err := suite.cdpKeeper.AddCdp(suite.ctx, userAddr, tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype) suite.Require().NoError(err) - claim, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0]) + claim, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, userAddr) suite.Require().True(found) suite.Require().Equal(sdk.ZeroDec(), claim.RewardIndexes[0].RewardFactor) @@ -130,13 +175,13 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaim() { err = suite.keeper.AccumulateUSDXMintingRewards(suite.ctx, rewardPeriod) suite.Require().NoError(err) - err = suite.keeper.ClaimUSDXMintingReward(suite.ctx, suite.addrs[0], tc.args.multiplier) + err = suite.keeper.ClaimUSDXMintingReward(suite.ctx, userAddr, tc.args.multiplier) if tc.errArgs.expectPass { suite.Require().NoError(err) - ak := suite.app.GetAccountKeeper() - acc := ak.GetAccount(suite.ctx, suite.addrs[0]) - suite.Require().Equal(tc.args.expectedBalance, acc.GetCoins()) // TODO check balance change to decouple from initialized account balance. + + acc := suite.getAccount(userAddr) + suite.Require().Equal(tc.args.expectedBalance, acc.GetCoins()) if tc.args.isPeriodicVestingAccount { vacc, ok := acc.(*vesting.PeriodicVestingAccount) @@ -144,7 +189,7 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaim() { suite.Require().Equal(tc.args.expectedPeriods, vacc.VestingPeriods) } - claim, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0]) + claim, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, userAddr) suite.Require().True(found) suite.Require().Equal(c("ukava", 0), claim.Reward) } else { @@ -155,19 +200,17 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaim() { } } -func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaimVVesting() { +func (suite *PayoutTestSuite) TestPayoutUSDXMintingClaimVVesting() { type args struct { - ctype string - rewardsPerSecond sdk.Coin - initialTime time.Time - initialCollateral sdk.Coin - initialPrincipal sdk.Coin - multipliers types.Multipliers - multiplier types.MultiplierName - timeElapsed int - expectedBalance sdk.Coins - expectedPeriods vesting.Periods - isPeriodicVestingAccount bool + ctype string + rewardsPerSecond sdk.Coin + initialCollateral sdk.Coin + initialPrincipal sdk.Coin + multipliers types.Multipliers + multiplier types.MultiplierName + timeElapsed int + expectedBalance sdk.Coins + expectedPeriods vesting.Periods } type errArgs struct { expectPass bool @@ -182,17 +225,15 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaimVVesting() { { "valid 1 day", args{ - ctype: "bnb-a", - rewardsPerSecond: c("ukava", 122354), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - initialCollateral: c("bnb", 1000000000000), - initialPrincipal: c("usdx", 10000000000), - multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - multiplier: types.MultiplierName("large"), - timeElapsed: 86400, - expectedBalance: cs(c("ukava", 11571385600)), - expectedPeriods: vesting.Periods{vesting.Period{Length: 32918400, Amount: cs(c("ukava", 10571385600))}}, - isPeriodicVestingAccount: true, + ctype: "bnb-a", + rewardsPerSecond: c("ukava", 122354), + initialCollateral: c("bnb", 1e12), + initialPrincipal: c("usdx", 1e10), + multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, + multiplier: types.MultiplierName("large"), + timeElapsed: 86400, + expectedBalance: cs(c("ukava", 10571385600)), + expectedPeriods: vesting.Periods{vesting.Period{Length: 32918400, Amount: cs(c("ukava", 10571385600))}}, }, errArgs{ expectPass: true, @@ -202,17 +243,15 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaimVVesting() { { "invalid zero rewards", args{ - ctype: "bnb-a", - rewardsPerSecond: c("ukava", 0), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - initialCollateral: c("bnb", 1000000000000), - initialPrincipal: c("usdx", 10000000000), - multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - multiplier: types.MultiplierName("large"), - timeElapsed: 86400, - expectedBalance: cs(), - expectedPeriods: vesting.Periods{}, - isPeriodicVestingAccount: false, + ctype: "bnb-a", + rewardsPerSecond: c("ukava", 0), + initialCollateral: c("bnb", 1e12), + initialPrincipal: c("usdx", 1e10), + multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, + multiplier: types.MultiplierName("large"), + timeElapsed: 86400, + expectedBalance: cs(), + expectedPeriods: vesting.Periods{}, }, errArgs{ expectPass: false, @@ -222,47 +261,29 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaimVVesting() { } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) - // setup incentive state - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - tc.args.multipliers, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime) - suite.keeper.SetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec()) - - // sets addrs[2] to be a validator vesting account - ak := suite.app.GetAccountKeeper() - acc := ak.GetAccount(suite.ctx, suite.addrs[2]) - bacc := auth.NewBaseAccount(acc.GetAddress(), acc.GetCoins(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence()) - bva, err2 := vesting.NewBaseVestingAccount(bacc, cs(c("ukava", 400)), suite.ctx.BlockTime().Unix()+16) - suite.Require().NoError(err2) + bacc := auth.NewBaseAccount(suite.addrs[2], cs(tc.args.initialCollateral, c("ukava", 400)), nil, 0, 0) + bva, err := vesting.NewBaseVestingAccount(bacc, cs(c("ukava", 400)), suite.genesisTime.Unix()+16) + suite.Require().NoError(err) periods := vesting.Periods{ vesting.Period{Length: int64(1), Amount: cs(c("ukava", 100))}, vesting.Period{Length: int64(2), Amount: cs(c("ukava", 100))}, vesting.Period{Length: int64(8), Amount: cs(c("ukava", 100))}, vesting.Period{Length: int64(5), Amount: cs(c("ukava", 100))}, } - vva := validatorvesting.NewValidatorVestingAccountRaw(bva, suite.ctx.BlockTime().Unix(), periods, sdk.ConsAddress{}, nil, 90) - ak.SetAccount(suite.ctx, vva) + vva := validatorvesting.NewValidatorVestingAccountRaw(bva, suite.genesisTime.Unix(), periods, sdk.ConsAddress{}, nil, 90) - // setup account state - sk := suite.app.GetSupplyKeeper() - err := sk.MintCoins(suite.ctx, cdptypes.ModuleName, sdk.NewCoins(tc.args.initialCollateral)) - suite.Require().NoError(err) - err = sk.SendCoinsFromModuleToAccount(suite.ctx, cdptypes.ModuleName, suite.addrs[2], sdk.NewCoins(tc.args.initialCollateral)) - suite.Require().NoError(err) + authBulder := app.NewAuthGenesisBuilder(). + WithAccounts(vva). + WithSimpleModuleAccount(kavadist.ModuleName, cs(c("ukava", 1e18))). + WithSimpleAccount(suite.addrs[0], cs()) // the recipient address needs to be a instantiated account // TODO change? - // setup kavadist state - err = sk.MintCoins(suite.ctx, kavadist.ModuleName, cs(c("ukava", 1000000000000))) - suite.Require().NoError(err) + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleUSDXRewardPeriod(tc.args.ctype, tc.args.rewardsPerSecond). + WithMultipliers(tc.args.multipliers) + + suite.SetupWithGenState(authBulder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) // setup cdp state cdpKeeper := suite.app.GetCDPKeeper() @@ -273,6 +294,7 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaimVVesting() { suite.Require().True(found) suite.Require().Equal(sdk.ZeroDec(), claim.RewardIndexes[0].RewardFactor) + // accumulate some usdx rewards updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed)) suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) rewardPeriod, found := suite.keeper.GetUSDXMintingRewardPeriod(suite.ctx, tc.args.ctype) @@ -286,13 +308,11 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaimVVesting() { suite.Require().NoError(err) ak := suite.app.GetAccountKeeper() acc := ak.GetAccount(suite.ctx, suite.addrs[0]) - suite.Require().Equal(tc.args.expectedBalance, acc.GetCoins()) // TODO check balance change to decouple from initialized account balance. + suite.Require().Equal(tc.args.expectedBalance, acc.GetCoins()) - if tc.args.isPeriodicVestingAccount { - vacc, ok := acc.(*vesting.PeriodicVestingAccount) - suite.Require().True(ok) - suite.Require().Equal(tc.args.expectedPeriods, vacc.VestingPeriods) - } + vacc, ok := acc.(*vesting.PeriodicVestingAccount) + suite.Require().True(ok) + suite.Require().Equal(tc.args.expectedPeriods, vacc.VestingPeriods) claim, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[2]) suite.Require().True(found) @@ -305,12 +325,11 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaimVVesting() { } } -func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaim() { +func (suite *PayoutTestSuite) TestPayoutHardLiquidityProviderClaim() { type args struct { deposit sdk.Coins borrow sdk.Coins rewardsPerSecond sdk.Coins - initialTime time.Time multipliers types.Multipliers multiplier types.MultiplierName timeElapsed int64 @@ -334,7 +353,6 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaim() { deposit: cs(c("bnb", 10000000000)), borrow: cs(c("bnb", 5000000000)), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, multiplier: types.MultiplierName("large"), timeElapsed: 86400, @@ -353,7 +371,6 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaim() { deposit: cs(c("bnb", 10000000000)), borrow: cs(c("bnb", 5000000000)), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, multiplier: types.MultiplierName("large"), timeElapsed: 864000, @@ -366,32 +383,12 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaim() { contains: "", }, }, - { - "invalid zero rewards", - args{ - deposit: cs(c("bnb", 10000000000)), - borrow: cs(c("bnb", 5000000000)), - rewardsPerSecond: cs(c("hard", 0)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - multiplier: types.MultiplierName("large"), - timeElapsed: 86400, - expectedRewards: cs(c("hard", 0)), - expectedPeriods: vesting.Periods{}, - isPeriodicVestingAccount: false, - }, - errArgs{ - expectPass: false, - contains: "claim amount rounds to zero", - }, - }, { "multiple reward denoms: valid 1 day", args{ deposit: cs(c("bnb", 10000000000)), borrow: cs(c("bnb", 5000000000)), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, multiplier: types.MultiplierName("large"), timeElapsed: 86400, @@ -410,7 +407,6 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaim() { deposit: cs(c("bnb", 10000000000)), borrow: cs(c("bnb", 5000000000)), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, multiplier: types.MultiplierName("large"), timeElapsed: 864000, @@ -429,7 +425,6 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaim() { deposit: cs(c("bnb", 10000000000)), borrow: cs(c("bnb", 5000000000)), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 222222)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, multiplier: types.MultiplierName("large"), timeElapsed: 86400, @@ -446,71 +441,31 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaim() { for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) - - // setup kavadist state - sk := suite.app.GetSupplyKeeper() - err := sk.MintCoins(suite.ctx, kavadist.ModuleName, cs(c("hard", 1000000000000000000), c("ukava", 1000000000000000000))) - suite.Require().NoError(err) - - // Set up generic reward periods - var multiRewardPeriods types.MultiRewardPeriods - var rewardPeriods types.RewardPeriods - for _, coin := range tc.args.deposit { - if len(tc.args.rewardsPerSecond) > 0 { - rewardPeriod := types.NewRewardPeriod(true, coin.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[0]) - rewardPeriods = append(rewardPeriods, rewardPeriod) - } - multiRewardPeriod := types.NewMultiRewardPeriod(true, coin.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond) - multiRewardPeriods = append(multiRewardPeriods, multiRewardPeriod) - } - - // Set up generic reward periods - params := types.NewParams( - rewardPeriods, multiRewardPeriods, multiRewardPeriods, rewardPeriods, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, params) - - // Set each denom's previous accrual time and supply reward factor - if len(tc.args.rewardsPerSecond) > 0 { - for _, coin := range tc.args.deposit { - suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, coin.Denom, tc.args.initialTime) - var rewardIndexes types.RewardIndexes - for _, rewardCoin := range tc.args.rewardsPerSecond { - rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) - } - suite.keeper.SetHardSupplyRewardIndexes(suite.ctx, coin.Denom, rewardIndexes) - } - } - - // Set each denom's previous accrual time and borrow reward factor - if len(tc.args.rewardsPerSecond) > 0 { - for _, coin := range tc.args.borrow { - suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, coin.Denom, tc.args.initialTime) - var rewardIndexes types.RewardIndexes - for _, rewardCoin := range tc.args.rewardsPerSecond { - rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) - } - suite.keeper.SetHardBorrowRewardIndexes(suite.ctx, coin.Denom, rewardIndexes) - } - } - - hardKeeper := suite.app.GetHardKeeper() userAddr := suite.addrs[3] + authBulder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(userAddr, cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15))). + WithSimpleModuleAccount(kavadist.ModuleName, cs(c("hard", 1000000000000000000), c("ukava", 1000000000000000000))) + + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithMultipliers(tc.args.multipliers) + for _, c := range tc.args.deposit { + incentBuilder = incentBuilder.WithSimpleSupplyRewardPeriod(c.Denom, tc.args.rewardsPerSecond) + } + for _, c := range tc.args.borrow { + incentBuilder = incentBuilder.WithSimpleBorrowRewardPeriod(c.Denom, tc.args.rewardsPerSecond) + } + + suite.SetupWithGenState(authBulder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) // User deposits and borrows - err = hardKeeper.Deposit(suite.ctx, userAddr, tc.args.deposit) + err := suite.hardKeeper.Deposit(suite.ctx, userAddr, tc.args.deposit) suite.Require().NoError(err) - err = hardKeeper.Borrow(suite.ctx, userAddr, tc.args.borrow) + err = suite.hardKeeper.Borrow(suite.ctx, userAddr, tc.args.borrow) suite.Require().NoError(err) // Check that Hard hooks initialized a HardLiquidityProviderClaim that has 0 rewards - claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) + claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, userAddr) suite.Require().True(found) for _, coin := range tc.args.deposit { suite.Require().Equal(sdk.ZeroInt(), claim.Reward.AmountOf(coin.Denom)) @@ -520,9 +475,6 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaim() { runAtTime := time.Unix(suite.ctx.BlockTime().Unix()+(tc.args.timeElapsed), 0) runCtx := suite.ctx.WithBlockTime(runAtTime) - // Run Hard begin blocker - hard.BeginBlocker(runCtx, suite.hardKeeper) - // Accumulate supply rewards for each deposit denom for _, coin := range tc.args.deposit { rewardPeriod, found := suite.keeper.GetHardSupplyRewardPeriods(runCtx, coin.Denom) @@ -540,25 +492,25 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaim() { } // Sync hard supply rewards - deposit, found := suite.hardKeeper.GetDeposit(suite.ctx, suite.addrs[3]) + deposit, found := suite.hardKeeper.GetDeposit(suite.ctx, userAddr) suite.Require().True(found) suite.keeper.SynchronizeHardSupplyReward(suite.ctx, deposit) // Sync hard borrow rewards - borrow, found := suite.hardKeeper.GetBorrow(suite.ctx, suite.addrs[3]) + borrow, found := suite.hardKeeper.GetBorrow(suite.ctx, userAddr) suite.Require().True(found) suite.keeper.SynchronizeHardBorrowReward(suite.ctx, borrow) // Fetch pre-claim balances ak := suite.app.GetAccountKeeper() - preClaimAcc := ak.GetAccount(runCtx, suite.addrs[3]) + preClaimAcc := ak.GetAccount(runCtx, userAddr) - err = suite.keeper.ClaimHardReward(runCtx, suite.addrs[3], tc.args.multiplier) + err = suite.keeper.ClaimHardReward(runCtx, userAddr, tc.args.multiplier) if tc.errArgs.expectPass { suite.Require().NoError(err) // Check that user's balance has increased by expected reward amount - postClaimAcc := ak.GetAccount(suite.ctx, suite.addrs[3]) + postClaimAcc := ak.GetAccount(suite.ctx, userAddr) suite.Require().Equal(preClaimAcc.GetCoins().Add(tc.args.expectedRewards...), postClaimAcc.GetCoins()) if tc.args.isPeriodicVestingAccount { @@ -568,7 +520,7 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaim() { } // Check that each claim reward coin's amount has been reset to 0 - claim, found := suite.keeper.GetHardLiquidityProviderClaim(runCtx, suite.addrs[3]) + claim, found := suite.keeper.GetHardLiquidityProviderClaim(runCtx, userAddr) suite.Require().True(found) for _, claimRewardCoin := range claim.Reward { suite.Require().Equal(c(claimRewardCoin.Denom, 0), claimRewardCoin) @@ -581,18 +533,16 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaim() { } } -func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() { +func (suite *PayoutTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() { type args struct { - deposit sdk.Coins - borrow sdk.Coins - rewardsPerSecond sdk.Coins - initialTime time.Time - multipliers types.Multipliers - multiplier types.MultiplierName - timeElapsed int64 - expectedRewards sdk.Coins - expectedPeriods vesting.Periods - isPeriodicVestingAccount bool + deposit sdk.Coins + borrow sdk.Coins + rewardsPerSecond sdk.Coins + multipliers types.Multipliers + multiplier types.MultiplierName + timeElapsed int64 + expectedRewards sdk.Coins + expectedPeriods vesting.Periods } type errArgs struct { expectPass bool @@ -607,16 +557,14 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() { { "single reward denom: valid 1 day", args{ - deposit: cs(c("bnb", 10000000000)), - borrow: cs(c("bnb", 5000000000)), - rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - multiplier: types.MultiplierName("large"), - timeElapsed: 86400, - expectedRewards: cs(c("hard", 21142771200)), // 10571385600 (deposit reward) + 10571385600 (borrow reward) - expectedPeriods: vesting.Periods{vesting.Period{Length: 32918400, Amount: cs(c("hard", 21142771200))}}, - isPeriodicVestingAccount: true, + deposit: cs(c("bnb", 10000000000)), + borrow: cs(c("bnb", 5000000000)), + rewardsPerSecond: cs(c("hard", 122354)), + multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, + multiplier: types.MultiplierName("large"), + timeElapsed: 86400, + expectedRewards: cs(c("hard", 21142771202)), + expectedPeriods: vesting.Periods{vesting.Period{Length: 32918400, Amount: cs(c("hard", 21142771202))}}, }, errArgs{ expectPass: true, @@ -626,54 +574,31 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() { { "single reward denom: valid 10 days", args{ - deposit: cs(c("bnb", 10000000000)), - borrow: cs(c("bnb", 5000000000)), - rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - multiplier: types.MultiplierName("large"), - timeElapsed: 864000, - expectedRewards: cs(c("hard", 211427712000)), // 105713856000 (deposit reward) + 105713856000 (borrow reward) - expectedPeriods: vesting.Periods{vesting.Period{Length: 32140800, Amount: cs(c("hard", 211427712000))}}, - isPeriodicVestingAccount: true, + deposit: cs(c("bnb", 10000000000)), + borrow: cs(c("bnb", 5000000000)), + rewardsPerSecond: cs(c("hard", 122354)), + multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, + multiplier: types.MultiplierName("large"), + timeElapsed: 864000, + expectedRewards: cs(c("hard", 211427712008)), + expectedPeriods: vesting.Periods{vesting.Period{Length: 32140800, Amount: cs(c("hard", 211427712008))}}, }, errArgs{ expectPass: true, contains: "", }, }, - { - "invalid zero rewards", - args{ - deposit: cs(c("bnb", 10000000000)), - borrow: cs(c("bnb", 5000000000)), - rewardsPerSecond: cs(c("hard", 0)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - multiplier: types.MultiplierName("large"), - timeElapsed: 86400, - expectedRewards: cs(c("hard", 0)), - expectedPeriods: vesting.Periods{}, - isPeriodicVestingAccount: false, - }, - errArgs{ - expectPass: false, - contains: "claim amount rounds to zero", - }, - }, { "multiple reward denoms: valid 1 day", args{ - deposit: cs(c("bnb", 10000000000)), - borrow: cs(c("bnb", 5000000000)), - rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - multiplier: types.MultiplierName("large"), - timeElapsed: 86400, - expectedRewards: cs(c("hard", 21142771200), c("ukava", 21142771200)), // 10571385600 (deposit reward) + 10571385600 (borrow reward) - expectedPeriods: vesting.Periods{vesting.Period{Length: 32918400, Amount: cs(c("hard", 21142771200), c("ukava", 21142771200))}}, - isPeriodicVestingAccount: true, + deposit: cs(c("bnb", 10000000000)), + borrow: cs(c("bnb", 5000000000)), + rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), + multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, + multiplier: types.MultiplierName("large"), + timeElapsed: 86400, + expectedRewards: cs(c("hard", 21142771202), c("ukava", 21142771202)), + expectedPeriods: vesting.Periods{vesting.Period{Length: 32918400, Amount: cs(c("hard", 21142771202), c("ukava", 21142771202))}}, }, errArgs{ expectPass: true, @@ -683,16 +608,14 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() { { "multiple reward denoms: valid 10 days", args{ - deposit: cs(c("bnb", 10000000000)), - borrow: cs(c("bnb", 5000000000)), - rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - multiplier: types.MultiplierName("large"), - timeElapsed: 864000, - expectedRewards: cs(c("hard", 211427712000), c("ukava", 211427712000)), // 105713856000 (deposit reward) + 105713856000 (borrow reward) - expectedPeriods: vesting.Periods{vesting.Period{Length: 32140800, Amount: cs(c("hard", 211427712000), c("ukava", 211427712000))}}, - isPeriodicVestingAccount: true, + deposit: cs(c("bnb", 10000000000)), + borrow: cs(c("bnb", 5000000000)), + rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), + multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, + multiplier: types.MultiplierName("large"), + timeElapsed: 864000, + expectedRewards: cs(c("hard", 211427712008), c("ukava", 211427712008)), + expectedPeriods: vesting.Periods{vesting.Period{Length: 32140800, Amount: cs(c("hard", 211427712008), c("ukava", 211427712008))}}, }, errArgs{ expectPass: true, @@ -702,16 +625,14 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() { { "multiple reward denoms with different rewards per second: valid 1 day", args{ - deposit: cs(c("bnb", 10000000000)), - borrow: cs(c("bnb", 5000000000)), - rewardsPerSecond: cs(c("hard", 122354), c("ukava", 222222)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - multiplier: types.MultiplierName("large"), - timeElapsed: 86400, - expectedRewards: cs(c("hard", 21142771200), c("ukava", 38399961600)), - expectedPeriods: vesting.Periods{vesting.Period{Length: 32918400, Amount: cs(c("hard", 21142771200), c("ukava", 38399961600))}}, - isPeriodicVestingAccount: true, + deposit: cs(c("bnb", 10000000000)), + borrow: cs(c("bnb", 5000000000)), + rewardsPerSecond: cs(c("hard", 122354), c("ukava", 222222)), + multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, + multiplier: types.MultiplierName("large"), + timeElapsed: 86400, + expectedRewards: cs(c("hard", 21142771202), c("ukava", 38399961603)), + expectedPeriods: vesting.Periods{vesting.Period{Length: 32918400, Amount: cs(c("hard", 21142771202), c("ukava", 38399961603))}}, }, errArgs{ expectPass: true, @@ -722,77 +643,39 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() { for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) - // setup kavadist state - sk := suite.app.GetSupplyKeeper() - err := sk.MintCoins(suite.ctx, kavadist.ModuleName, cs(c("hard", 1000000000000000000), c("ukava", 1000000000000000000))) + userAddr := suite.addrs[3] + + bacc := auth.NewBaseAccount(userAddr, cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15)), nil, 0, 0) + bva, err := vesting.NewBaseVestingAccount(bacc, cs(c("ukava", 400)), suite.genesisTime.Unix()+16) suite.Require().NoError(err) - - // Set up generic reward periods - var multiRewardPeriods types.MultiRewardPeriods - var rewardPeriods types.RewardPeriods - for _, coin := range tc.args.deposit { - if len(tc.args.rewardsPerSecond) > 0 { - rewardPeriod := types.NewRewardPeriod(true, coin.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[0]) - rewardPeriods = append(rewardPeriods, rewardPeriod) - } - multiRewardPeriod := types.NewMultiRewardPeriod(true, coin.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond) - multiRewardPeriods = append(multiRewardPeriods, multiRewardPeriod) - } - - // Set up generic reward periods - params := types.NewParams( - rewardPeriods, multiRewardPeriods, multiRewardPeriods, rewardPeriods, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, params) - - // Set each denom's previous accrual time and supply reward factor - if len(tc.args.rewardsPerSecond) > 0 { - for _, coin := range tc.args.deposit { - suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, coin.Denom, tc.args.initialTime) - var rewardIndexes types.RewardIndexes - for _, rewardCoin := range tc.args.rewardsPerSecond { - rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) - } - suite.keeper.SetHardSupplyRewardIndexes(suite.ctx, coin.Denom, rewardIndexes) - } - } - - // Set each denom's previous accrual time and borrow reward factor - if len(tc.args.rewardsPerSecond) > 0 { - for _, coin := range tc.args.borrow { - suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, coin.Denom, tc.args.initialTime) - var rewardIndexes types.RewardIndexes - for _, rewardCoin := range tc.args.rewardsPerSecond { - rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) - } - suite.keeper.SetHardBorrowRewardIndexes(suite.ctx, coin.Denom, rewardIndexes) - } - } - - // sets addrs[3] to be a validator vesting account - ak := suite.app.GetAccountKeeper() - acc := ak.GetAccount(suite.ctx, suite.addrs[3]) - bacc := auth.NewBaseAccount(acc.GetAddress(), acc.GetCoins(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence()) - bva, err2 := vesting.NewBaseVestingAccount(bacc, cs(c("ukava", 400)), suite.ctx.BlockTime().Unix()+16) - suite.Require().NoError(err2) periods := vesting.Periods{ vesting.Period{Length: int64(1), Amount: cs(c("ukava", 100))}, vesting.Period{Length: int64(2), Amount: cs(c("ukava", 100))}, vesting.Period{Length: int64(8), Amount: cs(c("ukava", 100))}, vesting.Period{Length: int64(5), Amount: cs(c("ukava", 100))}, } - vva := validatorvesting.NewValidatorVestingAccountRaw(bva, suite.ctx.BlockTime().Unix(), periods, sdk.ConsAddress{}, nil, 90) - ak.SetAccount(suite.ctx, vva) + vva := validatorvesting.NewValidatorVestingAccountRaw(bva, suite.genesisTime.Unix(), periods, sdk.ConsAddress{}, nil, 90) + authBulder := app.NewAuthGenesisBuilder(). + WithAccounts(vva). + WithSimpleAccount(suite.addrs[2], cs()). + WithSimpleModuleAccount(kavadist.ModuleName, cs(c("hard", 1000000000000000000), c("ukava", 1000000000000000000))) + + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithMultipliers(tc.args.multipliers) + for _, c := range tc.args.deposit { + incentBuilder = incentBuilder.WithSimpleSupplyRewardPeriod(c.Denom, tc.args.rewardsPerSecond) + } + for _, c := range tc.args.borrow { + incentBuilder = incentBuilder.WithSimpleBorrowRewardPeriod(c.Denom, tc.args.rewardsPerSecond) + } + + suite.SetupWithGenState(authBulder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) + + ak := suite.app.GetAccountKeeper() hardKeeper := suite.app.GetHardKeeper() - userAddr := suite.addrs[3] // User deposits and borrows err = hardKeeper.Deposit(suite.ctx, userAddr, tc.args.deposit) @@ -801,7 +684,7 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() { suite.Require().NoError(err) // Check that Hard hooks initialized a HardLiquidityProviderClaim that has 0 rewards - claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) + claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, userAddr) suite.Require().True(found) for _, coin := range tc.args.deposit { suite.Require().Equal(sdk.ZeroInt(), claim.Reward.AmountOf(coin.Denom)) @@ -831,19 +714,19 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() { } // Sync hard supply rewards - deposit, found := suite.hardKeeper.GetDeposit(suite.ctx, suite.addrs[3]) + deposit, found := suite.hardKeeper.GetDeposit(suite.ctx, userAddr) suite.Require().True(found) suite.keeper.SynchronizeHardSupplyReward(suite.ctx, deposit) // Sync hard borrow rewards - borrow, found := suite.hardKeeper.GetBorrow(suite.ctx, suite.addrs[3]) + borrow, found := suite.hardKeeper.GetBorrow(suite.ctx, userAddr) suite.Require().True(found) suite.keeper.SynchronizeHardBorrowReward(suite.ctx, borrow) // Fetch pre-claim balances preClaimAcc := ak.GetAccount(runCtx, suite.addrs[2]) - err = suite.keeper.ClaimHardRewardVVesting(runCtx, suite.addrs[3], suite.addrs[2], tc.args.multiplier) + err = suite.keeper.ClaimHardRewardVVesting(runCtx, userAddr, suite.addrs[2], tc.args.multiplier) if tc.errArgs.expectPass { suite.Require().NoError(err) @@ -851,11 +734,9 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() { postClaimAcc := ak.GetAccount(suite.ctx, suite.addrs[2]) suite.Require().Equal(preClaimAcc.GetCoins().Add(tc.args.expectedRewards...), postClaimAcc.GetCoins()) - if tc.args.isPeriodicVestingAccount { - vacc, ok := postClaimAcc.(*vesting.PeriodicVestingAccount) - suite.Require().True(ok) - suite.Require().Equal(tc.args.expectedPeriods, vacc.VestingPeriods) - } + vacc, ok := postClaimAcc.(*vesting.PeriodicVestingAccount) + suite.Require().True(ok) + suite.Require().Equal(tc.args.expectedPeriods, vacc.VestingPeriods) // Check that each claim reward coin's amount has been reset to 0 claim, found := suite.keeper.GetHardLiquidityProviderClaim(runCtx, suite.addrs[3]) @@ -871,7 +752,7 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() { } } -func (suite *KeeperTestSuite) TestSendCoinsToPeriodicVestingAccount() { +func (suite *PayoutTestSuite) TestSendCoinsToPeriodicVestingAccount() { type accountArgs struct { periods vesting.Periods origVestingCoins sdk.Coins @@ -1111,29 +992,31 @@ func (suite *KeeperTestSuite) TestSendCoinsToPeriodicVestingAccount() { } for _, tc := range tests { suite.Run(tc.name, func() { - // create the periodic vesting account - pva, err := createPeriodicVestingAccount(tc.args.accArgs.origVestingCoins, tc.args.accArgs.periods, tc.args.accArgs.startTime, tc.args.accArgs.endTime) - suite.Require().NoError(err) - - // setup store state with account and kavadist module account - suite.ctx = suite.ctx.WithBlockTime(tc.args.ctxTime) - ak := suite.app.GetAccountKeeper() - ak.SetAccount(suite.ctx, pva) - // mint module account coins if required + authBuilder := app.NewAuthGenesisBuilder().WithSimplePeriodicVestingAccount( + suite.addrs[0], + tc.args.accArgs.origVestingCoins, + tc.args.accArgs.periods, + tc.args.accArgs.startTime, + ) if tc.args.mintModAccountCoins { - sk := suite.app.GetSupplyKeeper() - err = sk.MintCoins(suite.ctx, kavadist.ModuleName, tc.args.period.Amount) - suite.Require().NoError(err) + authBuilder = authBuilder.WithSimpleModuleAccount(kavadist.ModuleName, tc.args.period.Amount) } - err = suite.keeper.SendTimeLockedCoinsToPeriodicVestingAccount(suite.ctx, kavadist.ModuleName, pva.Address, tc.args.period.Amount, tc.args.period.Length) + suite.genesisTime = tc.args.ctxTime + suite.SetupApp() + suite.app.InitializeFromGenesisStates( + authBuilder.BuildMarshalled(), + ) + + err := suite.keeper.SendTimeLockedCoinsToPeriodicVestingAccount(suite.ctx, kavadist.ModuleName, suite.addrs[0], tc.args.period.Amount, tc.args.period.Length) + if tc.errArgs.expectErr { suite.Require().Error(err) suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains)) } else { suite.Require().NoError(err) - acc := suite.getAccount(pva.Address) + acc := suite.getAccount(suite.addrs[0]) vacc, ok := acc.(*vesting.PeriodicVestingAccount) suite.Require().True(ok) suite.Require().Equal(tc.args.expectedPeriods, vacc.VestingPeriods) @@ -1144,8 +1027,17 @@ func (suite *KeeperTestSuite) TestSendCoinsToPeriodicVestingAccount() { } } -func (suite *KeeperTestSuite) TestSendCoinsToBaseAccount() { - suite.SetupWithAccountState() +func (suite *PayoutTestSuite) TestSendCoinsToBaseAccount() { + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(suite.addrs[1], cs(c("ukava", 400))). + WithSimpleModuleAccount(kavadist.ModuleName, cs(c("ukava", 600))) + + suite.genesisTime = time.Unix(100, 0) + suite.SetupApp() + suite.app.InitializeFromGenesisStates( + authBuilder.BuildMarshalled(), + ) + // send coins to base account err := suite.keeper.SendTimeLockedCoinsToAccount(suite.ctx, kavadist.ModuleName, suite.addrs[1], cs(c("ukava", 100)), 5) suite.Require().NoError(err) @@ -1163,8 +1055,15 @@ func (suite *KeeperTestSuite) TestSendCoinsToBaseAccount() { } -func (suite *KeeperTestSuite) TestSendCoinsToInvalidAccount() { - suite.SetupWithAccountState() +func (suite *PayoutTestSuite) TestSendCoinsToInvalidAccount() { + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleModuleAccount(kavadist.ModuleName, cs(c("ukava", 600))). + WithEmptyValidatorVestingAccount(suite.addrs[2]) + + suite.SetupApp() + suite.app.InitializeFromGenesisStates( + authBuilder.BuildMarshalled(), + ) err := suite.keeper.SendTimeLockedCoinsToAccount(suite.ctx, kavadist.ModuleName, suite.addrs[2], cs(c("ukava", 100)), 5) suite.Require().True(errors.Is(err, types.ErrInvalidAccountType)) macc := suite.getModuleAccount(cdptypes.ModuleName) @@ -1172,56 +1071,7 @@ func (suite *KeeperTestSuite) TestSendCoinsToInvalidAccount() { suite.Require().True(errors.Is(err, types.ErrInvalidAccountType)) } -func (suite *KeeperTestSuite) SetupWithAccountState() { - // creates a new app state with 4 funded addresses and 1 module account - tApp := app.NewTestApp() - ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: time.Unix(100, 0)}) - _, addrs := app.GeneratePrivKeyAddressPairs(4) - authGS := app.NewAuthGenState( - addrs, - []sdk.Coins{ - cs(c("ukava", 400)), - cs(c("ukava", 400)), - cs(c("ukava", 400)), - cs(c("ukava", 400)), - }) - tApp.InitializeFromGenesisStates( - authGS, - ) - supplyKeeper := tApp.GetSupplyKeeper() - macc := supplyKeeper.GetModuleAccount(ctx, kavadist.ModuleName) - err := supplyKeeper.MintCoins(ctx, macc.GetName(), cs(c("ukava", 600))) - suite.Require().NoError(err) - - // sets addrs[0] to be a periodic vesting account - ak := tApp.GetAccountKeeper() - acc := ak.GetAccount(ctx, addrs[0]) - bacc := auth.NewBaseAccount(acc.GetAddress(), acc.GetCoins(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence()) - periods := vesting.Periods{ - vesting.Period{Length: int64(1), Amount: cs(c("ukava", 100))}, - vesting.Period{Length: int64(2), Amount: cs(c("ukava", 100))}, - vesting.Period{Length: int64(8), Amount: cs(c("ukava", 100))}, - vesting.Period{Length: int64(5), Amount: cs(c("ukava", 100))}, - } - bva, err2 := vesting.NewBaseVestingAccount(bacc, cs(c("ukava", 400)), ctx.BlockTime().Unix()+16) - suite.Require().NoError(err2) - pva := vesting.NewPeriodicVestingAccountRaw(bva, ctx.BlockTime().Unix(), periods) - ak.SetAccount(ctx, pva) - - // sets addrs[2] to be a validator vesting account - acc = ak.GetAccount(ctx, addrs[2]) - bacc = auth.NewBaseAccount(acc.GetAddress(), acc.GetCoins(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence()) - bva, err2 = vesting.NewBaseVestingAccount(bacc, cs(c("ukava", 400)), ctx.BlockTime().Unix()+16) - suite.Require().NoError(err2) - vva := validatorvesting.NewValidatorVestingAccountRaw(bva, ctx.BlockTime().Unix(), periods, sdk.ConsAddress{}, nil, 90) - ak.SetAccount(ctx, vva) - suite.app = tApp - suite.keeper = tApp.GetIncentiveKeeper() - suite.ctx = ctx - suite.addrs = addrs -} - -func (suite *KeeperTestSuite) TestGetPeriodLength() { +func (suite *PayoutTestSuite) TestGetPeriodLength() { type args struct { blockTime time.Time multiplier types.Multiplier @@ -1348,8 +1198,10 @@ func (suite *KeeperTestSuite) TestGetPeriodLength() { } for _, tc := range testCases { suite.Run(tc.name, func() { - ctx := suite.ctx.WithBlockTime(tc.args.blockTime) - length, err := suite.keeper.GetPeriodLength(ctx, tc.args.multiplier) + suite.genesisTime = tc.args.blockTime + suite.SetupApp() + + length, err := suite.keeper.GetPeriodLength(suite.ctx, tc.args.multiplier) if tc.errArgs.expectPass { suite.Require().NoError(err) suite.Require().Equal(tc.args.expectedLength, length) @@ -1359,3 +1211,7 @@ func (suite *KeeperTestSuite) TestGetPeriodLength() { }) } } + +func TestPayoutTestSuite(t *testing.T) { + suite.Run(t, new(PayoutTestSuite)) +} diff --git a/x/incentive/keeper/rewards_borrow_test.go b/x/incentive/keeper/rewards_borrow_test.go index e5f643b4..b6d22c30 100644 --- a/x/incentive/keeper/rewards_borrow_test.go +++ b/x/incentive/keeper/rewards_borrow_test.go @@ -1,23 +1,75 @@ package keeper_test import ( + "testing" "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" + "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" + "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/x/committee" + committeekeeper "github.com/kava-labs/kava/x/committee/keeper" "github.com/kava-labs/kava/x/hard" - hardtypes "github.com/kava-labs/kava/x/hard/types" + hardkeeper "github.com/kava-labs/kava/x/hard/keeper" + "github.com/kava-labs/kava/x/incentive/keeper" "github.com/kava-labs/kava/x/incentive/types" ) -func (suite *KeeperTestSuite) TestAccumulateHardBorrowRewards() { +// Test suite used for all keeper tests +type BorrowRewardsTestSuite struct { + suite.Suite + + keeper keeper.Keeper + hardKeeper hardkeeper.Keeper + committeeKeeper committeekeeper.Keeper + + app app.TestApp + ctx sdk.Context + + genesisTime time.Time + addrs []sdk.AccAddress +} + +// SetupTest is run automatically before each suite test +func (suite *BorrowRewardsTestSuite) SetupTest() { + config := sdk.GetConfig() + app.SetBech32AddressPrefixes(config) + + _, suite.addrs = app.GeneratePrivKeyAddressPairs(5) + + suite.genesisTime = time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC) +} + +func (suite *BorrowRewardsTestSuite) SetupApp() { + suite.app = app.NewTestApp() + + suite.keeper = suite.app.GetIncentiveKeeper() + suite.hardKeeper = suite.app.GetHardKeeper() + suite.committeeKeeper = suite.app.GetCommitteeKeeper() + + suite.ctx = suite.app.NewContext(true, abci.Header{Height: 1, Time: suite.genesisTime}) +} + +func (suite *BorrowRewardsTestSuite) SetupWithGenState(authBuilder app.AuthGenesisBuilder, incentBuilder IncentiveGenesisBuilder, hardBuilder HardGenesisBuilder) { + suite.SetupApp() + + suite.app.InitializeFromGenesisStatesWithTime( + suite.genesisTime, + authBuilder.BuildMarshalled(), + NewPricefeedGenStateMultiFromTime(suite.genesisTime), + hardBuilder.BuildMarshalled(), + NewCommitteeGenesisState(suite.addrs[:2]), // TODO add committee members to suite, + incentBuilder.BuildMarshalled(), + ) +} + +func (suite *BorrowRewardsTestSuite) TestAccumulateHardBorrowRewards() { type args struct { borrow sdk.Coin rewardsPerSecond sdk.Coins - initialTime time.Time timeElapsed int expectedRewardIndexes types.RewardIndexes } @@ -31,7 +83,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardBorrowRewards() { args{ borrow: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 7, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("0.000000856478000001"))}, }, @@ -41,7 +92,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardBorrowRewards() { args{ borrow: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 86400, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("0.010571385600010177"))}, }, @@ -51,7 +101,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardBorrowRewards() { args{ borrow: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 0, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("0.0"))}, }, @@ -61,7 +110,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardBorrowRewards() { args{ borrow: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 7, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("0.000000856478000001")), @@ -74,7 +122,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardBorrowRewards() { args{ borrow: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 86400, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("0.010571385600010177")), @@ -87,7 +134,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardBorrowRewards() { args{ borrow: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 0, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("0.0")), @@ -100,7 +146,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardBorrowRewards() { args{ borrow: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 555555)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 86400, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("0.010571385600010177")), @@ -111,43 +156,22 @@ func (suite *KeeperTestSuite) TestAccumulateHardBorrowRewards() { } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) - - // Mint coins to hard module account - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000))) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) - - // setup incentive state - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[0])}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[0])}, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), + userAddr := suite.addrs[3] + authBuilder := app.NewAuthGenesisBuilder().WithSimpleAccount( + userAddr, + cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15)), ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, tc.args.borrow.Denom, tc.args.initialTime) - var rewardIndexes types.RewardIndexes - for _, rewardCoin := range tc.args.rewardsPerSecond { - rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) - } - suite.keeper.SetHardBorrowRewardIndexes(suite.ctx, tc.args.borrow.Denom, rewardIndexes) - // Set up hard state (interest factor for the relevant denom) - suite.hardKeeper.SetSupplyInterestFactor(suite.ctx, tc.args.borrow.Denom, sdk.MustNewDecFromStr("1.0")) - suite.hardKeeper.SetBorrowInterestFactor(suite.ctx, tc.args.borrow.Denom, sdk.MustNewDecFromStr("1.0")) - suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.borrow.Denom, tc.args.initialTime) + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleBorrowRewardPeriod(tc.args.borrow.Denom, tc.args.rewardsPerSecond) + + suite.SetupWithGenState(authBuilder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) // User deposits and borrows to increase total borrowed amount - hardKeeper := suite.app.GetHardKeeper() - userAddr := suite.addrs[3] - err := hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(sdk.NewCoin(tc.args.borrow.Denom, tc.args.borrow.Amount.Mul(sdk.NewInt(2))))) + err := suite.hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(sdk.NewCoin(tc.args.borrow.Denom, tc.args.borrow.Amount.Mul(sdk.NewInt(2))))) suite.Require().NoError(err) - err = hardKeeper.Borrow(suite.ctx, userAddr, sdk.NewCoins(tc.args.borrow)) + err = suite.hardKeeper.Borrow(suite.ctx, userAddr, sdk.NewCoins(tc.args.borrow)) suite.Require().NoError(err) // Set up chain context at future time @@ -175,13 +199,12 @@ func (suite *KeeperTestSuite) TestAccumulateHardBorrowRewards() { } } -func (suite *KeeperTestSuite) TestInitializeHardBorrowRewards() { +func (suite *BorrowRewardsTestSuite) TestInitializeHardBorrowRewards() { type args struct { - moneyMarketRewardDenoms map[string][]string + moneyMarketRewardDenoms map[string]sdk.Coins deposit sdk.Coins borrow sdk.Coins - initialTime time.Time expectedClaimBorrowRewardIndexes types.MultiRewardIndexes } type test struct { @@ -189,10 +212,9 @@ func (suite *KeeperTestSuite) TestInitializeHardBorrowRewards() { args args } - standardMoneyMarketRewardDenoms := map[string][]string{ - "bnb": {"hard"}, - "btcb": {"hard", "ukava"}, - "xrp": {}, + standardMoneyMarketRewardDenoms := map[string]sdk.Coins{ + "bnb": cs(c("hard", 1)), + "btcb": cs(c("hard", 1), c("ukava", 1)), } testCases := []test{ @@ -202,7 +224,6 @@ func (suite *KeeperTestSuite) TestInitializeHardBorrowRewards() { moneyMarketRewardDenoms: standardMoneyMarketRewardDenoms, deposit: cs(c("bnb", 1000000000000)), borrow: cs(c("bnb", 100000000000)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedClaimBorrowRewardIndexes: types.MultiRewardIndexes{ types.NewMultiRewardIndex( "bnb", @@ -219,7 +240,6 @@ func (suite *KeeperTestSuite) TestInitializeHardBorrowRewards() { moneyMarketRewardDenoms: standardMoneyMarketRewardDenoms, deposit: cs(c("btcb", 1000000000000)), borrow: cs(c("btcb", 100000000000)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedClaimBorrowRewardIndexes: types.MultiRewardIndexes{ types.NewMultiRewardIndex( "btcb", @@ -237,7 +257,6 @@ func (suite *KeeperTestSuite) TestInitializeHardBorrowRewards() { moneyMarketRewardDenoms: standardMoneyMarketRewardDenoms, deposit: cs(c("xrp", 1000000000000)), borrow: cs(c("xrp", 100000000000)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedClaimBorrowRewardIndexes: types.MultiRewardIndexes{ types.NewMultiRewardIndex( "xrp", @@ -252,7 +271,6 @@ func (suite *KeeperTestSuite) TestInitializeHardBorrowRewards() { moneyMarketRewardDenoms: standardMoneyMarketRewardDenoms, deposit: cs(c("bnb", 1000000000000), c("btcb", 1000000000000)), borrow: cs(c("bnb", 100000000000), c("btcb", 100000000000)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedClaimBorrowRewardIndexes: types.MultiRewardIndexes{ types.NewMultiRewardIndex( "bnb", @@ -276,7 +294,6 @@ func (suite *KeeperTestSuite) TestInitializeHardBorrowRewards() { moneyMarketRewardDenoms: standardMoneyMarketRewardDenoms, deposit: cs(c("bnb", 1000000000000), c("xrp", 1000000000000)), borrow: cs(c("bnb", 100000000000), c("xrp", 100000000000)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedClaimBorrowRewardIndexes: types.MultiRewardIndexes{ types.NewMultiRewardIndex( "bnb", @@ -294,64 +311,24 @@ func (suite *KeeperTestSuite) TestInitializeHardBorrowRewards() { } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) - - // Mint coins to hard module account - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000))) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) - userAddr := suite.addrs[3] - - // Prepare money market + reward params - i := 0 - var multiRewardPeriods types.MultiRewardPeriods - var rewardPeriods types.RewardPeriods - for moneyMarketDenom, rewardDenoms := range tc.args.moneyMarketRewardDenoms { - // Set up multi reward periods for supply/borrow indexes with dynamic money market denoms/reward denoms - var rewardsPerSecond sdk.Coins - for _, rewardDenom := range rewardDenoms { - rewardsPerSecond = append(rewardsPerSecond, sdk.NewCoin(rewardDenom, sdk.OneInt())) - } - multiRewardPeriod := types.NewMultiRewardPeriod(true, moneyMarketDenom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), rewardsPerSecond) - multiRewardPeriods = append(multiRewardPeriods, multiRewardPeriod) - - // Set up generic reward periods for usdx minting/delegator indexes - if i == 0 && len(rewardDenoms) > 0 { - rewardPeriod := types.NewRewardPeriod(true, moneyMarketDenom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), rewardsPerSecond[i]) - rewardPeriods = append(rewardPeriods, rewardPeriod) - i++ - } - } - - // Initialize and set incentive params - params := types.NewParams( - rewardPeriods, multiRewardPeriods, multiRewardPeriods, rewardPeriods, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), + authBuilder := app.NewAuthGenesisBuilder().WithSimpleAccount( + userAddr, + cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15)), ) - suite.keeper.SetParams(suite.ctx, params) - // Set each money market's previous accrual time and supply reward indexes - for moneyMarketDenom, rewardDenoms := range tc.args.moneyMarketRewardDenoms { - var rewardIndexes types.RewardIndexes - for _, rewardDenom := range rewardDenoms { - rewardIndex := types.NewRewardIndex(rewardDenom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) - } - suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, moneyMarketDenom, tc.args.initialTime) - if len(rewardIndexes) > 0 { - suite.keeper.SetHardBorrowRewardIndexes(suite.ctx, moneyMarketDenom, rewardIndexes) - } + incentBuilder := NewIncentiveGenesisBuilder().WithGenesisTime(suite.genesisTime) + for moneyMarketDenom, rewardsPerSecond := range tc.args.moneyMarketRewardDenoms { + incentBuilder = incentBuilder.WithSimpleBorrowRewardPeriod(moneyMarketDenom, rewardsPerSecond) } - hardKeeper := suite.app.GetHardKeeper() + suite.SetupWithGenState(authBuilder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) + // User deposits - err := hardKeeper.Deposit(suite.ctx, userAddr, tc.args.deposit) + err := suite.hardKeeper.Deposit(suite.ctx, userAddr, tc.args.deposit) suite.Require().NoError(err) // User borrows - err = hardKeeper.Borrow(suite.ctx, userAddr, tc.args.borrow) + err = suite.hardKeeper.Borrow(suite.ctx, userAddr, tc.args.borrow) suite.Require().NoError(err) claim, foundClaim := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, userAddr) @@ -361,12 +338,11 @@ func (suite *KeeperTestSuite) TestInitializeHardBorrowRewards() { } } -func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { +func (suite *BorrowRewardsTestSuite) TestSynchronizeHardBorrowReward() { type args struct { incentiveBorrowRewardDenom string borrow sdk.Coin rewardsPerSecond sdk.Coins - initialTime time.Time blockTimes []int expectedRewardIndexes types.RewardIndexes expectedRewards sdk.Coins @@ -389,7 +365,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { incentiveBorrowRewardDenom: "bnb", borrow: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("0.001223540000173228"))}, expectedRewards: cs(c("hard", 12235400)), @@ -402,7 +377,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { incentiveBorrowRewardDenom: "bnb", borrow: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("10.571385603126235340"))}, expectedRewards: cs(c("hard", 105713856031)), @@ -414,7 +388,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { incentiveBorrowRewardDenom: "ukava", borrow: c("ukava", 1), // borrow a tiny amount so that rewards round to zero rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("0.122354003908172328"))}, expectedRewards: cs(), @@ -427,7 +400,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { incentiveBorrowRewardDenom: "bnb", borrow: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("0.001223540000173228")), @@ -442,7 +414,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { incentiveBorrowRewardDenom: "bnb", borrow: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("10.571385603126235340")), @@ -457,7 +428,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { incentiveBorrowRewardDenom: "bnb", borrow: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 555555)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("0.001223540000173228")), @@ -466,33 +436,12 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { expectedRewards: cs(c("hard", 12235400), c("ukava", 55555500)), }, }, - { - "denom is in incentive's hard borrow reward params but it has no rewards; add reward", - args{ - incentiveBorrowRewardDenom: "bnb", - borrow: c("bnb", 10000000000), - rewardsPerSecond: sdk.Coins{}, - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - blockTimes: []int{100}, - expectedRewardIndexes: types.RewardIndexes{}, - expectedRewards: sdk.Coins{}, - updateRewardsViaCommmittee: true, - updatedBaseDenom: "bnb", - updatedRewardsPerSecond: cs(c("hard", 100000)), - updatedExpectedRewards: cs(c("hard", 8640000000)), - updatedExpectedRewardIndexes: types.RewardIndexes{ - types.NewRewardIndex("hard", d("0.864000000049803065")), - }, - updatedTimeDuration: 86400, - }, - }, { "denom is in incentive's hard borrow reward params and has rewards; add new reward type", args{ incentiveBorrowRewardDenom: "bnb", borrow: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{86400}, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("1.057138560060101160")), @@ -514,8 +463,7 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { args{ incentiveBorrowRewardDenom: "bnb", borrow: c("zzz", 10000000000), - rewardsPerSecond: sdk.Coins{}, - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + rewardsPerSecond: nil, blockTimes: []int{100}, expectedRewardIndexes: types.RewardIndexes{}, expectedRewards: sdk.Coins{}, @@ -529,35 +477,12 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { updatedTimeDuration: 86400, }, }, - { - "denom incentive's hard borrow reward params but it has no rewards; add multiple reward types", - args{ - incentiveBorrowRewardDenom: "bnb", - borrow: c("bnb", 10000000000), - rewardsPerSecond: sdk.Coins{}, - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - blockTimes: []int{100}, - expectedRewardIndexes: types.RewardIndexes{}, - expectedRewards: sdk.Coins{}, - updateRewardsViaCommmittee: true, - updatedBaseDenom: "bnb", - updatedRewardsPerSecond: cs(c("hard", 100000), c("ukava", 100500), c("swap", 500)), - updatedExpectedRewards: cs(c("hard", 8640000000), c("ukava", 8683200001), c("swap", 43200000)), - updatedExpectedRewardIndexes: types.RewardIndexes{ - types.NewRewardIndex("hard", d("0.864000000049803065")), - types.NewRewardIndex("ukava", d("0.868320000050052081")), - types.NewRewardIndex("swap", d("0.004320000000249015")), - }, - updatedTimeDuration: 86400, - }, - }, { "denom is in hard's money market params but not in incentive's hard supply reward params; add multiple reward types", args{ incentiveBorrowRewardDenom: "bnb", borrow: c("zzz", 10000000000), - rewardsPerSecond: sdk.Coins{}, - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + rewardsPerSecond: nil, blockTimes: []int{100}, expectedRewardIndexes: types.RewardIndexes{}, expectedRewards: sdk.Coins{}, @@ -573,45 +498,23 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { updatedTimeDuration: 86400, }, }, + // TODO test synchronize when there is a reward period with 0 rewardsPerSecond } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + userAddr := suite.addrs[3] + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(suite.addrs[2], cs(c("ukava", 1e9))). + WithSimpleAccount(userAddr, cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15))) - // Mint coins to hard module account - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000))) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) - - // Set up incentive state - incentiveParams := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.incentiveBorrowRewardDenom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), c("hard", 1))}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.incentiveBorrowRewardDenom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), sdk.Coins{})}, // Don't set any supply rewards for easier accounting - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.incentiveBorrowRewardDenom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.incentiveBorrowRewardDenom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), c("hard", 1))}, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, incentiveParams) - suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, tc.args.incentiveBorrowRewardDenom, tc.args.initialTime) - var rewardIndexes types.RewardIndexes - for _, rewardCoin := range tc.args.rewardsPerSecond { - rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) + incentBuilder := NewIncentiveGenesisBuilder().WithGenesisTime(suite.genesisTime) + if tc.args.rewardsPerSecond != nil { + incentBuilder = incentBuilder.WithSimpleBorrowRewardPeriod(tc.args.incentiveBorrowRewardDenom, tc.args.rewardsPerSecond) } - if len(rewardIndexes) > 0 { - suite.keeper.SetHardBorrowRewardIndexes(suite.ctx, tc.args.incentiveBorrowRewardDenom, rewardIndexes) - } - - // Set up hard state (interest factor for the relevant denom) - suite.hardKeeper.SetSupplyInterestFactor(suite.ctx, tc.args.borrow.Denom, sdk.MustNewDecFromStr("1.0")) - suite.hardKeeper.SetBorrowInterestFactor(suite.ctx, tc.args.borrow.Denom, sdk.MustNewDecFromStr("1.0")) - suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.borrow.Denom, tc.args.initialTime) // Set the minimum borrow to 0 to allow testing small borrows - hardParams := suite.hardKeeper.GetParams(suite.ctx) - hardParams.MinimumBorrowUSDValue = sdk.ZeroDec() - suite.hardKeeper.SetParams(suite.ctx, hardParams) + hardBuilder := NewHardGenStateMulti(suite.genesisTime).WithMinBorrow(sdk.ZeroDec()) + + suite.SetupWithGenState(authBuilder, incentBuilder, hardBuilder) // Borrow a fixed amount from another user to dilute primary user's rewards per second. suite.Require().NoError( @@ -622,11 +525,9 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { ) // User deposits and borrows to increase total borrowed amount - hardKeeper := suite.app.GetHardKeeper() - userAddr := suite.addrs[3] - err := hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(sdk.NewCoin(tc.args.borrow.Denom, tc.args.borrow.Amount.Mul(sdk.NewInt(2))))) + err := suite.hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(sdk.NewCoin(tc.args.borrow.Denom, tc.args.borrow.Amount.Mul(sdk.NewInt(2))))) suite.Require().NoError(err) - err = hardKeeper.Borrow(suite.ctx, userAddr, sdk.NewCoins(tc.args.borrow)) + err = suite.hardKeeper.Borrow(suite.ctx, userAddr, sdk.NewCoins(tc.args.borrow)) suite.Require().NoError(err) // Check that Hard hooks initialized a HardLiquidityProviderClaim @@ -662,7 +563,7 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) // After we've accumulated, run synchronize - borrow, found := hardKeeper.GetBorrow(suite.ctx, userAddr) + borrow, found := suite.hardKeeper.GetBorrow(suite.ctx, userAddr) suite.Require().True(found) suite.Require().NotPanics(func() { suite.keeper.SynchronizeHardBorrowReward(suite.ctx, borrow) @@ -714,7 +615,7 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { // Borrow denom's reward period does not exist _, found := currIncentiveHardBorrowRewardPeriods.GetMultiRewardPeriodIndex(tc.args.borrow.Denom) suite.Require().False(found) - newMultiRewardPeriod := types.NewMultiRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.updatedRewardsPerSecond) + newMultiRewardPeriod := types.NewMultiRewardPeriod(true, tc.args.borrow.Denom, suite.genesisTime, suite.genesisTime.Add(time.Hour*24*365*4), tc.args.updatedRewardsPerSecond) currIncentiveHardBorrowRewardPeriods = append(currIncentiveHardBorrowRewardPeriods, newMultiRewardPeriod) } @@ -742,7 +643,9 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { // 5. Committee votes and passes proposal err = suite.committeeKeeper.AddVote(suite.ctx, proposalID, committeeMemberOne, committee.Yes) + suite.Require().NoError(err) err = suite.committeeKeeper.AddVote(suite.ctx, proposalID, committeeMemberTwo, committee.Yes) + suite.Require().NoError(err) // 6. Check proposal passed com, found := suite.committeeKeeper.GetCommittee(suite.ctx, 1) @@ -774,7 +677,7 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { suite.Require().NoError(err) // After we've accumulated, run synchronize - borrow, found = hardKeeper.GetBorrow(suite.ctx, userAddr) + borrow, found = suite.hardKeeper.GetBorrow(suite.ctx, userAddr) suite.Require().True(found) suite.Require().NotPanics(func() { suite.keeper.SynchronizeHardBorrowReward(suite.ctx, borrow) @@ -808,7 +711,7 @@ func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { } } -func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { +func (suite *BorrowRewardsTestSuite) TestUpdateHardBorrowIndexDenoms() { type withdrawModification struct { coins sdk.Coins repay bool @@ -819,7 +722,6 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { firstBorrow sdk.Coins modification withdrawModification rewardsPerSecond sdk.Coins - initialTime time.Time expectedBorrowIndexDenoms []string } type test struct { @@ -835,7 +737,6 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { firstBorrow: cs(c("bnb", 50000000)), modification: withdrawModification{coins: cs(c("ukava", 500000000))}, rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedBorrowIndexDenoms: []string{"bnb", "ukava"}, }, }, @@ -846,7 +747,6 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { firstBorrow: cs(c("btcb", 50000000)), modification: withdrawModification{coins: cs(c("ukava", 500000000), c("bnb", 50000000000), c("xrp", 50000000000))}, rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedBorrowIndexDenoms: []string{"btcb", "ukava", "bnb", "xrp"}, }, }, @@ -857,7 +757,6 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { firstBorrow: cs(c("bnb", 50000000)), modification: withdrawModification{coins: cs(c("bnb", 50000000000))}, rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedBorrowIndexDenoms: []string{"bnb"}, }, }, @@ -868,7 +767,6 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { firstBorrow: cs(c("bnb", 50000000)), modification: withdrawModification{coins: cs(c("ukava", 500000000))}, rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedBorrowIndexDenoms: []string{"bnb", "ukava"}, }, }, @@ -879,7 +777,6 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { firstBorrow: cs(c("btcb", 50000000)), modification: withdrawModification{coins: cs(c("ukava", 500000000), c("bnb", 50000000000), c("xrp", 50000000000))}, rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedBorrowIndexDenoms: []string{"btcb", "ukava", "bnb", "xrp"}, }, }, @@ -890,7 +787,6 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { firstBorrow: cs(c("bnb", 50000000)), modification: withdrawModification{coins: cs(c("bnb", 50000000000))}, rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedBorrowIndexDenoms: []string{"bnb"}, }, }, @@ -901,7 +797,6 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { firstBorrow: cs(c("bnb", 100000000)), modification: withdrawModification{coins: cs(c("bnb", 1100000000)), repay: true}, rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedBorrowIndexDenoms: []string{}, }, }, @@ -912,7 +807,6 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { firstBorrow: cs(c("bnb", 100000000), c("ukava", 10000000)), modification: withdrawModification{coins: cs(c("bnb", 1100000000)), repay: true}, rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedBorrowIndexDenoms: []string{"ukava"}, }, }, @@ -923,70 +817,51 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { firstBorrow: cs(c("bnb", 100000000), c("ukava", 10000000)), modification: withdrawModification{coins: cs(c("bnb", 1100000000)), repay: true}, rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedBorrowIndexDenoms: []string{"ukava"}, }, }, } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + userAddr := suite.addrs[3] + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleAccount( + userAddr, + cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15)), + ). + WithSimpleAccount( + suite.addrs[0], + cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15)), + ) - // Mint coins to hard module account so it can service borrow requests - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := tc.args.firstBorrow.Add(tc.args.modification.coins...) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleBorrowRewardPeriod("bnb", tc.args.rewardsPerSecond). + WithSimpleBorrowRewardPeriod("ukava", tc.args.rewardsPerSecond). + WithSimpleBorrowRewardPeriod("btcb", tc.args.rewardsPerSecond). + WithSimpleBorrowRewardPeriod("xrp", tc.args.rewardsPerSecond) - // Set up generic reward periods - var multiRewardPeriods types.MultiRewardPeriods - var rewardPeriods types.RewardPeriods - for i, denom := range tc.args.expectedBorrowIndexDenoms { - // Create just one reward period for USDX Minting / Hard Delegator reward periods (otherwise params will panic on duplicate) - if i == 0 { - rewardPeriod := types.NewRewardPeriod(true, denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[i]) - rewardPeriods = append(rewardPeriods, rewardPeriod) - } - multiRewardPeriod := types.NewMultiRewardPeriod(true, denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond) - multiRewardPeriods = append(multiRewardPeriods, multiRewardPeriod) - } + suite.SetupWithGenState(authBuilder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) - // Setup incentive state - params := types.NewParams( - rewardPeriods, multiRewardPeriods, multiRewardPeriods, rewardPeriods, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, params) - - // Set each expected borrow denom's previous accrual time and borrow reward factor - var rewardIndexes types.RewardIndexes - for _, rewardCoin := range tc.args.rewardsPerSecond { - rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) - } - for _, denom := range tc.args.expectedBorrowIndexDenoms { - suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, denom, tc.args.initialTime) - suite.keeper.SetHardBorrowRewardIndexes(suite.ctx, denom, rewardIndexes) - } + // Fill the hard supply to allow user to borrow + err := suite.hardKeeper.Deposit(suite.ctx, suite.addrs[0], tc.args.firstBorrow.Add(tc.args.modification.coins...)) + suite.Require().NoError(err) // User deposits initial funds (so that user can borrow) - hardKeeper := suite.app.GetHardKeeper() - userAddr := suite.addrs[3] - err := hardKeeper.Deposit(suite.ctx, userAddr, tc.args.initialDeposit) + err = suite.hardKeeper.Deposit(suite.ctx, userAddr, tc.args.initialDeposit) suite.Require().NoError(err) // Confirm that claim exists but no borrow reward indexes have been added - claimAfterDeposit, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) + claimAfterDeposit, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, userAddr) suite.Require().True(found) suite.Require().Equal(0, len(claimAfterDeposit.BorrowRewardIndexes)) // User borrows (first time) - err = hardKeeper.Borrow(suite.ctx, userAddr, tc.args.firstBorrow) + err = suite.hardKeeper.Borrow(suite.ctx, userAddr, tc.args.firstBorrow) suite.Require().NoError(err) // Confirm that claim's borrow reward indexes have been updated - claimAfterFirstBorrow, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) + claimAfterFirstBorrow, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, userAddr) suite.Require().True(found) for _, coin := range tc.args.firstBorrow { _, hasIndex := claimAfterFirstBorrow.HasBorrowRewardIndex(coin.Denom) @@ -996,14 +871,14 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { // User modifies their Borrow by either repaying or borrowing more if tc.args.modification.repay { - err = hardKeeper.Repay(suite.ctx, userAddr, userAddr, tc.args.modification.coins) + err = suite.hardKeeper.Repay(suite.ctx, userAddr, userAddr, tc.args.modification.coins) } else { - err = hardKeeper.Borrow(suite.ctx, userAddr, tc.args.modification.coins) + err = suite.hardKeeper.Borrow(suite.ctx, userAddr, tc.args.modification.coins) } suite.Require().NoError(err) // Confirm that claim's borrow reward indexes contain expected values - claimAfterModification, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) + claimAfterModification, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, userAddr) suite.Require().True(found) for _, coin := range tc.args.modification.coins { _, hasIndex := claimAfterModification.HasBorrowRewardIndex(coin.Denom) @@ -1021,11 +896,10 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { } } -func (suite *KeeperTestSuite) TestSimulateHardBorrowRewardSynchronization() { +func (suite *BorrowRewardsTestSuite) TestSimulateHardBorrowRewardSynchronization() { type args struct { borrow sdk.Coin rewardsPerSecond sdk.Coins - initialTime time.Time blockTimes []int expectedRewardIndexes types.RewardIndexes expectedRewards sdk.Coins @@ -1041,7 +915,6 @@ func (suite *KeeperTestSuite) TestSimulateHardBorrowRewardSynchronization() { args{ borrow: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("0.001223540000173228"))}, expectedRewards: cs(c("hard", 12235400)), @@ -1052,7 +925,6 @@ func (suite *KeeperTestSuite) TestSimulateHardBorrowRewardSynchronization() { args{ borrow: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("10.571385603126235340"))}, expectedRewards: cs(c("hard", 105713856031)), @@ -1061,55 +933,21 @@ func (suite *KeeperTestSuite) TestSimulateHardBorrowRewardSynchronization() { } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + userAddr := suite.addrs[3] + authBuilder := app.NewAuthGenesisBuilder().WithSimpleAccount(userAddr, cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15))) - // Mint coins to hard module account - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000))) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleBorrowRewardPeriod(tc.args.borrow.Denom, tc.args.rewardsPerSecond) - // setup incentive state - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[0])}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[0])}, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, tc.args.borrow.Denom, tc.args.initialTime) - var rewardIndexes types.RewardIndexes - for _, rewardCoin := range tc.args.rewardsPerSecond { - rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) - } - suite.keeper.SetHardBorrowRewardIndexes(suite.ctx, tc.args.borrow.Denom, rewardIndexes) - - // Set up hard state (interest factor for the relevant denom) - suite.hardKeeper.SetSupplyInterestFactor(suite.ctx, tc.args.borrow.Denom, sdk.MustNewDecFromStr("1.0")) - suite.hardKeeper.SetBorrowInterestFactor(suite.ctx, tc.args.borrow.Denom, sdk.MustNewDecFromStr("1.0")) - suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.borrow.Denom, tc.args.initialTime) + suite.SetupWithGenState(authBuilder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) // User deposits and borrows to increase total borrowed amount - hardKeeper := suite.app.GetHardKeeper() - userAddr := suite.addrs[3] - err := hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(sdk.NewCoin(tc.args.borrow.Denom, tc.args.borrow.Amount.Mul(sdk.NewInt(2))))) + err := suite.hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(sdk.NewCoin(tc.args.borrow.Denom, tc.args.borrow.Amount.Mul(sdk.NewInt(2))))) suite.Require().NoError(err) - err = hardKeeper.Borrow(suite.ctx, userAddr, sdk.NewCoins(tc.args.borrow)) + err = suite.hardKeeper.Borrow(suite.ctx, userAddr, sdk.NewCoins(tc.args.borrow)) suite.Require().NoError(err) - // Check that Hard hooks initialized a HardLiquidityProviderClaim - claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) - suite.Require().True(found) - multiRewardIndex, _ := claim.BorrowRewardIndexes.GetRewardIndex(tc.args.borrow.Denom) - for _, expectedRewardIndex := range tc.args.expectedRewardIndexes { - currRewardIndex, found := multiRewardIndex.RewardIndexes.GetRewardIndex(expectedRewardIndex.CollateralType) - suite.Require().True(found) - suite.Require().Equal(sdk.ZeroDec(), currRewardIndex.RewardFactor) - } - // Run accumulator at several intervals var timeElapsed int previousBlockTime := suite.ctx.BlockTime() @@ -1132,7 +970,7 @@ func (suite *KeeperTestSuite) TestSimulateHardBorrowRewardSynchronization() { suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) // Confirm that the user's claim hasn't been synced - claimPre, foundPre := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) + claimPre, foundPre := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, userAddr) suite.Require().True(foundPre) multiRewardIndexPre, _ := claimPre.BorrowRewardIndexes.GetRewardIndex(tc.args.borrow.Denom) for _, expectedRewardIndex := range tc.args.expectedRewardIndexes { @@ -1142,7 +980,7 @@ func (suite *KeeperTestSuite) TestSimulateHardBorrowRewardSynchronization() { } // Check that the synced claim held in memory has properly simulated syncing - syncedClaim := suite.keeper.SimulateHardSynchronization(suite.ctx, claim) + syncedClaim := suite.keeper.SimulateHardSynchronization(suite.ctx, claimPre) for _, expectedRewardIndex := range tc.args.expectedRewardIndexes { // Check that the user's claim's reward index matches the expected reward index multiRewardIndex, found := syncedClaim.BorrowRewardIndexes.GetRewardIndex(tc.args.borrow.Denom) @@ -1160,3 +998,7 @@ func (suite *KeeperTestSuite) TestSimulateHardBorrowRewardSynchronization() { }) } } + +func TestBorrowRewardsTestSuite(t *testing.T) { + suite.Run(t, new(BorrowRewardsTestSuite)) +} diff --git a/x/incentive/keeper/rewards_delegator_test.go b/x/incentive/keeper/rewards_delegator_test.go index 96d2e862..14b7106d 100644 --- a/x/incentive/keeper/rewards_delegator_test.go +++ b/x/incentive/keeper/rewards_delegator_test.go @@ -1,23 +1,73 @@ package keeper_test import ( + "testing" "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/kava-labs/kava/x/hard" - hardtypes "github.com/kava-labs/kava/x/hard/types" + "github.com/kava-labs/kava/app" + "github.com/kava-labs/kava/x/incentive/keeper" "github.com/kava-labs/kava/x/incentive/types" ) -func (suite *KeeperTestSuite) TestAccumulateHardDelegatorRewards() { +// Test suite used for all keeper tests +type DelegatorRewardsTestSuite struct { + suite.Suite + + keeper keeper.Keeper + stakingKeeper stakingkeeper.Keeper + + app app.TestApp + ctx sdk.Context + + genesisTime time.Time + addrs []sdk.AccAddress + validatorAddrs []sdk.ValAddress +} + +// SetupTest is run automatically before each suite test +func (suite *DelegatorRewardsTestSuite) SetupTest() { + config := sdk.GetConfig() + app.SetBech32AddressPrefixes(config) + + _, allAddrs := app.GeneratePrivKeyAddressPairs(10) + suite.addrs = allAddrs[:5] + for _, a := range allAddrs[5:] { + suite.validatorAddrs = append(suite.validatorAddrs, sdk.ValAddress(a)) + } + suite.genesisTime = time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC) +} + +func (suite *DelegatorRewardsTestSuite) SetupApp() { + suite.app = app.NewTestApp() + + suite.keeper = suite.app.GetIncentiveKeeper() + suite.stakingKeeper = suite.app.GetStakingKeeper() + + suite.ctx = suite.app.NewContext(true, abci.Header{Height: 1, Time: suite.genesisTime}) +} + +func (suite *DelegatorRewardsTestSuite) SetupWithGenState(authBuilder app.AuthGenesisBuilder, incentBuilder IncentiveGenesisBuilder) { + suite.SetupApp() + + suite.app.InitializeFromGenesisStatesWithTime( + suite.genesisTime, + authBuilder.BuildMarshalled(), + NewStakingGenesisState(), + incentBuilder.BuildMarshalled(), + ) +} + +func (suite *DelegatorRewardsTestSuite) TestAccumulateHardDelegatorRewards() { type args struct { delegation sdk.Coin rewardsPerSecond sdk.Coin - initialTime time.Time timeElapsed int expectedRewardFactor sdk.Dec } @@ -31,7 +81,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardDelegatorRewards() { args{ delegation: c("ukava", 1_000_000), rewardsPerSecond: c("hard", 122354), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 7, expectedRewardFactor: d("0.428239000000000000"), }, @@ -41,7 +90,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardDelegatorRewards() { args{ delegation: c("ukava", 1_000_000), rewardsPerSecond: c("hard", 122354), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 86400, expectedRewardFactor: d("5285.692800000000000000"), }, @@ -51,7 +99,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardDelegatorRewards() { args{ delegation: c("ukava", 1_000_000), rewardsPerSecond: c("hard", 122354), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 0, expectedRewardFactor: d("0.0"), }, @@ -59,29 +106,15 @@ func (suite *KeeperTestSuite) TestAccumulateHardDelegatorRewards() { } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(suite.addrs[0], cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[0]), cs(c("ukava", 1e9))) - // Mint coins to hard module account - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000))) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleDelegatorRewardPeriod(tc.args.delegation.Denom, tc.args.rewardsPerSecond) - // Set up incentive state - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousHardDelegatorRewardAccrualTime(suite.ctx, tc.args.delegation.Denom, tc.args.initialTime) - suite.keeper.SetHardDelegatorRewardFactor(suite.ctx, tc.args.delegation.Denom, sdk.ZeroDec()) - - // Set up hard state (interest factor for the relevant denom) - suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.delegation.Denom, tc.args.initialTime) + suite.SetupWithGenState(authBuilder, incentBuilder) err := suite.deliverMsgCreateValidator(suite.ctx, suite.validatorAddrs[0], tc.args.delegation) suite.Require().NoError(err) @@ -94,25 +127,21 @@ func (suite *KeeperTestSuite) TestAccumulateHardDelegatorRewards() { runAtTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed)) runCtx := suite.ctx.WithBlockTime(runAtTime) - // Run Hard begin blocker in order to update the denom's index factor - hard.BeginBlocker(runCtx, suite.hardKeeper) - rewardPeriod, found := suite.keeper.GetHardDelegatorRewardPeriod(runCtx, tc.args.delegation.Denom) suite.Require().True(found) err = suite.keeper.AccumulateHardDelegatorRewards(runCtx, rewardPeriod) suite.Require().NoError(err) - rewardFactor, found := suite.keeper.GetHardDelegatorRewardFactor(runCtx, tc.args.delegation.Denom) + rewardFactor, _ := suite.keeper.GetHardDelegatorRewardFactor(runCtx, tc.args.delegation.Denom) suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) }) } } -func (suite *KeeperTestSuite) TestSynchronizeHardDelegatorReward() { +func (suite *DelegatorRewardsTestSuite) TestSynchronizeHardDelegatorReward() { type args struct { delegation sdk.Coin rewardsPerSecond sdk.Coin - initialTime time.Time blockTimes []int expectedRewardFactor sdk.Dec expectedRewards sdk.Coins @@ -128,7 +157,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardDelegatorReward() { args{ delegation: c("ukava", 1_000_000), rewardsPerSecond: c("hard", 122354), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardFactor: d("6.117700000000000000"), expectedRewards: cs(c("hard", 6117700)), @@ -139,7 +167,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardDelegatorReward() { args{ delegation: c("ukava", 1_000_000), rewardsPerSecond: c("hard", 122354), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, expectedRewardFactor: d("52856.928000000000000000"), expectedRewards: cs(c("hard", 52856928000)), @@ -150,7 +177,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardDelegatorReward() { args{ delegation: c("ukava", 1), rewardsPerSecond: c("hard", 1), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardFactor: d("0.000099999900000100"), expectedRewards: nil, @@ -159,29 +185,15 @@ func (suite *KeeperTestSuite) TestSynchronizeHardDelegatorReward() { } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(suite.addrs[0], cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[0]), cs(c("ukava", 1e9))) - // Mint coins to hard module account - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000))) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleDelegatorRewardPeriod(tc.args.delegation.Denom, tc.args.rewardsPerSecond) - // setup incentive state - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousHardDelegatorRewardAccrualTime(suite.ctx, tc.args.delegation.Denom, tc.args.initialTime) - suite.keeper.SetHardDelegatorRewardFactor(suite.ctx, tc.args.delegation.Denom, sdk.ZeroDec()) - - // Set up hard state (interest factor for the relevant denom) - suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.delegation.Denom, tc.args.initialTime) + suite.SetupWithGenState(authBuilder, incentBuilder) // Create validator account staking.BeginBlocker(suite.ctx, suite.stakingKeeper) @@ -214,9 +226,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardDelegatorReward() { previousBlockTime = updatedBlockTime blockCtx := suite.ctx.WithBlockTime(updatedBlockTime) - // Run Hard begin blocker for each block ctx to update denom's interest factor - hard.BeginBlocker(blockCtx, suite.hardKeeper) - rewardPeriod, found := suite.keeper.GetHardDelegatorRewardPeriod(blockCtx, tc.args.delegation.Denom) suite.Require().True(found) @@ -232,7 +241,7 @@ func (suite *KeeperTestSuite) TestSynchronizeHardDelegatorReward() { }) // Check that reward factor and claim have been updated as expected - rewardFactor, found := suite.keeper.GetHardDelegatorRewardFactor(suite.ctx, tc.args.delegation.Denom) + rewardFactor, _ := suite.keeper.GetHardDelegatorRewardFactor(suite.ctx, tc.args.delegation.Denom) suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) claim, found = suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[0]) @@ -243,11 +252,10 @@ func (suite *KeeperTestSuite) TestSynchronizeHardDelegatorReward() { } } -func (suite *KeeperTestSuite) TestSimulateHardDelegatorRewardSynchronization() { +func (suite *DelegatorRewardsTestSuite) TestSimulateHardDelegatorRewardSynchronization() { type args struct { delegation sdk.Coin - rewardsPerSecond sdk.Coins - initialTime time.Time + rewardsPerSecond sdk.Coin blockTimes []int expectedRewardIndexes types.RewardIndexes expectedRewards sdk.Coins @@ -262,8 +270,7 @@ func (suite *KeeperTestSuite) TestSimulateHardDelegatorRewardSynchronization() { "10 blocks", args{ delegation: c("ukava", 1_000_000), - rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + rewardsPerSecond: c("hard", 122354), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("ukava", d("6.117700000000000000"))}, // Here the reward index stores data differently than inside a MultiRewardIndex expectedRewards: cs(c("hard", 6117700)), @@ -273,8 +280,7 @@ func (suite *KeeperTestSuite) TestSimulateHardDelegatorRewardSynchronization() { "10 blocks - long block time", args{ delegation: c("ukava", 1_000_000), - rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + rewardsPerSecond: c("hard", 122354), blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("ukava", d("52856.928000000000000000"))}, expectedRewards: cs(c("hard", 52856928000)), @@ -284,29 +290,15 @@ func (suite *KeeperTestSuite) TestSimulateHardDelegatorRewardSynchronization() { for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(suite.addrs[0], cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[0]), cs(c("ukava", 1e9))) - // Mint coins to hard module account - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000))) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleDelegatorRewardPeriod(tc.args.delegation.Denom, tc.args.rewardsPerSecond) - // setup incentive state - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[0])}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[0])}, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousHardDelegatorRewardAccrualTime(suite.ctx, tc.args.delegation.Denom, tc.args.initialTime) - suite.keeper.SetHardDelegatorRewardFactor(suite.ctx, tc.args.delegation.Denom, sdk.ZeroDec()) - - // Set up hard state (interest factor for the relevant denom) - suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.delegation.Denom, tc.args.initialTime) + suite.SetupWithGenState(authBuilder, incentBuilder) // Delegator delegates err := suite.deliverMsgCreateValidator(suite.ctx, suite.validatorAddrs[0], tc.args.delegation) @@ -330,9 +322,6 @@ func (suite *KeeperTestSuite) TestSimulateHardDelegatorRewardSynchronization() { previousBlockTime = updatedBlockTime blockCtx := suite.ctx.WithBlockTime(updatedBlockTime) - // Run Hard begin blocker for each block ctx to update denom's interest factor - hard.BeginBlocker(blockCtx, suite.hardKeeper) - // Accumulate hard delegator rewards rewardPeriod, found := suite.keeper.GetHardDelegatorRewardPeriod(blockCtx, tc.args.delegation.Denom) suite.Require().True(found) @@ -360,7 +349,7 @@ func (suite *KeeperTestSuite) TestSimulateHardDelegatorRewardSynchronization() { } } -func (suite *KeeperTestSuite) deliverMsgCreateValidator(ctx sdk.Context, address sdk.ValAddress, selfDelegation sdk.Coin) error { +func (suite *DelegatorRewardsTestSuite) deliverMsgCreateValidator(ctx sdk.Context, address sdk.ValAddress, selfDelegation sdk.Coin) error { msg := staking.NewMsgCreateValidator( address, ed25519.GenPrivKey().PubKey(), @@ -374,7 +363,7 @@ func (suite *KeeperTestSuite) deliverMsgCreateValidator(ctx sdk.Context, address return err } -func (suite *KeeperTestSuite) deliverMsgDelegate(ctx sdk.Context, delegator sdk.AccAddress, validator sdk.ValAddress, amount sdk.Coin) error { +func (suite *DelegatorRewardsTestSuite) deliverMsgDelegate(ctx sdk.Context, delegator sdk.AccAddress, validator sdk.ValAddress, amount sdk.Coin) error { msg := staking.NewMsgDelegate( delegator, validator, @@ -385,7 +374,7 @@ func (suite *KeeperTestSuite) deliverMsgDelegate(ctx sdk.Context, delegator sdk. return err } -func (suite *KeeperTestSuite) deliverMsgRedelegate(ctx sdk.Context, delegator sdk.AccAddress, sourceValidator, destinationValidator sdk.ValAddress, amount sdk.Coin) error { +func (suite *DelegatorRewardsTestSuite) deliverMsgRedelegate(ctx sdk.Context, delegator sdk.AccAddress, sourceValidator, destinationValidator sdk.ValAddress, amount sdk.Coin) error { msg := staking.NewMsgBeginRedelegate( delegator, sourceValidator, @@ -398,28 +387,24 @@ func (suite *KeeperTestSuite) deliverMsgRedelegate(ctx sdk.Context, delegator sd } // given a user has a delegation to a bonded validator, when the validator starts unbonding, the user does not accumulate rewards -func (suite *KeeperTestSuite) TestUnbondingValidatorSyncsClaim() { - suite.SetupWithGenState() - initialTime := time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC) - suite.ctx = suite.ctx.WithBlockTime(initialTime) - blockDuration := 10 * time.Second +func (suite *DelegatorRewardsTestSuite) TestUnbondingValidatorSyncsClaim() { + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(suite.addrs[0], cs(c("ukava", 1e9))). + WithSimpleAccount(suite.addrs[2], cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[0]), cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[1]), cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[2]), cs(c("ukava", 1e9))) - // Setup incentive state rewardsPerSecond := c("hard", 122354) bondDenom := "ukava" - params := types.NewParams( - nil, - nil, - nil, - types.RewardPeriods{ - types.NewRewardPeriod(true, bondDenom, initialTime.Add(-1*oneYear), initialTime.Add(4*oneYear), rewardsPerSecond), - }, - types.DefaultMultipliers, - initialTime.Add(5*oneYear), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousHardDelegatorRewardAccrualTime(suite.ctx, bondDenom, initialTime) - suite.keeper.SetHardDelegatorRewardFactor(suite.ctx, bondDenom, sdk.ZeroDec()) + + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleDelegatorRewardPeriod(bondDenom, rewardsPerSecond) + + suite.SetupWithGenState(authBuilder, incentBuilder) + + blockDuration := 10 * time.Second // Reduce the size of the validator set stakingParams := suite.app.GetStakingKeeper().GetParams(suite.ctx) @@ -437,7 +422,7 @@ func (suite *KeeperTestSuite) TestUnbondingValidatorSyncsClaim() { // End the block so top validators become bonded _ = suite.app.EndBlocker(suite.ctx, abci.RequestEndBlock{}) - suite.ctx = suite.ctx.WithBlockTime(initialTime.Add(1 * blockDuration)) + suite.ctx = suite.ctx.WithBlockTime(suite.genesisTime.Add(1 * blockDuration)) _ = suite.app.BeginBlocker(suite.ctx, abci.RequestBeginBlock{}) // height and time in header are ignored by module begin blockers // Delegate to a bonded validator from the test user. This will initialize their incentive claim. @@ -446,7 +431,7 @@ func (suite *KeeperTestSuite) TestUnbondingValidatorSyncsClaim() { // Start a new block to accumulate some delegation rewards for the user. _ = suite.app.EndBlocker(suite.ctx, abci.RequestEndBlock{}) - suite.ctx = suite.ctx.WithBlockTime(initialTime.Add(2 * blockDuration)) + suite.ctx = suite.ctx.WithBlockTime(suite.genesisTime.Add(2 * blockDuration)) _ = suite.app.BeginBlocker(suite.ctx, abci.RequestBeginBlock{}) // height and time in header are ignored by module begin blockers // Delegate to the unbonded validator to push it into the bonded validator set, pushing out the user's delegated validator @@ -473,7 +458,7 @@ func (suite *KeeperTestSuite) TestUnbondingValidatorSyncsClaim() { ) // Run another block and check the claim is not accumulating more rewards - suite.ctx = suite.ctx.WithBlockTime(initialTime.Add(3 * blockDuration)) + suite.ctx = suite.ctx.WithBlockTime(suite.genesisTime.Add(3 * blockDuration)) _ = suite.app.BeginBlocker(suite.ctx, abci.RequestBeginBlock{}) suite.keeper.SynchronizeHardDelegatorRewards(suite.ctx, suite.addrs[0], nil, false) @@ -492,28 +477,24 @@ func (suite *KeeperTestSuite) TestUnbondingValidatorSyncsClaim() { } // given a user has a delegation to an unbonded validator, when the validator becomes bonded, the user starts accumulating rewards -func (suite *KeeperTestSuite) TestBondingValidatorSyncsClaim() { - suite.SetupWithGenState() - initialTime := time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC) - suite.ctx = suite.ctx.WithBlockTime(initialTime) - blockDuration := 10 * time.Second +func (suite *DelegatorRewardsTestSuite) TestBondingValidatorSyncsClaim() { + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(suite.addrs[0], cs(c("ukava", 1e9))). + WithSimpleAccount(suite.addrs[2], cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[0]), cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[1]), cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[2]), cs(c("ukava", 1e9))) - // Setup incentive state rewardsPerSecond := c("hard", 122354) bondDenom := "ukava" - params := types.NewParams( - nil, - nil, - nil, - types.RewardPeriods{ - types.NewRewardPeriod(true, bondDenom, initialTime.Add(-1*oneYear), initialTime.Add(4*oneYear), rewardsPerSecond), - }, - types.DefaultMultipliers, - initialTime.Add(5*oneYear), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousHardDelegatorRewardAccrualTime(suite.ctx, bondDenom, initialTime) - suite.keeper.SetHardDelegatorRewardFactor(suite.ctx, bondDenom, sdk.ZeroDec()) + + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleDelegatorRewardPeriod(bondDenom, rewardsPerSecond) + + suite.SetupWithGenState(authBuilder, incentBuilder) + + blockDuration := 10 * time.Second // Reduce the size of the validator set stakingParams := suite.app.GetStakingKeeper().GetParams(suite.ctx) @@ -531,7 +512,7 @@ func (suite *KeeperTestSuite) TestBondingValidatorSyncsClaim() { // End the block so top validators become bonded _ = suite.app.EndBlocker(suite.ctx, abci.RequestEndBlock{}) - suite.ctx = suite.ctx.WithBlockTime(initialTime.Add(1 * blockDuration)) + suite.ctx = suite.ctx.WithBlockTime(suite.genesisTime.Add(1 * blockDuration)) _ = suite.app.BeginBlocker(suite.ctx, abci.RequestBeginBlock{}) // height and time in header are ignored by module begin blockers // Delegate to an unbonded validator from the test user. This will initialize their incentive claim. @@ -540,7 +521,7 @@ func (suite *KeeperTestSuite) TestBondingValidatorSyncsClaim() { // Start a new block to accumulate some delegation rewards globally. _ = suite.app.EndBlocker(suite.ctx, abci.RequestEndBlock{}) - suite.ctx = suite.ctx.WithBlockTime(initialTime.Add(2 * blockDuration)) + suite.ctx = suite.ctx.WithBlockTime(suite.genesisTime.Add(2 * blockDuration)) _ = suite.app.BeginBlocker(suite.ctx, abci.RequestBeginBlock{}) // Delegate to the user's unbonded validator to push it into the bonded validator set @@ -567,7 +548,7 @@ func (suite *KeeperTestSuite) TestBondingValidatorSyncsClaim() { ) // Run another block and check the claim is accumulating more rewards - suite.ctx = suite.ctx.WithBlockTime(initialTime.Add(3 * blockDuration)) + suite.ctx = suite.ctx.WithBlockTime(suite.genesisTime.Add(3 * blockDuration)) _ = suite.app.BeginBlocker(suite.ctx, abci.RequestBeginBlock{}) suite.keeper.SynchronizeHardDelegatorRewards(suite.ctx, suite.addrs[0], nil, false) @@ -586,28 +567,22 @@ func (suite *KeeperTestSuite) TestBondingValidatorSyncsClaim() { } // If a validator is slashed delegators should have their claims synced -func (suite *KeeperTestSuite) TestSlashingValidatorSyncsClaim() { - suite.SetupWithGenState() - initialTime := time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC) - suite.ctx = suite.ctx.WithBlockTime(initialTime) - blockDuration := 10 * time.Second +func (suite *DelegatorRewardsTestSuite) TestSlashingValidatorSyncsClaim() { + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(suite.addrs[0], cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[0]), cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[1]), cs(c("ukava", 1e9))) - // Setup incentive state rewardsPerSecond := c("hard", 122354) bondDenom := "ukava" - params := types.NewParams( - nil, - nil, - nil, - types.RewardPeriods{ - types.NewRewardPeriod(true, bondDenom, initialTime.Add(-1*oneYear), initialTime.Add(4*oneYear), rewardsPerSecond), - }, - types.DefaultMultipliers, - initialTime.Add(5*oneYear), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousHardDelegatorRewardAccrualTime(suite.ctx, bondDenom, initialTime.Add(-1*blockDuration)) - suite.keeper.SetHardDelegatorRewardFactor(suite.ctx, bondDenom, sdk.ZeroDec()) + + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleDelegatorRewardPeriod(bondDenom, rewardsPerSecond) + + suite.SetupWithGenState(authBuilder, incentBuilder) + + blockDuration := 10 * time.Second // Reduce the size of the validator set stakingParams := suite.app.GetStakingKeeper().GetParams(suite.ctx) @@ -623,7 +598,7 @@ func (suite *KeeperTestSuite) TestSlashingValidatorSyncsClaim() { // End the block so validators become bonded _ = suite.app.EndBlocker(suite.ctx, abci.RequestEndBlock{}) - suite.ctx = suite.ctx.WithBlockTime(initialTime.Add(1 * blockDuration)) + suite.ctx = suite.ctx.WithBlockTime(suite.genesisTime.Add(1 * blockDuration)) _ = suite.app.BeginBlocker(suite.ctx, abci.RequestBeginBlock{}) // height and time in header are ignored by module begin blockers // Delegate to a bonded validator from the test user. This will initialize their incentive claim. @@ -642,7 +617,7 @@ func (suite *KeeperTestSuite) TestSlashingValidatorSyncsClaim() { // Start a new block to accumulate some delegation rewards for the user. _ = suite.app.EndBlocker(suite.ctx, abci.RequestEndBlock{}) - suite.ctx = suite.ctx.WithBlockTime(initialTime.Add(2 * blockDuration)) + suite.ctx = suite.ctx.WithBlockTime(suite.genesisTime.Add(2 * blockDuration)) _ = suite.app.BeginBlocker(suite.ctx, abci.RequestBeginBlock{}) // height and time in header are ignored by module begin blockers // Fetch validator and slash them @@ -673,28 +648,23 @@ func (suite *KeeperTestSuite) TestSlashingValidatorSyncsClaim() { } // Given a delegation to a bonded validator, when a user redelegates everything to another (bonded) validator, the user's claim is synced -func (suite *KeeperTestSuite) TestRedelegationSyncsClaim() { - suite.SetupWithGenState() - initialTime := time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC) - suite.ctx = suite.ctx.WithBlockTime(initialTime) - blockDuration := 10 * time.Second +func (suite *DelegatorRewardsTestSuite) TestRedelegationSyncsClaim() { + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(suite.addrs[0], cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[0]), cs(c("ukava", 1e9))). + WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[1]), cs(c("ukava", 1e9))) - // Setup incentive state rewardsPerSecond := c("hard", 122354) bondDenom := "ukava" - params := types.NewParams( - nil, - nil, - nil, - types.RewardPeriods{ - types.NewRewardPeriod(true, bondDenom, initialTime.Add(-1*oneYear), initialTime.Add(4*oneYear), rewardsPerSecond), - }, - types.DefaultMultipliers, - initialTime.Add(5*oneYear), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousHardDelegatorRewardAccrualTime(suite.ctx, bondDenom, initialTime) - suite.keeper.SetHardDelegatorRewardFactor(suite.ctx, bondDenom, sdk.ZeroDec()) + + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleDelegatorRewardPeriod(bondDenom, rewardsPerSecond) + + suite.SetupWithGenState(authBuilder, incentBuilder) + + suite.ctx = suite.ctx.WithBlockTime(suite.genesisTime) + blockDuration := 10 * time.Second // Create 2 validators err := suite.deliverMsgCreateValidator(suite.ctx, suite.validatorAddrs[0], c(bondDenom, 10_000_000)) @@ -708,7 +678,7 @@ func (suite *KeeperTestSuite) TestRedelegationSyncsClaim() { // Start a new block to accumulate some delegation rewards globally. _ = suite.app.EndBlocker(suite.ctx, abci.RequestEndBlock{}) - suite.ctx = suite.ctx.WithBlockTime(initialTime.Add(1 * blockDuration)) + suite.ctx = suite.ctx.WithBlockTime(suite.genesisTime.Add(1 * blockDuration)) _ = suite.app.BeginBlocker(suite.ctx, abci.RequestBeginBlock{}) // height and time in header are ignored by module begin blockers // Redelegate the user's delegation between the two validators. This should trigger hooks that sync the user's claim. @@ -729,3 +699,7 @@ func (suite *KeeperTestSuite) TestRedelegationSyncsClaim() { claim.Reward, ) } + +func TestDelegatorRewardsTestSuite(t *testing.T) { + suite.Run(t, new(DelegatorRewardsTestSuite)) +} diff --git a/x/incentive/keeper/rewards_supply_test.go b/x/incentive/keeper/rewards_supply_test.go index 64090fd1..8871aaee 100644 --- a/x/incentive/keeper/rewards_supply_test.go +++ b/x/incentive/keeper/rewards_supply_test.go @@ -1,23 +1,75 @@ package keeper_test import ( + "testing" "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" + "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" + "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/x/committee" + committeekeeper "github.com/kava-labs/kava/x/committee/keeper" "github.com/kava-labs/kava/x/hard" - hardtypes "github.com/kava-labs/kava/x/hard/types" + hardkeeper "github.com/kava-labs/kava/x/hard/keeper" + "github.com/kava-labs/kava/x/incentive/keeper" "github.com/kava-labs/kava/x/incentive/types" ) -func (suite *KeeperTestSuite) TestAccumulateHardSupplyRewards() { +// Test suite used for all keeper tests +type SupplyRewardsTestSuite struct { + suite.Suite + + keeper keeper.Keeper + hardKeeper hardkeeper.Keeper + committeeKeeper committeekeeper.Keeper + + app app.TestApp + ctx sdk.Context + + genesisTime time.Time + addrs []sdk.AccAddress +} + +// SetupTest is run automatically before each suite test +func (suite *SupplyRewardsTestSuite) SetupTest() { + config := sdk.GetConfig() + app.SetBech32AddressPrefixes(config) + + _, suite.addrs = app.GeneratePrivKeyAddressPairs(5) + + suite.genesisTime = time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC) +} + +func (suite *SupplyRewardsTestSuite) SetupApp() { + suite.app = app.NewTestApp() + + suite.keeper = suite.app.GetIncentiveKeeper() + suite.hardKeeper = suite.app.GetHardKeeper() + suite.committeeKeeper = suite.app.GetCommitteeKeeper() + + suite.ctx = suite.app.NewContext(true, abci.Header{Height: 1, Time: suite.genesisTime}) +} + +func (suite *SupplyRewardsTestSuite) SetupWithGenState(authBuilder app.AuthGenesisBuilder, incentBuilder IncentiveGenesisBuilder, hardBuilder HardGenesisBuilder) { + suite.SetupApp() + + suite.app.InitializeFromGenesisStatesWithTime( + suite.genesisTime, + authBuilder.BuildMarshalled(), + NewPricefeedGenStateMultiFromTime(suite.genesisTime), + hardBuilder.BuildMarshalled(), + NewCommitteeGenesisState(suite.addrs[:2]), // TODO add committee members to suite + incentBuilder.BuildMarshalled(), + ) +} + +func (suite *SupplyRewardsTestSuite) TestAccumulateHardSupplyRewards() { type args struct { deposit sdk.Coin rewardsPerSecond sdk.Coins - initialTime time.Time timeElapsed int expectedRewardIndexes types.RewardIndexes } @@ -31,7 +83,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardSupplyRewards() { args{ deposit: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 7, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("0.000000856478000000"))}, }, @@ -41,7 +92,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardSupplyRewards() { args{ deposit: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 86400, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("0.010571385600000000"))}, }, @@ -51,7 +101,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardSupplyRewards() { args{ deposit: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 0, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("0.0"))}, }, @@ -61,7 +110,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardSupplyRewards() { args{ deposit: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 7, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("0.000000856478000000")), @@ -74,7 +122,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardSupplyRewards() { args{ deposit: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 86400, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("0.010571385600000000")), @@ -87,7 +134,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardSupplyRewards() { args{ deposit: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 0, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("0.0")), @@ -100,7 +146,6 @@ func (suite *KeeperTestSuite) TestAccumulateHardSupplyRewards() { args{ deposit: c("bnb", 1000000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 555555)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), timeElapsed: 86400, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("0.010571385600000000")), @@ -108,55 +153,26 @@ func (suite *KeeperTestSuite) TestAccumulateHardSupplyRewards() { }, }, }, - { - "single reward denom, no rewards", - args{ - deposit: c("bnb", 1000000000000), - rewardsPerSecond: sdk.Coins{}, - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - timeElapsed: 7, - expectedRewardIndexes: types.RewardIndexes{}, - }, - }, + // TODO test accumulate when there is a reward period with 0 rewardsPerSecond } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) - - // Mint coins to hard module account - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000))) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) - - // Set up incentive state - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), c("hard", 1))}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), c("hard", 1))}, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), + userAddr := suite.addrs[3] + authBuilder := app.NewAuthGenesisBuilder().WithSimpleAccount( + userAddr, + cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15)), ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime) - var rewardIndexes types.RewardIndexes - for _, rewardCoin := range tc.args.rewardsPerSecond { - rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) - } - if len(rewardIndexes) > 0 { - suite.keeper.SetHardSupplyRewardIndexes(suite.ctx, tc.args.deposit.Denom, rewardIndexes) + // suite.SetupWithGenState(authBuilder) + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime) + if tc.args.rewardsPerSecond != nil { + incentBuilder = incentBuilder.WithSimpleSupplyRewardPeriod(tc.args.deposit.Denom, tc.args.rewardsPerSecond) } - // Set up hard state (interest factor for the relevant denom) - suite.hardKeeper.SetSupplyInterestFactor(suite.ctx, tc.args.deposit.Denom, sdk.MustNewDecFromStr("1.0")) - suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime) + suite.SetupWithGenState(authBuilder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) // User deposits to increase total supplied amount - hardKeeper := suite.app.GetHardKeeper() - userAddr := suite.addrs[3] - err := hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(tc.args.deposit)) + err := suite.hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(tc.args.deposit)) suite.Require().NoError(err) // Set up chain context at future time @@ -189,12 +205,11 @@ func (suite *KeeperTestSuite) TestAccumulateHardSupplyRewards() { } } -func (suite *KeeperTestSuite) TestInitializeHardSupplyRewards() { +func (suite *SupplyRewardsTestSuite) TestInitializeHardSupplyRewards() { type args struct { - moneyMarketRewardDenoms map[string][]string + moneyMarketRewardDenoms map[string]sdk.Coins deposit sdk.Coins - initialTime time.Time expectedClaimSupplyRewardIndexes types.MultiRewardIndexes } type test struct { @@ -202,10 +217,9 @@ func (suite *KeeperTestSuite) TestInitializeHardSupplyRewards() { args args } - standardMoneyMarketRewardDenoms := map[string][]string{ - "bnb": {"hard"}, - "btcb": {"hard", "ukava"}, - "xrp": {}, + standardMoneyMarketRewardDenoms := map[string]sdk.Coins{ + "bnb": cs(c("hard", 1)), + "btcb": cs(c("hard", 1), c("ukava", 1)), } testCases := []test{ @@ -214,7 +228,6 @@ func (suite *KeeperTestSuite) TestInitializeHardSupplyRewards() { args{ moneyMarketRewardDenoms: standardMoneyMarketRewardDenoms, deposit: cs(c("bnb", 1000000000000)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedClaimSupplyRewardIndexes: types.MultiRewardIndexes{ types.NewMultiRewardIndex( "bnb", @@ -230,7 +243,6 @@ func (suite *KeeperTestSuite) TestInitializeHardSupplyRewards() { args{ moneyMarketRewardDenoms: standardMoneyMarketRewardDenoms, deposit: cs(c("btcb", 1000000000000)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedClaimSupplyRewardIndexes: types.MultiRewardIndexes{ types.NewMultiRewardIndex( "btcb", @@ -247,7 +259,6 @@ func (suite *KeeperTestSuite) TestInitializeHardSupplyRewards() { args{ moneyMarketRewardDenoms: standardMoneyMarketRewardDenoms, deposit: cs(c("xrp", 1000000000000)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedClaimSupplyRewardIndexes: types.MultiRewardIndexes{ types.NewMultiRewardIndex( "xrp", @@ -261,7 +272,6 @@ func (suite *KeeperTestSuite) TestInitializeHardSupplyRewards() { args{ moneyMarketRewardDenoms: standardMoneyMarketRewardDenoms, deposit: cs(c("bnb", 1000000000000), c("btcb", 1000000000000)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedClaimSupplyRewardIndexes: types.MultiRewardIndexes{ types.NewMultiRewardIndex( "bnb", @@ -284,7 +294,6 @@ func (suite *KeeperTestSuite) TestInitializeHardSupplyRewards() { args{ moneyMarketRewardDenoms: standardMoneyMarketRewardDenoms, deposit: cs(c("bnb", 1000000000000), c("xrp", 1000000000000)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedClaimSupplyRewardIndexes: types.MultiRewardIndexes{ types.NewMultiRewardIndex( "bnb", @@ -302,61 +311,20 @@ func (suite *KeeperTestSuite) TestInitializeHardSupplyRewards() { } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) - - // Mint coins to hard module account - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000))) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) - userAddr := suite.addrs[3] - - // Prepare money market + reward params - i := 0 - var multiRewardPeriods types.MultiRewardPeriods - var rewardPeriods types.RewardPeriods - for moneyMarketDenom, rewardDenoms := range tc.args.moneyMarketRewardDenoms { - // Set up multi reward periods for supply/borrow indexes with dynamic money market denoms/reward denoms - var rewardsPerSecond sdk.Coins - for _, rewardDenom := range rewardDenoms { - rewardsPerSecond = append(rewardsPerSecond, sdk.NewCoin(rewardDenom, sdk.OneInt())) - } - multiRewardPeriod := types.NewMultiRewardPeriod(true, moneyMarketDenom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), rewardsPerSecond) - multiRewardPeriods = append(multiRewardPeriods, multiRewardPeriod) - - // Set up generic reward periods for usdx minting/delegator indexes - if i == 0 && len(rewardDenoms) > 0 { - rewardPeriod := types.NewRewardPeriod(true, moneyMarketDenom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), rewardsPerSecond[i]) - rewardPeriods = append(rewardPeriods, rewardPeriod) - i++ - } - } - - // Initialize and set incentive params - params := types.NewParams( - rewardPeriods, multiRewardPeriods, multiRewardPeriods, rewardPeriods, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), + authBuilder := app.NewAuthGenesisBuilder().WithSimpleAccount( + userAddr, + cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15)), ) - suite.keeper.SetParams(suite.ctx, params) - // Set each money market's previous accrual time and supply reward indexes - for moneyMarketDenom, rewardDenoms := range tc.args.moneyMarketRewardDenoms { - var rewardIndexes types.RewardIndexes - for _, rewardDenom := range rewardDenoms { - rewardIndex := types.NewRewardIndex(rewardDenom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) - } - suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, moneyMarketDenom, tc.args.initialTime) - if len(rewardIndexes) > 0 { - suite.keeper.SetHardSupplyRewardIndexes(suite.ctx, moneyMarketDenom, rewardIndexes) - } + incentBuilder := NewIncentiveGenesisBuilder().WithGenesisTime(suite.genesisTime) + for moneyMarketDenom, rewardsPerSecond := range tc.args.moneyMarketRewardDenoms { + incentBuilder = incentBuilder.WithSimpleSupplyRewardPeriod(moneyMarketDenom, rewardsPerSecond) } + suite.SetupWithGenState(authBuilder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) // User deposits - hardKeeper := suite.app.GetHardKeeper() - err := hardKeeper.Deposit(suite.ctx, userAddr, tc.args.deposit) + err := suite.hardKeeper.Deposit(suite.ctx, userAddr, tc.args.deposit) suite.Require().NoError(err) claim, foundClaim := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, userAddr) @@ -366,12 +334,11 @@ func (suite *KeeperTestSuite) TestInitializeHardSupplyRewards() { } } -func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { +func (suite *SupplyRewardsTestSuite) TestSynchronizeHardSupplyReward() { type args struct { incentiveSupplyRewardDenom string deposit sdk.Coin rewardsPerSecond sdk.Coins - initialTime time.Time blockTimes []int expectedRewardIndexes types.RewardIndexes expectedRewards sdk.Coins @@ -394,7 +361,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { incentiveSupplyRewardDenom: "bnb", deposit: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("0.001223540000000000"))}, expectedRewards: cs(c("hard", 12235400)), @@ -407,7 +373,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { incentiveSupplyRewardDenom: "bnb", deposit: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("10.571385600000000000"))}, expectedRewards: cs(c("hard", 105713856000)), @@ -420,7 +385,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { incentiveSupplyRewardDenom: "ukava", deposit: c("ukava", 1), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("0.122353998776460010"))}, expectedRewards: cs(), @@ -433,7 +397,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { incentiveSupplyRewardDenom: "bnb", deposit: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("0.001223540000000000")), @@ -449,7 +412,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { incentiveSupplyRewardDenom: "bnb", deposit: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("10.571385600000000000")), @@ -465,7 +427,6 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { incentiveSupplyRewardDenom: "bnb", deposit: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354), c("ukava", 555555)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("0.001223540000000000")), @@ -475,33 +436,12 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { updateRewardsViaCommmittee: false, }, }, - { - "denom is in incentive's hard supply reward params but it has no rewards; add reward", - args{ - incentiveSupplyRewardDenom: "bnb", - deposit: c("bnb", 10000000000), - rewardsPerSecond: sdk.Coins{}, - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - blockTimes: []int{100}, - expectedRewardIndexes: types.RewardIndexes{}, - expectedRewards: sdk.Coins{}, - updateRewardsViaCommmittee: true, - updatedBaseDenom: "bnb", - updatedRewardsPerSecond: cs(c("hard", 100000)), - updatedExpectedRewards: cs(c("hard", 8640000000)), - updatedExpectedRewardIndexes: types.RewardIndexes{ - types.NewRewardIndex("hard", d("0.864")), - }, - updatedTimeDuration: 86400, - }, - }, { "denom is in incentive's hard supply reward params and has rewards; add new reward type", args{ incentiveSupplyRewardDenom: "bnb", deposit: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{86400}, expectedRewardIndexes: types.RewardIndexes{ types.NewRewardIndex("hard", d("1.057138560000000000")), @@ -523,8 +463,7 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { args{ incentiveSupplyRewardDenom: "bnb", deposit: c("zzz", 10000000000), - rewardsPerSecond: sdk.Coins{}, - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + rewardsPerSecond: nil, blockTimes: []int{100}, expectedRewardIndexes: types.RewardIndexes{}, expectedRewards: sdk.Coins{}, @@ -538,35 +477,12 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { updatedTimeDuration: 86400, }, }, - { - "denom incentive's hard supply reward params but it has no rewards; add multiple reward types", - args{ - incentiveSupplyRewardDenom: "bnb", - deposit: c("bnb", 10000000000), - rewardsPerSecond: sdk.Coins{}, - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), - blockTimes: []int{100}, - expectedRewardIndexes: types.RewardIndexes{}, - expectedRewards: sdk.Coins{}, - updateRewardsViaCommmittee: true, - updatedBaseDenom: "bnb", - updatedRewardsPerSecond: cs(c("hard", 100000), c("ukava", 100500), c("swap", 500)), - updatedExpectedRewards: cs(c("hard", 8640000000), c("ukava", 8683200000), c("swap", 43200000)), - updatedExpectedRewardIndexes: types.RewardIndexes{ - types.NewRewardIndex("hard", d("0.864")), - types.NewRewardIndex("ukava", d("0.86832")), - types.NewRewardIndex("swap", d("0.00432")), - }, - updatedTimeDuration: 86400, - }, - }, { "denom is in hard's money market params but not in incentive's hard supply reward params; add multiple reward types", args{ incentiveSupplyRewardDenom: "bnb", deposit: c("zzz", 10000000000), - rewardsPerSecond: sdk.Coins{}, - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + rewardsPerSecond: nil, blockTimes: []int{100}, expectedRewardIndexes: types.RewardIndexes{}, expectedRewards: sdk.Coins{}, @@ -582,41 +498,21 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { updatedTimeDuration: 86400, }, }, + // TODO test synchronize when there is a reward period with 0 rewardsPerSecond } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + userAddr := suite.addrs[3] + authBuilder := app.NewAuthGenesisBuilder(). + WithSimpleAccount(suite.addrs[2], cs(c("ukava", 1e9))). + WithSimpleAccount(userAddr, cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15))) - // Mint coins to hard module account - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000))) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) - - // Set up incentive state - incentiveParams := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.incentiveSupplyRewardDenom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), c("hard", 1))}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.incentiveSupplyRewardDenom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.incentiveSupplyRewardDenom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.incentiveSupplyRewardDenom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), c("hard", 1))}, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, incentiveParams) - suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, tc.args.incentiveSupplyRewardDenom, tc.args.initialTime) - var rewardIndexes types.RewardIndexes - for _, rewardCoin := range tc.args.rewardsPerSecond { - rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime) + if tc.args.rewardsPerSecond != nil { + incentBuilder = incentBuilder.WithSimpleSupplyRewardPeriod(tc.args.incentiveSupplyRewardDenom, tc.args.rewardsPerSecond) } - if len(rewardIndexes) > 0 { - suite.keeper.SetHardSupplyRewardIndexes(suite.ctx, tc.args.incentiveSupplyRewardDenom, rewardIndexes) - } - - // Set up hard state (interest factor for the relevant denom) - suite.hardKeeper.SetSupplyInterestFactor(suite.ctx, tc.args.incentiveSupplyRewardDenom, sdk.MustNewDecFromStr("1.0")) - suite.hardKeeper.SetBorrowInterestFactor(suite.ctx, tc.args.incentiveSupplyRewardDenom, sdk.MustNewDecFromStr("1.0")) - suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.incentiveSupplyRewardDenom, tc.args.initialTime) + suite.SetupWithGenState(authBuilder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) // Deposit a fixed amount from another user to dilute primary user's rewards per second. suite.Require().NoError( @@ -624,9 +520,7 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { ) // User deposits and borrows to increase total borrowed amount - hardKeeper := suite.app.GetHardKeeper() - userAddr := suite.addrs[3] - err := hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(tc.args.deposit)) + err := suite.hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(tc.args.deposit)) suite.Require().NoError(err) // Check that Hard hooks initialized a HardLiquidityProviderClaim with 0 reward indexes @@ -662,7 +556,7 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) // After we've accumulated, run synchronize - deposit, found := hardKeeper.GetDeposit(suite.ctx, userAddr) + deposit, found := suite.hardKeeper.GetDeposit(suite.ctx, userAddr) suite.Require().True(found) suite.Require().NotPanics(func() { suite.keeper.SynchronizeHardSupplyReward(suite.ctx, deposit) @@ -714,7 +608,7 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { // Deposit denom's reward period does not exist _, found := currIncentiveHardSupplyRewardPeriods.GetMultiRewardPeriodIndex(tc.args.deposit.Denom) suite.Require().False(found) - newMultiRewardPeriod := types.NewMultiRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.updatedRewardsPerSecond) + newMultiRewardPeriod := types.NewMultiRewardPeriod(true, tc.args.deposit.Denom, suite.genesisTime, suite.genesisTime.Add(time.Hour*24*365*4), tc.args.updatedRewardsPerSecond) currIncentiveHardSupplyRewardPeriods = append(currIncentiveHardSupplyRewardPeriods, newMultiRewardPeriod) } @@ -742,7 +636,9 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { // 5. Committee votes and passes proposal err = suite.committeeKeeper.AddVote(suite.ctx, proposalID, committeeMemberOne, committee.Yes) + suite.Require().NoError(err) err = suite.committeeKeeper.AddVote(suite.ctx, proposalID, committeeMemberTwo, committee.Yes) + suite.Require().NoError(err) // 6. Check proposal passed com, found := suite.committeeKeeper.GetCommittee(suite.ctx, 1) @@ -773,7 +669,7 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { suite.Require().NoError(err) // After we've accumulated, run synchronize - deposit, found = hardKeeper.GetDeposit(suite.ctx, userAddr) + deposit, found = suite.hardKeeper.GetDeposit(suite.ctx, userAddr) suite.Require().True(found) suite.Require().NotPanics(func() { suite.keeper.SynchronizeHardSupplyReward(suite.ctx, deposit) @@ -807,7 +703,7 @@ func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { } } -func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { +func (suite *SupplyRewardsTestSuite) TestUpdateHardSupplyIndexDenoms() { type depositModification struct { coins sdk.Coins withdraw bool @@ -817,7 +713,6 @@ func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { firstDeposit sdk.Coins modification depositModification rewardsPerSecond sdk.Coins - initialTime time.Time expectedSupplyIndexDenoms []string } type test struct { @@ -832,7 +727,6 @@ func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { firstDeposit: cs(c("bnb", 10000000000)), modification: depositModification{coins: cs(c("ukava", 10000000000))}, rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedSupplyIndexDenoms: []string{"bnb", "ukava"}, }, }, @@ -842,7 +736,6 @@ func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { firstDeposit: cs(c("bnb", 10000000000)), modification: depositModification{coins: cs(c("ukava", 10000000000), c("btcb", 10000000000), c("xrp", 10000000000))}, rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedSupplyIndexDenoms: []string{"bnb", "ukava", "btcb", "xrp"}, }, }, @@ -852,7 +745,6 @@ func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { firstDeposit: cs(c("bnb", 10000000000)), modification: depositModification{coins: cs(c("bnb", 5000000000))}, rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedSupplyIndexDenoms: []string{"bnb"}, }, }, @@ -862,7 +754,6 @@ func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { firstDeposit: cs(c("bnb", 10000000000)), modification: depositModification{coins: cs(c("ukava", 10000000000))}, rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedSupplyIndexDenoms: []string{"bnb", "ukava"}, }, }, @@ -872,7 +763,6 @@ func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { firstDeposit: cs(c("bnb", 10000000000)), modification: depositModification{coins: cs(c("ukava", 10000000000), c("btcb", 10000000000), c("xrp", 10000000000))}, rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedSupplyIndexDenoms: []string{"bnb", "ukava", "btcb", "xrp"}, }, }, @@ -882,7 +772,6 @@ func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { firstDeposit: cs(c("bnb", 10000000000)), modification: depositModification{coins: cs(c("bnb", 5000000000))}, rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedSupplyIndexDenoms: []string{"bnb"}, }, }, @@ -892,7 +781,6 @@ func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { firstDeposit: cs(c("bnb", 1000000000)), modification: depositModification{coins: cs(c("bnb", 1100000000)), withdraw: true}, rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedSupplyIndexDenoms: []string{}, }, }, @@ -902,7 +790,6 @@ func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { firstDeposit: cs(c("bnb", 1000000000), c("ukava", 100000000)), modification: depositModification{coins: cs(c("bnb", 1100000000)), withdraw: true}, rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedSupplyIndexDenoms: []string{"ukava"}, }, }, @@ -912,61 +799,32 @@ func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { firstDeposit: cs(c("bnb", 1000000000)), modification: depositModification{coins: cs(c("bnb", 1100000000)), withdraw: true}, rewardsPerSecond: cs(c("hard", 122354), c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), expectedSupplyIndexDenoms: []string{}, }, }, } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) - - // Mint coins to hard module account - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000))) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) - - // Set up generic reward periods - var multiRewardPeriods types.MultiRewardPeriods - var rewardPeriods types.RewardPeriods - for i, denom := range tc.args.expectedSupplyIndexDenoms { - // Create just one reward period for USDX Minting / Hard Delegator reward periods (otherwise params will panic on duplicate) - if i == 0 { - rewardPeriod := types.NewRewardPeriod(true, denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[i]) - rewardPeriods = append(rewardPeriods, rewardPeriod) - } - multiRewardPeriod := types.NewMultiRewardPeriod(true, denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond) - multiRewardPeriods = append(multiRewardPeriods, multiRewardPeriod) - } - - // Setup incentive state - params := types.NewParams( - rewardPeriods, multiRewardPeriods, multiRewardPeriods, rewardPeriods, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), + userAddr := suite.addrs[3] + authBuilder := app.NewAuthGenesisBuilder().WithSimpleAccount( + userAddr, + cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15)), ) - suite.keeper.SetParams(suite.ctx, params) + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleSupplyRewardPeriod("bnb", tc.args.rewardsPerSecond). + WithSimpleSupplyRewardPeriod("ukava", tc.args.rewardsPerSecond). + WithSimpleSupplyRewardPeriod("btcb", tc.args.rewardsPerSecond). + WithSimpleSupplyRewardPeriod("xrp", tc.args.rewardsPerSecond) - // Set each denom's previous accrual time and supply reward factor - var rewardIndexes types.RewardIndexes - for _, rewardCoin := range tc.args.rewardsPerSecond { - rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) - } - for _, denom := range tc.args.expectedSupplyIndexDenoms { - suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, denom, tc.args.initialTime) - suite.keeper.SetHardSupplyRewardIndexes(suite.ctx, denom, rewardIndexes) - } + suite.SetupWithGenState(authBuilder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) // User deposits (first time) - hardKeeper := suite.app.GetHardKeeper() - userAddr := suite.addrs[3] - err := hardKeeper.Deposit(suite.ctx, userAddr, tc.args.firstDeposit) + err := suite.hardKeeper.Deposit(suite.ctx, userAddr, tc.args.firstDeposit) suite.Require().NoError(err) // Confirm that a claim was created and populated with the correct supply indexes - claimAfterFirstDeposit, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) + claimAfterFirstDeposit, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, userAddr) suite.Require().True(found) for _, coin := range tc.args.firstDeposit { _, hasIndex := claimAfterFirstDeposit.HasSupplyRewardIndex(coin.Denom) @@ -976,14 +834,14 @@ func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { // User modifies their Deposit by withdrawing or depositing more if tc.args.modification.withdraw { - err = hardKeeper.Withdraw(suite.ctx, userAddr, tc.args.modification.coins) + err = suite.hardKeeper.Withdraw(suite.ctx, userAddr, tc.args.modification.coins) } else { - err = hardKeeper.Deposit(suite.ctx, userAddr, tc.args.modification.coins) + err = suite.hardKeeper.Deposit(suite.ctx, userAddr, tc.args.modification.coins) } suite.Require().NoError(err) // Confirm that the claim contains all expected supply indexes - claimAfterModification, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) + claimAfterModification, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, userAddr) suite.Require().True(found) for _, denom := range tc.args.expectedSupplyIndexDenoms { _, hasIndex := claimAfterModification.HasSupplyRewardIndex(denom) @@ -994,11 +852,10 @@ func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { } } -func (suite *KeeperTestSuite) TestSimulateHardSupplyRewardSynchronization() { +func (suite *SupplyRewardsTestSuite) TestSimulateHardSupplyRewardSynchronization() { type args struct { deposit sdk.Coin rewardsPerSecond sdk.Coins - initialTime time.Time blockTimes []int expectedRewardIndexes types.RewardIndexes expectedRewards sdk.Coins @@ -1014,7 +871,6 @@ func (suite *KeeperTestSuite) TestSimulateHardSupplyRewardSynchronization() { args{ deposit: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("0.001223540000000000"))}, expectedRewards: cs(c("hard", 12235400)), @@ -1025,7 +881,6 @@ func (suite *KeeperTestSuite) TestSimulateHardSupplyRewardSynchronization() { args{ deposit: c("bnb", 10000000000), rewardsPerSecond: cs(c("hard", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("10.571385600000000000"))}, expectedRewards: cs(c("hard", 105713856000)), @@ -1034,52 +889,21 @@ func (suite *KeeperTestSuite) TestSimulateHardSupplyRewardSynchronization() { } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) - - // Mint coins to hard module account - supplyKeeper := suite.app.GetSupplyKeeper() - hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000))) - supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) - - // Set up incentive state - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[0])}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[0])}, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), + userAddr := suite.addrs[3] + authBuilder := app.NewAuthGenesisBuilder().WithSimpleAccount( + userAddr, + cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15)), ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime) - var rewardIndexes types.RewardIndexes - for _, rewardCoin := range tc.args.rewardsPerSecond { - rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) - rewardIndexes = append(rewardIndexes, rewardIndex) - } - suite.keeper.SetHardSupplyRewardIndexes(suite.ctx, tc.args.deposit.Denom, rewardIndexes) + incentBuilder := NewIncentiveGenesisBuilder(). + WithGenesisTime(suite.genesisTime). + WithSimpleSupplyRewardPeriod(tc.args.deposit.Denom, tc.args.rewardsPerSecond) - // Set up hard state (interest factor for the relevant denom) - suite.hardKeeper.SetSupplyInterestFactor(suite.ctx, tc.args.deposit.Denom, sdk.MustNewDecFromStr("1.0")) - suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime) + suite.SetupWithGenState(authBuilder, incentBuilder, NewHardGenStateMulti(suite.genesisTime)) // User deposits and borrows to increase total borrowed amount - hardKeeper := suite.app.GetHardKeeper() - userAddr := suite.addrs[3] - err := hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(tc.args.deposit)) + err := suite.hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(tc.args.deposit)) suite.Require().NoError(err) - // Check that Hard hooks initialized a HardLiquidityProviderClaim - claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) - suite.Require().True(found) - multiRewardIndex, _ := claim.SupplyRewardIndexes.GetRewardIndex(tc.args.deposit.Denom) - for _, expectedRewardIndex := range tc.args.expectedRewardIndexes { - currRewardIndex, found := multiRewardIndex.RewardIndexes.GetRewardIndex(expectedRewardIndex.CollateralType) - suite.Require().True(found) - suite.Require().Equal(sdk.ZeroDec(), currRewardIndex.RewardFactor) - } - // Run accumulator at several intervals var timeElapsed int previousBlockTime := suite.ctx.BlockTime() @@ -1102,7 +926,7 @@ func (suite *KeeperTestSuite) TestSimulateHardSupplyRewardSynchronization() { suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) // Confirm that the user's claim hasn't been synced - claimPre, foundPre := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) + claimPre, foundPre := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, userAddr) suite.Require().True(foundPre) multiRewardIndexPre, _ := claimPre.SupplyRewardIndexes.GetRewardIndex(tc.args.deposit.Denom) for _, expectedRewardIndex := range tc.args.expectedRewardIndexes { @@ -1130,3 +954,7 @@ func (suite *KeeperTestSuite) TestSimulateHardSupplyRewardSynchronization() { }) } } + +func TestSupplyRewardsTestSuite(t *testing.T) { + suite.Run(t, new(SupplyRewardsTestSuite)) +} diff --git a/x/incentive/keeper/rewards_usdx_test.go b/x/incentive/keeper/rewards_usdx_test.go index e7654ab0..82b0bc44 100644 --- a/x/incentive/keeper/rewards_usdx_test.go +++ b/x/incentive/keeper/rewards_usdx_test.go @@ -1,23 +1,68 @@ package keeper_test import ( + "testing" "time" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/kava-labs/kava/app" + cdpkeeper "github.com/kava-labs/kava/x/cdp/keeper" cdptypes "github.com/kava-labs/kava/x/cdp/types" - "github.com/kava-labs/kava/x/incentive/types" + "github.com/kava-labs/kava/x/incentive/keeper" ) -const ( - oneYear time.Duration = time.Hour * 24 * 365 -) +// Test suite used for all keeper tests +type USDXRewardsTestSuite struct { + suite.Suite -func (suite *KeeperTestSuite) TestAccumulateUSDXMintingRewards() { + keeper keeper.Keeper + cdpKeeper cdpkeeper.Keeper + + app app.TestApp + ctx sdk.Context + + genesisTime time.Time + addrs []sdk.AccAddress +} + +// SetupTest is run automatically before each suite test +func (suite *USDXRewardsTestSuite) SetupTest() { + config := sdk.GetConfig() + app.SetBech32AddressPrefixes(config) + + _, suite.addrs = app.GeneratePrivKeyAddressPairs(5) + + suite.genesisTime = time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC) +} + +func (suite *USDXRewardsTestSuite) SetupApp() { + suite.app = app.NewTestApp() + + suite.keeper = suite.app.GetIncentiveKeeper() + suite.cdpKeeper = suite.app.GetCDPKeeper() + + suite.ctx = suite.app.NewContext(true, abci.Header{Height: 1, Time: suite.genesisTime}) +} + +func (suite *USDXRewardsTestSuite) SetupWithGenState(authBuilder app.AuthGenesisBuilder, incentBuilder IncentiveGenesisBuilder) { + suite.SetupApp() + + suite.app.InitializeFromGenesisStatesWithTime( + suite.genesisTime, + authBuilder.BuildMarshalled(), + NewPricefeedGenStateMultiFromTime(suite.genesisTime), + NewCDPGenStateMulti(), + incentBuilder.BuildMarshalled(), + ) +} + +func (suite *USDXRewardsTestSuite) TestAccumulateUSDXMintingRewards() { type args struct { ctype string rewardsPerSecond sdk.Coin - initialTime time.Time initialTotalPrincipal sdk.Coin timeElapsed int expectedRewardFactor sdk.Dec @@ -32,7 +77,6 @@ func (suite *KeeperTestSuite) TestAccumulateUSDXMintingRewards() { args{ ctype: "bnb-a", rewardsPerSecond: c("ukava", 122354), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), initialTotalPrincipal: c("usdx", 1000000000000), timeElapsed: 7, expectedRewardFactor: d("0.000000856478000000"), @@ -43,7 +87,6 @@ func (suite *KeeperTestSuite) TestAccumulateUSDXMintingRewards() { args{ ctype: "bnb-a", rewardsPerSecond: c("ukava", 122354), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), initialTotalPrincipal: c("usdx", 1000000000000), timeElapsed: 86400, expectedRewardFactor: d("0.0105713856"), @@ -54,7 +97,6 @@ func (suite *KeeperTestSuite) TestAccumulateUSDXMintingRewards() { args{ ctype: "bnb-a", rewardsPerSecond: c("ukava", 122354), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), initialTotalPrincipal: c("usdx", 1000000000000), timeElapsed: 0, expectedRewardFactor: d("0.0"), @@ -63,25 +105,12 @@ func (suite *KeeperTestSuite) TestAccumulateUSDXMintingRewards() { } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + incentBuilder := NewIncentiveGenesisBuilder().WithGenesisTime(suite.genesisTime).WithSimpleUSDXRewardPeriod(tc.args.ctype, tc.args.rewardsPerSecond) + + suite.SetupWithGenState(app.NewAuthGenesisBuilder(), incentBuilder) // setup cdp state - cdpKeeper := suite.app.GetCDPKeeper() - cdpKeeper.SetTotalPrincipal(suite.ctx, tc.args.ctype, cdptypes.DefaultStableDenom, tc.args.initialTotalPrincipal.Amount) - - // setup incentive state - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime) - suite.keeper.SetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec()) + suite.cdpKeeper.SetTotalPrincipal(suite.ctx, tc.args.ctype, cdptypes.DefaultStableDenom, tc.args.initialTotalPrincipal.Amount) updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed)) suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) @@ -90,17 +119,16 @@ func (suite *KeeperTestSuite) TestAccumulateUSDXMintingRewards() { err := suite.keeper.AccumulateUSDXMintingRewards(suite.ctx, rewardPeriod) suite.Require().NoError(err) - rewardFactor, found := suite.keeper.GetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype) + rewardFactor, _ := suite.keeper.GetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype) suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) }) } } -func (suite *KeeperTestSuite) TestSynchronizeUSDXMintingReward() { +func (suite *USDXRewardsTestSuite) TestSynchronizeUSDXMintingReward() { type args struct { ctype string rewardsPerSecond sdk.Coin - initialTime time.Time initialCollateral sdk.Coin initialPrincipal sdk.Coin blockTimes []int @@ -118,7 +146,6 @@ func (suite *KeeperTestSuite) TestSynchronizeUSDXMintingReward() { args{ ctype: "bnb-a", rewardsPerSecond: c("ukava", 122354), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), initialCollateral: c("bnb", 1000000000000), initialPrincipal: c("usdx", 10000000000), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, @@ -131,7 +158,6 @@ func (suite *KeeperTestSuite) TestSynchronizeUSDXMintingReward() { args{ ctype: "bnb-a", rewardsPerSecond: c("ukava", 122354), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), initialCollateral: c("bnb", 1000000000000), initialPrincipal: c("usdx", 10000000000), blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, @@ -142,30 +168,13 @@ func (suite *KeeperTestSuite) TestSynchronizeUSDXMintingReward() { } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + authBuilder := app.NewAuthGenesisBuilder().WithSimpleAccount(suite.addrs[0], cs(tc.args.initialCollateral)) + incentBuilder := NewIncentiveGenesisBuilder().WithGenesisTime(suite.genesisTime).WithSimpleUSDXRewardPeriod(tc.args.ctype, tc.args.rewardsPerSecond) - // setup incentive state - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime) - suite.keeper.SetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec()) - - // setup account state - sk := suite.app.GetSupplyKeeper() - sk.MintCoins(suite.ctx, cdptypes.ModuleName, sdk.NewCoins(tc.args.initialCollateral)) - sk.SendCoinsFromModuleToAccount(suite.ctx, cdptypes.ModuleName, suite.addrs[0], sdk.NewCoins(tc.args.initialCollateral)) + suite.SetupWithGenState(authBuilder, incentBuilder) // setup cdp state - cdpKeeper := suite.app.GetCDPKeeper() - err := cdpKeeper.AddCdp(suite.ctx, suite.addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype) + err := suite.cdpKeeper.AddCdp(suite.ctx, suite.addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype) suite.Require().NoError(err) claim, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0]) @@ -186,13 +195,13 @@ func (suite *KeeperTestSuite) TestSynchronizeUSDXMintingReward() { } updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed)) suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) - cdp, found := cdpKeeper.GetCdpByOwnerAndCollateralType(suite.ctx, suite.addrs[0], tc.args.ctype) + cdp, found := suite.cdpKeeper.GetCdpByOwnerAndCollateralType(suite.ctx, suite.addrs[0], tc.args.ctype) suite.Require().True(found) suite.Require().NotPanics(func() { suite.keeper.SynchronizeUSDXMintingReward(suite.ctx, cdp) }) - rewardFactor, found := suite.keeper.GetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype) + rewardFactor, _ := suite.keeper.GetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype) suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) claim, found = suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0]) @@ -203,11 +212,10 @@ func (suite *KeeperTestSuite) TestSynchronizeUSDXMintingReward() { } } -func (suite *KeeperTestSuite) TestSimulateUSDXMintingRewardSynchronization() { +func (suite *USDXRewardsTestSuite) TestSimulateUSDXMintingRewardSynchronization() { type args struct { ctype string - rewardsPerSecond sdk.Coins - initialTime time.Time + rewardsPerSecond sdk.Coin initialCollateral sdk.Coin initialPrincipal sdk.Coin blockTimes []int @@ -224,8 +232,7 @@ func (suite *KeeperTestSuite) TestSimulateUSDXMintingRewardSynchronization() { "10 blocks", args{ ctype: "bnb-a", - rewardsPerSecond: cs(c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + rewardsPerSecond: c("ukava", 122354), initialCollateral: c("bnb", 1000000000000), initialPrincipal: c("usdx", 10000000000), blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, @@ -237,8 +244,7 @@ func (suite *KeeperTestSuite) TestSimulateUSDXMintingRewardSynchronization() { "10 blocks - long block time", args{ ctype: "bnb-a", - rewardsPerSecond: cs(c("ukava", 122354)), - initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), + rewardsPerSecond: c("ukava", 122354), initialCollateral: c("bnb", 1000000000000), initialPrincipal: c("usdx", 10000000000), blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, @@ -249,31 +255,13 @@ func (suite *KeeperTestSuite) TestSimulateUSDXMintingRewardSynchronization() { } for _, tc := range testCases { suite.Run(tc.name, func() { - suite.SetupWithGenState() - suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) + authBuilder := app.NewAuthGenesisBuilder().WithSimpleAccount(suite.addrs[0], cs(tc.args.initialCollateral)) + incentBuilder := NewIncentiveGenesisBuilder().WithGenesisTime(suite.genesisTime).WithSimpleUSDXRewardPeriod(tc.args.ctype, tc.args.rewardsPerSecond) - // setup incentive state - params := types.NewParams( - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[0])}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)}, - types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond[0])}, - types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))}, - tc.args.initialTime.Add(time.Hour*24*365*5), - ) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetParams(suite.ctx, params) - suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime) - suite.keeper.SetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec()) - - // setup account state - sk := suite.app.GetSupplyKeeper() - sk.MintCoins(suite.ctx, cdptypes.ModuleName, sdk.NewCoins(tc.args.initialCollateral)) - sk.SendCoinsFromModuleToAccount(suite.ctx, cdptypes.ModuleName, suite.addrs[0], sdk.NewCoins(tc.args.initialCollateral)) + suite.SetupWithGenState(authBuilder, incentBuilder) // setup cdp state - cdpKeeper := suite.app.GetCDPKeeper() - err := cdpKeeper.AddCdp(suite.ctx, suite.addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype) + err := suite.cdpKeeper.AddCdp(suite.ctx, suite.addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype) suite.Require().NoError(err) claim, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0]) @@ -306,3 +294,7 @@ func (suite *KeeperTestSuite) TestSimulateUSDXMintingRewardSynchronization() { }) } } + +func TestUSDXRewardsTestSuite(t *testing.T) { + suite.Run(t, new(USDXRewardsTestSuite)) +}