package keeper_test import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" tmtime "github.com/tendermint/tendermint/types/time" "github.com/kava-labs/kava/app" cdptypes "github.com/kava-labs/kava/x/cdp/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" ) func (suite *KeeperTestSuite) TestAccumulateUSDXMintingRewards() { type args struct { ctype string rewardsPerSecond sdk.Coin initialTime time.Time initialTotalPrincipal sdk.Coin timeElapsed int expectedRewardFactor sdk.Dec } type test struct { name string args args } testCases := []test{ { "7 seconds", 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"), }, }, { "1 day", 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"), }, }, { "0 seconds", 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"), }, }, } for _, tc := range testCases { suite.Run(tc.name, func() { suite.SetupWithGenState() suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime) // 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()) 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) suite.Require().True(found) err := suite.keeper.AccumulateUSDXMintingRewards(suite.ctx, rewardPeriod) suite.Require().NoError(err) rewardFactor, found := suite.keeper.GetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype) suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) }) } } func (suite *KeeperTestSuite) TestSynchronizeUSDXMintingReward() { type args struct { ctype string rewardsPerSecond sdk.Coin initialTime time.Time initialCollateral sdk.Coin initialPrincipal sdk.Coin blockTimes []int expectedRewardFactor sdk.Dec expectedRewards sdk.Coin } type test struct { name string args args } testCases := []test{ { "10 blocks", 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}, expectedRewardFactor: d("0.001223540000000000"), expectedRewards: c("ukava", 12235400), }, }, { "10 blocks - long block time", 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}, expectedRewardFactor: d("10.57138560000000000"), expectedRewards: c("ukava", 105713856000), }, }, } 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)}, 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)) // setup cdp state cdpKeeper := suite.app.GetCDPKeeper() err := 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]) suite.Require().True(found) suite.Require().Equal(sdk.ZeroDec(), claim.RewardIndexes[0].RewardFactor) var timeElapsed int previousBlockTime := suite.ctx.BlockTime() for _, t := range tc.args.blockTimes { timeElapsed += t updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t)) previousBlockTime = updatedBlockTime blockCtx := suite.ctx.WithBlockTime(updatedBlockTime) rewardPeriod, found := suite.keeper.GetUSDXMintingRewardPeriod(blockCtx, tc.args.ctype) suite.Require().True(found) err := suite.keeper.AccumulateUSDXMintingRewards(blockCtx, rewardPeriod) suite.Require().NoError(err) } 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) suite.Require().True(found) suite.Require().NotPanics(func() { suite.keeper.SynchronizeUSDXMintingReward(suite.ctx, cdp) }) rewardFactor, found := 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]) suite.Require().True(found) suite.Require().Equal(tc.args.expectedRewardFactor, claim.RewardIndexes[0].RewardFactor) suite.Require().Equal(tc.args.expectedRewards, claim.Reward) }) } } // func (suite *KeeperTestSuite) TestAccumulateHardBorrowRewards() { // type args struct { // borrow sdk.Coin // rewardsPerSecond sdk.Coin // initialTime time.Time // timeElapsed int // expectedRewardFactor sdk.Dec // } // type test struct { // name string // args args // } // testCases := []test{ // { // "7 seconds", // args{ // borrow: c("bnb", 1000000000000), // rewardsPerSecond: c("hard", 122354), // initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), // timeElapsed: 7, // expectedRewardFactor: d("0.000000856478000001"), // }, // }, // { // "1 day", // args{ // borrow: c("bnb", 1000000000000), // rewardsPerSecond: c("hard", 122354), // initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), // timeElapsed: 86400, // expectedRewardFactor: d("0.010571385600010177"), // }, // }, // { // "0 seconds", // args{ // borrow: c("bnb", 1000000000000), // rewardsPerSecond: c("hard", 122354), // initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), // timeElapsed: 0, // expectedRewardFactor: d("0.0"), // }, // }, // } // 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)}, // types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, // types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(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)}, // 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) // defaultRewardIndexes := types.RewardIndexes{types.NewRewardIndex(types.HardLiquidityRewardDenom, sdk.ZeroDec())} // suite.keeper.SetHardBorrowRewardIndexes(suite.ctx, tc.args.borrow.Denom, defaultRewardIndexes) // // 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) // // 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))))) // suite.Require().NoError(err) // err = hardKeeper.Borrow(suite.ctx, userAddr, sdk.NewCoins(tc.args.borrow)) // suite.Require().NoError(err) // // Set up chain context at future time // 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.GetHardBorrowRewardPeriods(runCtx, tc.args.borrow.Denom) // suite.Require().True(found) // err = suite.keeper.AccumulateHardBorrowRewards(runCtx, rewardPeriod) // suite.Require().NoError(err) // rewardIndexes, found := suite.keeper.GetHardBorrowRewardIndexes(suite.ctx, tc.args.borrow.Denom) // suite.Require().True(found) // rewardFactor, found := rewardIndexes.GetRewardIndex(types.HardLiquidityRewardDenom) // suite.Require().True(found) // suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) // }) // } // } // func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() { // type args struct { // borrow sdk.Coin // rewardsPerSecond sdk.Coin // initialTime time.Time // blockTimes []int // expectedRewardFactor sdk.Dec // expectedRewards sdk.Coin // } // type test struct { // name string // args args // } // testCases := []test{ // { // "10 blocks", // args{ // borrow: c("bnb", 10000000000), // TODO: 2 decimal diff from TestAccumulateHardBorrowRewards's borrow // 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("0.001223540000173228"), // expectedRewards: c("hard", 12235400), // }, // }, // { // "10 blocks - long block time", // args{ // borrow: c("bnb", 10000000000), // 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("10.571385603126235340"), // expectedRewards: c("hard", 105713856031), // }, // }, // } // 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)}, // types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, // types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(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)}, // 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) // defaultRewardIndexes := types.RewardIndexes{types.NewRewardIndex(types.HardLiquidityRewardDenom, sdk.ZeroDec())} // suite.keeper.SetHardBorrowRewardIndexes(suite.ctx, tc.args.borrow.Denom, defaultRewardIndexes) // // 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) // // 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))))) // suite.Require().NoError(err) // err = 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) // suite.Require().Equal(sdk.ZeroDec(), claim.BorrowRewardIndexes[0].RewardIndexes[0].RewardFactor) // // Run accumulator at several intervals // var timeElapsed int // previousBlockTime := suite.ctx.BlockTime() // for _, t := range tc.args.blockTimes { // timeElapsed += t // updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t)) // 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.GetHardBorrowRewardPeriods(blockCtx, tc.args.borrow.Denom) // suite.Require().True(found) // err := suite.keeper.AccumulateHardBorrowRewards(blockCtx, rewardPeriod) // suite.Require().NoError(err) // } // updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed)) // suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) // // After we've accumulated, run synchronize // borrow, found := hardKeeper.GetBorrow(suite.ctx, suite.addrs[3]) // suite.Require().True(found) // suite.Require().NotPanics(func() { // suite.keeper.SynchronizeHardBorrowReward(suite.ctx, borrow) // }) // // Check that reward factor and claim have been updated as expected // rewardIndexes, found := suite.keeper.GetHardBorrowRewardIndexes(suite.ctx, tc.args.borrow.Denom) // suite.Require().True(found) // rewardFactor, found := rewardIndexes.GetRewardIndex(types.HardLiquidityRewardDenom) // suite.Require().True(found) // suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) // claim, found = suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) // suite.Require().True(found) // suite.Require().Equal(tc.args.expectedRewardFactor, claim.BorrowRewardIndexes[0].RewardIndexes[0].RewardFactor) // suite.Require().Equal(tc.args.expectedRewards, claim.Reward) // }) // } // } // func (suite *KeeperTestSuite) TestAccumulateHardSupplyRewards() { // type args struct { // deposit sdk.Coin // rewardsPerSecond sdk.Coin // initialTime time.Time // timeElapsed int // expectedRewardFactor sdk.Dec // } // type test struct { // name string // args args // } // testCases := []test{ // { // "7 seconds", // args{ // deposit: c("bnb", 1000000000000), // rewardsPerSecond: c("hard", 122354), // initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), // timeElapsed: 7, // expectedRewardFactor: d("0.000000856478000000"), // }, // }, // { // "1 day", // args{ // deposit: c("bnb", 1000000000000), // rewardsPerSecond: c("hard", 122354), // initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), // timeElapsed: 86400, // expectedRewardFactor: d("0.010571385600000000"), // }, // }, // { // "0 seconds", // args{ // deposit: c("bnb", 1000000000000), // rewardsPerSecond: c("hard", 122354), // initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), // timeElapsed: 0, // expectedRewardFactor: d("0.0"), // }, // }, // } // 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)}, // types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(tc.args.rewardsPerSecond))}, // types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(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)}, // 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.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime) // defaultRewardIndexes := types.RewardIndexes{types.NewRewardIndex(types.HardLiquidityRewardDenom, sdk.ZeroDec())} // suite.keeper.SetHardSupplyRewardIndexes(suite.ctx, tc.args.deposit.Denom, defaultRewardIndexes) // // 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) // // 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)) // suite.Require().NoError(err) // // Set up chain context at future time // 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.GetHardSupplyRewardPeriods(runCtx, tc.args.deposit.Denom) // suite.Require().True(found) // err = suite.keeper.AccumulateHardSupplyRewards(runCtx, rewardPeriod) // suite.Require().NoError(err) // rewardIndexes, found := suite.keeper.GetHardSupplyRewardIndexes(suite.ctx, tc.args.deposit.Denom) // suite.Require().True(found) // rewardFactor, found := rewardIndexes.GetRewardIndex(types.HardLiquidityRewardDenom) // suite.Require().True(found) // suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) // }) // } // } // func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() { // type args struct { // deposit sdk.Coin // rewardsPerSecond sdk.Coin // initialTime time.Time // blockTimes []int // expectedRewardFactor sdk.Dec // expectedRewards sdk.Coin // } // type test struct { // name string // args args // } // testCases := []test{ // { // "10 blocks", // args{ // deposit: c("bnb", 10000000000), // TODO: 2 decimal diff // 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("0.001223540000000000"), // expectedRewards: c("hard", 12235400), // }, // }, // { // "10 blocks - long block time", // args{ // deposit: c("bnb", 10000000000), // 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("10.571385600000000000"), // expectedRewards: c("hard", 105713856000), // }, // }, // } // 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.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), cs(tc.args.rewardsPerSecond))}, // types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(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)}, // 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.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime) // defaultRewardIndexes := types.RewardIndexes{types.NewRewardIndex(types.HardLiquidityRewardDenom, sdk.ZeroDec())} // suite.keeper.SetHardSupplyRewardIndexes(suite.ctx, tc.args.deposit.Denom, defaultRewardIndexes) // // 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.SetBorrowInterestFactor(suite.ctx, tc.args.deposit.Denom, sdk.MustNewDecFromStr("1.0")) // suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime) // // 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)) // 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) // suite.Require().Equal(sdk.ZeroDec(), claim.SupplyRewardIndexes[0].RewardIndexes[0].RewardFactor) // // Run accumulator at several intervals // var timeElapsed int // previousBlockTime := suite.ctx.BlockTime() // for _, t := range tc.args.blockTimes { // timeElapsed += t // updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t)) // 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.GetHardSupplyRewardPeriods(blockCtx, tc.args.deposit.Denom) // suite.Require().True(found) // err := suite.keeper.AccumulateHardSupplyRewards(blockCtx, rewardPeriod) // suite.Require().NoError(err) // } // updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed)) // suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) // // After we've accumulated, run synchronize // deposit, found := hardKeeper.GetDeposit(suite.ctx, suite.addrs[3]) // suite.Require().True(found) // suite.Require().NotPanics(func() { // suite.keeper.SynchronizeHardSupplyReward(suite.ctx, deposit) // }) // // Check that reward factor and claim have been updated as expected // rewardIndexes, found := suite.keeper.GetHardBorrowRewardIndexes(suite.ctx, tc.args.deposit.Denom) // suite.Require().True(found) // rewardFactor, found := rewardIndexes.GetRewardIndex(types.HardLiquidityRewardDenom) // suite.Require().True(found) // suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) // claim, found = suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) // suite.Require().True(found) // suite.Require().Equal(tc.args.expectedRewardFactor, claim.SupplyRewardIndexes[0].RewardIndexes[0].RewardFactor) // suite.Require().Equal(tc.args.expectedRewards, claim.Reward) // }) // } // } // func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() { // type args struct { // firstDeposit sdk.Coins // secondDeposit sdk.Coins // rewardsPerSecond sdk.Coin // initialTime time.Time // expectedSupplyIndexDenoms []string // } // type test struct { // name string // args args // } // testCases := []test{ // { // "update adds one supply reward index", // args{ // firstDeposit: cs(c("bnb", 10000000000)), // secondDeposit: cs(c("ukava", 10000000000)), // rewardsPerSecond: c("hard", 122354), // initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), // expectedSupplyIndexDenoms: []string{"bnb", "ukava"}, // }, // }, // { // "update adds multiple supply reward indexes", // args{ // firstDeposit: cs(c("bnb", 10000000000)), // secondDeposit: cs(c("ukava", 10000000000), c("btcb", 10000000000), c("xrp", 10000000000)), // rewardsPerSecond: c("hard", 122354), // initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), // expectedSupplyIndexDenoms: []string{"bnb", "ukava", "btcb", "xrp"}, // }, // }, // { // "update doesn't add duplicate supply reward index for same denom", // args{ // firstDeposit: cs(c("bnb", 10000000000)), // secondDeposit: cs(c("bnb", 5000000000)), // rewardsPerSecond: c("hard", 122354), // initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), // expectedSupplyIndexDenoms: []string{"bnb"}, // }, // }, // } // 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 _, denom := range tc.args.expectedSupplyIndexDenoms { // rewardPeriod := types.NewRewardPeriod(true, denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond) // rewardPeriods = append(rewardPeriods, rewardPeriod) // multiRewardPeriod := types.NewMultiRewardPeriod(true, denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(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), // ) // suite.keeper.SetParams(suite.ctx, params) // // Set each denom's previous accrual time and supply reward factor // defaultRewardIndexes := types.RewardIndexes{types.NewRewardIndex(types.HardLiquidityRewardDenom, sdk.ZeroDec())} // for _, denom := range tc.args.expectedSupplyIndexDenoms { // suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, denom, tc.args.initialTime) // suite.keeper.SetHardSupplyRewardIndexes(suite.ctx, denom, defaultRewardIndexes) // } // // User deposits (first time) // hardKeeper := suite.app.GetHardKeeper() // userAddr := suite.addrs[3] // err := 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]) // suite.Require().True(found) // for _, coin := range tc.args.firstDeposit { // _, hasIndex := claimAfterFirstDeposit.HasSupplyRewardIndex(coin.Denom) // suite.Require().True(hasIndex) // } // suite.Require().True(len(claimAfterFirstDeposit.SupplyRewardIndexes) == len(tc.args.firstDeposit)) // // User deposits (second time) // err = hardKeeper.Deposit(suite.ctx, userAddr, tc.args.secondDeposit) // suite.Require().NoError(err) // // Confirm that the claim contains all expected supply indexes // claimAfterSecondDeposit, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) // suite.Require().True(found) // for _, denom := range tc.args.expectedSupplyIndexDenoms { // _, hasIndex := claimAfterSecondDeposit.HasSupplyRewardIndex(denom) // suite.Require().True(hasIndex) // } // suite.Require().True(len(claimAfterSecondDeposit.SupplyRewardIndexes) == len(tc.args.expectedSupplyIndexDenoms)) // }) // } // } // func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() { // type args struct { // initialDeposit sdk.Coins // firstBorrow sdk.Coins // secondBorrow sdk.Coins // rewardsPerSecond sdk.Coin // initialTime time.Time // expectedBorrowIndexDenoms []string // } // type test struct { // name string // args args // } // testCases := []test{ // { // "update adds one borrow reward index", // args{ // initialDeposit: cs(c("bnb", 10000000000)), // firstBorrow: cs(c("bnb", 50000000)), // secondBorrow: cs(c("ukava", 500000000)), // rewardsPerSecond: c("hard", 122354), // initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), // expectedBorrowIndexDenoms: []string{"bnb", "ukava"}, // }, // }, // { // "update adds multiple borrow supply reward indexes", // args{ // initialDeposit: cs(c("btcb", 10000000000)), // firstBorrow: cs(c("btcb", 50000000)), // secondBorrow: cs(c("ukava", 500000000), c("bnb", 50000000000), c("xrp", 50000000000)), // rewardsPerSecond: c("hard", 122354), // initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), // expectedBorrowIndexDenoms: []string{"btcb", "ukava", "bnb", "xrp"}, // }, // }, // { // "update doesn't add duplicate borrow reward index for same denom", // args{ // initialDeposit: cs(c("bnb", 100000000000)), // firstBorrow: cs(c("bnb", 50000000)), // secondBorrow: cs(c("bnb", 50000000000)), // rewardsPerSecond: c("hard", 122354), // initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), // expectedBorrowIndexDenoms: []string{"bnb"}, // }, // }, // } // 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.secondBorrow...) // supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins) // // Set up generic reward periods // var multiRewardPeriods types.MultiRewardPeriods // var rewardPeriods types.RewardPeriods // for _, denom := range tc.args.expectedBorrowIndexDenoms { // rewardPeriod := types.NewRewardPeriod(true, denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond) // rewardPeriods = append(rewardPeriods, rewardPeriod) // multiRewardPeriod := types.NewMultiRewardPeriod(true, denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), cs(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), // ) // suite.keeper.SetParams(suite.ctx, params) // defaultRewardIndexes := types.RewardIndexes{types.NewRewardIndex(types.HardLiquidityRewardDenom, sdk.ZeroDec())} // // Set each initial deposit denom's previous accrual time and supply reward factor // for _, coin := range tc.args.initialDeposit { // suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, coin.Denom, tc.args.initialTime) // suite.keeper.SetHardSupplyRewardIndexes(suite.ctx, coin.Denom, defaultRewardIndexes) // } // // Set each expected borrow denom's previous accrual time and borrow reward factor // for _, denom := range tc.args.expectedBorrowIndexDenoms { // suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, denom, tc.args.initialTime) // suite.keeper.SetHardBorrowRewardIndexes(suite.ctx, denom, defaultRewardIndexes) // } // // 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) // 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]) // suite.Require().True(found) // suite.Require().Equal(0, len(claimAfterDeposit.BorrowRewardIndexes)) // // User borrows (first time) // err = 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]) // suite.Require().True(found) // for _, coin := range tc.args.firstBorrow { // _, hasIndex := claimAfterFirstBorrow.HasBorrowRewardIndex(coin.Denom) // suite.Require().True(hasIndex) // } // suite.Require().True(len(claimAfterFirstBorrow.BorrowRewardIndexes) == len(tc.args.firstBorrow)) // // User borrows (second time) // err = hardKeeper.Borrow(suite.ctx, userAddr, tc.args.secondBorrow) // suite.Require().NoError(err) // // Confirm that claim's borrow reward indexes contain expected values // claimAfterSecondBorrow, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) // suite.Require().True(found) // for _, coin := range tc.args.secondBorrow { // _, hasIndex := claimAfterSecondBorrow.HasBorrowRewardIndex(coin.Denom) // suite.Require().True(hasIndex) // } // suite.Require().True(len(claimAfterSecondBorrow.BorrowRewardIndexes) == len(tc.args.expectedBorrowIndexDenoms)) // }) // } // } func (suite *KeeperTestSuite) TestAccumulateHardDelegatorRewards() { type args struct { delegation sdk.Coin rewardsPerSecond sdk.Coin initialTime time.Time timeElapsed int expectedRewardFactor sdk.Dec } type test struct { name string args args } testCases := []test{ { "7 seconds", 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"), }, }, { "1 day", 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"), }, }, { "0 seconds", 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"), }, }, } 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.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) err := suite.deliverMsgCreateValidator(suite.ctx, suite.validatorAddrs[0], tc.args.delegation) suite.Require().NoError(err) suite.deliverMsgDelegate(suite.ctx, suite.addrs[0], suite.validatorAddrs[0], tc.args.delegation) suite.Require().NoError(err) staking.EndBlocker(suite.ctx, suite.stakingKeeper) // Set up chain context at future time 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) suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) }) } } // func (suite *KeeperTestSuite) TestSynchronizeHardDelegatorReward() { // type args struct { // delegation sdk.Coin // rewardsPerSecond sdk.Coin // initialTime time.Time // blockTimes []int // expectedRewardFactor sdk.Dec // expectedRewards sdk.Coin // } // type test struct { // name string // args args // } // testCases := []test{ // { // "10 blocks", // 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: c("hard", 6117700), // }, // }, // { // "10 blocks - long block time", // 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: c("hard", 52856928000), // }, // }, // } // 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.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) // // Delegator delegates // err := suite.deliverMsgCreateValidator(suite.ctx, suite.validatorAddrs[0], tc.args.delegation) // suite.Require().NoError(err) // suite.deliverMsgDelegate(suite.ctx, suite.addrs[0], suite.validatorAddrs[0], tc.args.delegation) // suite.Require().NoError(err) // staking.EndBlocker(suite.ctx, suite.stakingKeeper) // // Check that Staking hooks initialized a HardLiquidityProviderClaim // claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[0]) // suite.Require().True(found) // suite.Require().Equal(sdk.ZeroDec(), claim.DelegatorRewardIndexes[0].RewardFactor) // // Run accumulator at several intervals // var timeElapsed int // previousBlockTime := suite.ctx.BlockTime() // for _, t := range tc.args.blockTimes { // timeElapsed += t // updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t)) // 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) // err := suite.keeper.AccumulateHardDelegatorRewards(blockCtx, rewardPeriod) // suite.Require().NoError(err) // } // updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed)) // suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) // // After we've accumulated, run synchronize // suite.Require().NotPanics(func() { // suite.keeper.SynchronizeHardDelegatorRewards(suite.ctx, suite.addrs[0]) // }) // // Check that reward factor and claim have been updated as expected // rewardFactor, found := 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]) // suite.Require().True(found) // suite.Require().Equal(tc.args.expectedRewardFactor, claim.DelegatorRewardIndexes[0].RewardFactor) // suite.Require().Equal(tc.args.expectedRewards, claim.Reward) // }) // } // } func (suite *KeeperTestSuite) TestSimulateHardSupplyRewardSynchronization() { type args struct { deposit sdk.Coin rewardsPerSecond sdk.Coin initialTime time.Time blockTimes []int expectedRewardFactor sdk.Dec expectedRewards sdk.Coin } type test struct { name string args args } testCases := []test{ { "10 blocks", args{ deposit: c("bnb", 10000000000), 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("0.001223540000000000"), expectedRewards: c("hard", 12235400), }, }, { "10 blocks - long block time", args{ deposit: c("bnb", 10000000000), 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("10.571385600000000000"), expectedRewards: c("hard", 105713856000), }, }, } 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.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)}, types.RewardPeriods{types.NewRewardPeriod(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)}, 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.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime) suite.keeper.SetHardSupplyRewardFactor(suite.ctx, tc.args.deposit.Denom, sdk.ZeroDec()) // 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.SetBorrowInterestFactor(suite.ctx, tc.args.deposit.Denom, sdk.MustNewDecFromStr("1.0")) suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime) // 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)) 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) suite.Require().Equal(sdk.ZeroDec(), claim.SupplyRewardIndexes[0].RewardFactor) // Run accumulator at several intervals var timeElapsed int previousBlockTime := suite.ctx.BlockTime() for _, t := range tc.args.blockTimes { timeElapsed += t updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t)) 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.GetHardSupplyRewardPeriod(blockCtx, tc.args.deposit.Denom) suite.Require().True(found) err := suite.keeper.AccumulateHardSupplyRewards(blockCtx, rewardPeriod) suite.Require().NoError(err) } updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed)) suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) claim, found = suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) suite.Require().True(found) suite.Require().Equal(claim.SupplyRewardIndexes[0].RewardFactor, sdk.ZeroDec()) suite.Require().Equal(claim.Reward, sdk.NewCoin("hard", sdk.ZeroInt())) updatedClaim := suite.keeper.SimulateHardSynchronization(suite.ctx, claim) suite.Require().Equal(updatedClaim.SupplyRewardIndexes[0].RewardFactor, tc.args.expectedRewardFactor) suite.Require().Equal(updatedClaim.Reward, tc.args.expectedRewards) }) } } func (suite *KeeperTestSuite) TestSimulateHardBorrowRewardSynchronization() { type args struct { borrow sdk.Coin rewardsPerSecond sdk.Coin initialTime time.Time blockTimes []int expectedRewardFactor sdk.Dec expectedRewards sdk.Coin } type test struct { name string args args } testCases := []test{ { "10 blocks", args{ borrow: c("bnb", 10000000000), 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("0.001223540000173228"), expectedRewards: c("hard", 12235400), }, }, { "10 blocks - long block time", args{ borrow: c("bnb", 10000000000), 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("10.571385603126235340"), expectedRewards: c("hard", 105713856031), }, }, } 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)}, types.RewardPeriods{types.NewRewardPeriod(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)}, types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.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.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, tc.args.borrow.Denom, tc.args.initialTime) suite.keeper.SetHardBorrowRewardFactor(suite.ctx, tc.args.borrow.Denom, sdk.ZeroDec()) // 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) // 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))))) suite.Require().NoError(err) err = 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) suite.Require().Equal(sdk.ZeroDec(), claim.BorrowRewardIndexes[0].RewardFactor) // Run accumulator at several intervals var timeElapsed int previousBlockTime := suite.ctx.BlockTime() for _, t := range tc.args.blockTimes { timeElapsed += t updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t)) 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.GetHardBorrowRewardPeriod(blockCtx, tc.args.borrow.Denom) suite.Require().True(found) err := suite.keeper.AccumulateHardBorrowRewards(blockCtx, rewardPeriod) suite.Require().NoError(err) } updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed)) suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) claim, found = suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3]) suite.Require().True(found) suite.Require().Equal(claim.BorrowRewardIndexes[0].RewardFactor, sdk.ZeroDec()) suite.Require().Equal(claim.Reward, sdk.NewCoin("hard", sdk.ZeroInt())) updatedClaim := suite.keeper.SimulateHardSynchronization(suite.ctx, claim) suite.Require().Equal(updatedClaim.BorrowRewardIndexes[0].RewardFactor, tc.args.expectedRewardFactor) suite.Require().Equal(updatedClaim.Reward, tc.args.expectedRewards) }) } } func (suite *KeeperTestSuite) TestSimulateHardDelegatorRewardSynchronization() { type args struct { delegation sdk.Coin rewardsPerSecond sdk.Coin initialTime time.Time blockTimes []int expectedRewardFactor sdk.Dec expectedRewards sdk.Coin } type test struct { name string args args } testCases := []test{ { "10 blocks", 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: c("hard", 6117700), }, }, { "10 blocks - long block time", 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: c("hard", 52856928000), }, }, } 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.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)}, 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.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) // Delegator delegates err := suite.deliverMsgCreateValidator(suite.ctx, suite.validatorAddrs[0], tc.args.delegation) suite.Require().NoError(err) suite.deliverMsgDelegate(suite.ctx, suite.addrs[0], suite.validatorAddrs[0], tc.args.delegation) suite.Require().NoError(err) staking.EndBlocker(suite.ctx, suite.stakingKeeper) // Check that Staking hooks initialized a HardLiquidityProviderClaim claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[0]) suite.Require().True(found) suite.Require().Equal(sdk.ZeroDec(), claim.DelegatorRewardIndexes[0].RewardFactor) // Run accumulator at several intervals var timeElapsed int previousBlockTime := suite.ctx.BlockTime() for _, t := range tc.args.blockTimes { timeElapsed += t updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t)) 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) err := suite.keeper.AccumulateHardDelegatorRewards(blockCtx, rewardPeriod) suite.Require().NoError(err) } updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed)) suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) claim, found = suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[0]) suite.Require().True(found) suite.Require().Equal(claim.DelegatorRewardIndexes[0].RewardFactor, sdk.ZeroDec()) suite.Require().Equal(claim.Reward, sdk.NewCoin("hard", sdk.ZeroInt())) updatedClaim := suite.keeper.SimulateHardSynchronization(suite.ctx, claim) suite.Require().Equal(updatedClaim.DelegatorRewardIndexes[0].RewardFactor, tc.args.expectedRewardFactor) suite.Require().Equal(updatedClaim.Reward, tc.args.expectedRewards) }) } } func (suite *KeeperTestSuite) TestSimulateUSDXMintingRewardSynchronization() { type args struct { ctype string rewardsPerSecond sdk.Coin initialTime time.Time initialCollateral sdk.Coin initialPrincipal sdk.Coin blockTimes []int expectedRewardFactor sdk.Dec expectedRewards sdk.Coin } type test struct { name string args args } testCases := []test{ { "10 blocks", 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}, expectedRewardFactor: d("0.001223540000000000"), expectedRewards: c("ukava", 12235400), }, }, { "10 blocks - long block time", 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}, expectedRewardFactor: d("10.57138560000000000"), expectedRewards: c("ukava", 105713856000), }, }, } 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.RewardPeriods{types.NewRewardPeriod(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)}, 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)) // setup cdp state cdpKeeper := suite.app.GetCDPKeeper() err := 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]) suite.Require().True(found) suite.Require().Equal(sdk.ZeroDec(), claim.RewardIndexes[0].RewardFactor) var timeElapsed int previousBlockTime := suite.ctx.BlockTime() for _, t := range tc.args.blockTimes { timeElapsed += t updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t)) previousBlockTime = updatedBlockTime blockCtx := suite.ctx.WithBlockTime(updatedBlockTime) rewardPeriod, found := suite.keeper.GetUSDXMintingRewardPeriod(blockCtx, tc.args.ctype) suite.Require().True(found) err := suite.keeper.AccumulateUSDXMintingRewards(blockCtx, rewardPeriod) suite.Require().NoError(err) } updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed)) suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime) claim, found = suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0]) suite.Require().True(found) suite.Require().Equal(claim.RewardIndexes[0].RewardFactor, sdk.ZeroDec()) suite.Require().Equal(claim.Reward, sdk.NewCoin("ukava", sdk.ZeroInt())) updatedClaim := suite.keeper.SimulateUSDXMintingSynchronization(suite.ctx, claim) suite.Require().Equal(tc.args.expectedRewardFactor, updatedClaim.RewardIndexes[0].RewardFactor) suite.Require().Equal(tc.args.expectedRewards, updatedClaim.Reward) }) } } func (suite *KeeperTestSuite) SetupWithGenState() { 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)) } tApp := app.NewTestApp() ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) tApp.InitializeFromGenesisStates( coinsAuthGenState(allAddrs, cs(c("ukava", 5_000_000))), stakingGenesisState(), NewPricefeedGenStateMulti(), NewCDPGenStateMulti(), NewHardGenStateMulti(), ) suite.app = tApp suite.ctx = ctx suite.keeper = tApp.GetIncentiveKeeper() suite.hardKeeper = tApp.GetHardKeeper() suite.stakingKeeper = tApp.GetStakingKeeper() } func coinsAuthGenState(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)), ) } return app.NewAuthGenState(addresses, coinsList) } func stakingGenesisState() app.GenesisState { genState := staking.DefaultGenesisState() genState.Params.BondDenom = "ukava" return app.GenesisState{ staking.ModuleName: staking.ModuleCdc.MustMarshalJSON(genState), } } func (suite *KeeperTestSuite) deliverMsgCreateValidator(ctx sdk.Context, address sdk.ValAddress, selfDelegation sdk.Coin) error { msg := staking.NewMsgCreateValidator( address, ed25519.GenPrivKey().PubKey(), selfDelegation, staking.Description{}, staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), sdk.NewInt(1_000_000), ) handleStakingMsg := staking.NewHandler(suite.stakingKeeper) _, err := handleStakingMsg(ctx, msg) return err } func (suite *KeeperTestSuite) deliverMsgDelegate(ctx sdk.Context, delegator sdk.AccAddress, validator sdk.ValAddress, amount sdk.Coin) error { msg := staking.NewMsgDelegate( delegator, validator, amount, ) handleStakingMsg := staking.NewHandler(suite.stakingKeeper) _, err := handleStakingMsg(ctx, msg) return err }