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
This commit is contained in:
Ruaridh 2021-06-10 14:35:44 +01:00 committed by GitHub
parent 9d9b169e6a
commit d56bb77231
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1162 additions and 1541 deletions

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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{
func NewCommitteeGenesisState(members []sdk.AccAddress) app.GenesisState {
genState := committeetypes.DefaultGenesisState()
genState.Committees = committeetypes.Committees{
committeetypes.MemberCommittee{
BaseCommittee: committeetypes.BaseCommittee{
ID: 1,
ID: genState.NextProposalID,
Description: "This committee is for testing.",
Members: suite.addrs[:2],
Members: members,
Permissions: []committeetypes.Permission{committeetypes.GodPermission{}},
VoteThreshold: d("0.667"),
ProposalDuration: time.Hour * 24 * 7,
TallyOption: committeetypes.FirstPastThePost,
},
},
}
genState.NextProposalID += 1
return app.GenesisState{
committeetypes.ModuleName: committeetypes.ModuleCdc.MustMarshalJSON(genState),
}
}
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
// 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(),
)
}

View File

@ -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"
)
@ -27,57 +19,34 @@ type KeeperTestSuite struct {
suite.Suite
keeper keeper.Keeper
hardKeeper hardkeeper.Keeper
stakingKeeper stakingkeeper.Keeper
committeeKeeper committeekeeper.Keeper
app app.TestApp
ctx sdk.Context
genesisTime time.Time
addrs []sdk.AccAddress
validatorAddrs []sdk.ValAddress
}
// 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)
suite.genesisTime = time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC)
}
tApp := app.NewTestApp()
ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()})
func (suite *KeeperTestSuite) SetupApp() {
suite.app = app.NewTestApp()
tApp.InitializeFromGenesisStates()
suite.keeper = suite.app.GetIncentiveKeeper()
suite.keeper = tApp.GetIncentiveKeeper()
suite.app = tApp
suite.ctx = ctx
}
// 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) getAccount(addr sdk.AccAddress) authexported.Account {
ak := suite.app.GetAccountKeeper()
return ak.GetAccount(suite.ctx, addr)
}
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))
}

View File

@ -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,11 +200,10 @@ 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
@ -167,7 +211,6 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaimVVesting() {
timeElapsed int
expectedBalance sdk.Coins
expectedPeriods vesting.Periods
isPeriodicVestingAccount bool
}
type errArgs struct {
expectPass bool
@ -184,15 +227,13 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaimVVesting() {
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),
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", 11571385600)),
expectedBalance: cs(c("ukava", 10571385600)),
expectedPeriods: vesting.Periods{vesting.Period{Length: 32918400, Amount: cs(c("ukava", 10571385600))}},
isPeriodicVestingAccount: true,
},
errArgs{
expectPass: true,
@ -204,15 +245,13 @@ func (suite *KeeperTestSuite) TestPayoutUSDXMintingClaimVVesting() {
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),
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{},
isPeriodicVestingAccount: false,
},
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)
}
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
}
type errArgs struct {
expectPass bool
@ -610,13 +560,11 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() {
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,
expectedRewards: cs(c("hard", 21142771202)),
expectedPeriods: vesting.Periods{vesting.Period{Length: 32918400, Amount: cs(c("hard", 21142771202))}},
},
errArgs{
expectPass: true,
@ -629,51 +577,28 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() {
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,
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,
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,
@ -686,13 +611,11 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() {
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,
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,
@ -705,13 +628,11 @@ func (suite *KeeperTestSuite) TestPayoutHardLiquidityProviderClaimVVesting() {
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,
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)
}
// 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))
}

View File

@ -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)
// 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)
// 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)
}
// 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)),
).
WithSimpleAccount(
suite.addrs[0],
cs(c("bnb", 1e15), c("ukava", 1e15), c("btcb", 1e15), c("xrp", 1e15), c("zzz", 1e15)),
)
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)
}
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)
suite.SetupWithGenState(authBuilder, incentBuilder, NewHardGenStateMulti(suite.genesisTime))
// 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))
}

View File

@ -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))
}

View File

@ -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))
}

View File

@ -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))
}