mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-10-31 21:47:27 +00:00 
			
		
		
		
	Update delegator rewards to multi-reward index (#945)
* update claim attribute type to MultiRewardIndexes * update param attribute type to MultiRewardPeriods * keeper: update params to match types * keeper: update delegator core keeper methods * keeper: update InitializeHardDelegatorReward * keeper: update SynchronizeHardDelegatorRewards * remove reward factor in favor of reward indexes * update querier * fix test: delegator init test * fix test: delegator sync test * implement delegator reward accumulation * fix test: delegator general tests * add legact types, update v0_11 -> v0_14 migration * remove duplicate import form v0_15 migration * implement v0_15incentive migration * test data and migration test * add multiple reward denoms to init/sync tests * update delegator test with multiple reward coins * clean up simulation sync
This commit is contained in:
		
							parent
							
								
									baf17b4ec8
								
							
						
					
					
						commit
						bc33b94822
					
				| @ -23,8 +23,8 @@ import ( | ||||
| 	v0_14committee "github.com/kava-labs/kava/x/committee/legacy/v0_14" | ||||
| 	v0_14hard "github.com/kava-labs/kava/x/hard" | ||||
| 	v0_11hard "github.com/kava-labs/kava/x/hard/legacy/v0_11" | ||||
| 	v0_14incentive "github.com/kava-labs/kava/x/incentive" | ||||
| 	v0_11incentive "github.com/kava-labs/kava/x/incentive/legacy/v0_11" | ||||
| 	v0_14incentive "github.com/kava-labs/kava/x/incentive/legacy/v0_14" | ||||
| 	"github.com/kava-labs/kava/x/kavadist" | ||||
| 	v0_11pricefeed "github.com/kava-labs/kava/x/pricefeed" | ||||
| 	v0_14pricefeed "github.com/kava-labs/kava/x/pricefeed" | ||||
|  | ||||
| @ -24,8 +24,8 @@ import ( | ||||
| 	v0_14committee "github.com/kava-labs/kava/x/committee/legacy/v0_14" | ||||
| 	v0_14hard "github.com/kava-labs/kava/x/hard" | ||||
| 	v0_11hard "github.com/kava-labs/kava/x/hard/legacy/v0_11" | ||||
| 	v0_14incentive "github.com/kava-labs/kava/x/incentive" | ||||
| 	v0_11incentive "github.com/kava-labs/kava/x/incentive/legacy/v0_11" | ||||
| 	v0_14incentive "github.com/kava-labs/kava/x/incentive/legacy/v0_14" | ||||
| 	v0_11pricefeed "github.com/kava-labs/kava/x/pricefeed" | ||||
| 	validatorvesting "github.com/kava-labs/kava/x/validator-vesting" | ||||
| 
 | ||||
|  | ||||
| @ -12,13 +12,16 @@ import ( | ||||
| 
 | ||||
| 	"github.com/kava-labs/kava/app" | ||||
| 	v0_14committee "github.com/kava-labs/kava/x/committee/legacy/v0_14" | ||||
| 	"github.com/kava-labs/kava/x/committee/types" | ||||
| 	v0_15committee "github.com/kava-labs/kava/x/committee/types" | ||||
| 	v0_14incentive "github.com/kava-labs/kava/x/incentive/legacy/v0_14" | ||||
| 	v0_15incentive "github.com/kava-labs/kava/x/incentive/types" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	// TODO: update GenesisTime for kava-8 launch
 | ||||
| 	GenesisTime = time.Date(2021, 4, 8, 15, 0, 0, 0, time.UTC) | ||||
| 	// TODO: update SWP reward per second amount before production
 | ||||
| 	SwpRewardsPerSecond = sdk.NewCoin("swp", sdk.OneInt()) | ||||
| ) | ||||
| 
 | ||||
| // Migrate translates a genesis file from kava v0.14 format to kava v0.15 format
 | ||||
| @ -47,6 +50,15 @@ func Migrate(genDoc tmtypes.GenesisDoc) tmtypes.GenesisDoc { | ||||
| // MigrateAppState migrates application state from v0.14 format to a kava v0.15 format
 | ||||
| func MigrateAppState(v0_14AppState genutil.AppMap) genutil.AppMap { | ||||
| 	v0_15AppState := v0_14AppState | ||||
| 	cdc := app.MakeCodec() | ||||
| 
 | ||||
| 	// Migrate incentive app state
 | ||||
| 	if v0_14AppState[v0_14incentive.ModuleName] != nil { | ||||
| 		var incentiveGenState v0_14incentive.GenesisState | ||||
| 		cdc.MustUnmarshalJSON(v0_14AppState[v0_15incentive.ModuleName], &incentiveGenState) | ||||
| 		delete(v0_14AppState, v0_14incentive.ModuleName) | ||||
| 		v0_15AppState[v0_15incentive.ModuleName] = cdc.MustMarshalJSON(Incentive(incentiveGenState)) | ||||
| 	} | ||||
| 
 | ||||
| 	// Migrate commmittee app state
 | ||||
| 	if v0_14AppState[v0_14committee.ModuleName] != nil { | ||||
| @ -75,7 +87,7 @@ func Committee(genesisState v0_14committee.GenesisState) v0_15committee.GenesisS | ||||
| 	for _, com := range genesisState.Committees { | ||||
| 		if com.ID == 1 { | ||||
| 			// Initialize member committee without permissions
 | ||||
| 			stabilityCom := types.NewMemberCommittee(com.ID, com.Description, com.Members, | ||||
| 			stabilityCom := v0_15committee.NewMemberCommittee(com.ID, com.Description, com.Members, | ||||
| 				[]v0_15committee.Permission{}, com.VoteThreshold, com.ProposalDuration, | ||||
| 				v0_15committee.FirstPastThePost) | ||||
| 
 | ||||
| @ -171,7 +183,7 @@ func Committee(genesisState v0_14committee.GenesisState) v0_15committee.GenesisS | ||||
| 			newStabilityCom := v0_15committee.MemberCommittee{BaseCommittee: baseStabilityCom} | ||||
| 			committees = append(committees, newStabilityCom) | ||||
| 		} else { | ||||
| 			safetyCom := types.NewMemberCommittee(com.ID, com.Description, com.Members, | ||||
| 			safetyCom := v0_15committee.NewMemberCommittee(com.ID, com.Description, com.Members, | ||||
| 				[]v0_15committee.Permission{v0_15committee.SoftwareUpgradePermission{}}, | ||||
| 				com.VoteThreshold, com.ProposalDuration, v0_15committee.FirstPastThePost) | ||||
| 			committees = append(committees, safetyCom) | ||||
| @ -179,7 +191,7 @@ func Committee(genesisState v0_14committee.GenesisState) v0_15committee.GenesisS | ||||
| 	} | ||||
| 
 | ||||
| 	for _, v := range genesisState.Votes { | ||||
| 		newVote := v0_15committee.NewVote(v.ProposalID, v.Voter, types.Yes) | ||||
| 		newVote := v0_15committee.NewVote(v.ProposalID, v.Voter, v0_15committee.Yes) | ||||
| 		votes = append(votes, v0_15committee.Vote(newVote)) | ||||
| 	} | ||||
| 
 | ||||
| @ -191,3 +203,141 @@ func Committee(genesisState v0_14committee.GenesisState) v0_15committee.GenesisS | ||||
| 	return v0_15committee.NewGenesisState( | ||||
| 		genesisState.NextProposalID, committees, proposals, votes) | ||||
| } | ||||
| 
 | ||||
| // Incentive migrates from a v0.14 incentive genesis state to a v0.15 incentive genesis state
 | ||||
| func Incentive(incentiveGS v0_14incentive.GenesisState) v0_15incentive.GenesisState { | ||||
| 	// Migrate params
 | ||||
| 	var claimMultipliers v0_15incentive.Multipliers | ||||
| 	for _, m := range incentiveGS.Params.ClaimMultipliers { | ||||
| 		newMultiplier := v0_15incentive.NewMultiplier(v0_15incentive.MultiplierName(m.Name), m.MonthsLockup, m.Factor) | ||||
| 		claimMultipliers = append(claimMultipliers, newMultiplier) | ||||
| 	} | ||||
| 
 | ||||
| 	var usdxMintingRewardPeriods v0_15incentive.RewardPeriods | ||||
| 	for _, rp := range incentiveGS.Params.USDXMintingRewardPeriods { | ||||
| 		usdxMintingRewardPeriod := v0_15incentive.NewRewardPeriod(rp.Active, | ||||
| 			rp.CollateralType, rp.Start, rp.End, rp.RewardsPerSecond) | ||||
| 		usdxMintingRewardPeriods = append(usdxMintingRewardPeriods, usdxMintingRewardPeriod) | ||||
| 	} | ||||
| 
 | ||||
| 	var hardSupplyRewardPeriods v0_15incentive.MultiRewardPeriods | ||||
| 	for _, rp := range incentiveGS.Params.HardSupplyRewardPeriods { | ||||
| 		hardSupplyRewardPeriod := v0_15incentive.NewMultiRewardPeriod(rp.Active, | ||||
| 			rp.CollateralType, rp.Start, rp.End, rp.RewardsPerSecond) | ||||
| 		hardSupplyRewardPeriods = append(hardSupplyRewardPeriods, hardSupplyRewardPeriod) | ||||
| 	} | ||||
| 
 | ||||
| 	var hardBorrowRewardPeriods v0_15incentive.MultiRewardPeriods | ||||
| 	for _, rp := range incentiveGS.Params.HardBorrowRewardPeriods { | ||||
| 		hardBorrowRewardPeriod := v0_15incentive.NewMultiRewardPeriod(rp.Active, | ||||
| 			rp.CollateralType, rp.Start, rp.End, rp.RewardsPerSecond) | ||||
| 		hardBorrowRewardPeriods = append(hardBorrowRewardPeriods, hardBorrowRewardPeriod) | ||||
| 	} | ||||
| 
 | ||||
| 	var hardDelegatorRewardPeriods v0_15incentive.MultiRewardPeriods | ||||
| 	for _, rp := range incentiveGS.Params.HardDelegatorRewardPeriods { | ||||
| 		rewardsPerSecond := sdk.NewCoins(rp.RewardsPerSecond, SwpRewardsPerSecond) | ||||
| 		hardDelegatorRewardPeriod := v0_15incentive.NewMultiRewardPeriod(rp.Active, | ||||
| 			rp.CollateralType, rp.Start, rp.End, rewardsPerSecond) | ||||
| 		hardDelegatorRewardPeriods = append(hardDelegatorRewardPeriods, hardDelegatorRewardPeriod) | ||||
| 	} | ||||
| 
 | ||||
| 	// Build new params from migrated values
 | ||||
| 	params := v0_15incentive.NewParams( | ||||
| 		usdxMintingRewardPeriods, | ||||
| 		hardSupplyRewardPeriods, | ||||
| 		hardBorrowRewardPeriods, | ||||
| 		hardDelegatorRewardPeriods, | ||||
| 		claimMultipliers, | ||||
| 		incentiveGS.Params.ClaimEnd, | ||||
| 	) | ||||
| 
 | ||||
| 	// Migrate accumulation times
 | ||||
| 	var usdxAccumulationTimes v0_15incentive.GenesisAccumulationTimes | ||||
| 	for _, t := range incentiveGS.USDXAccumulationTimes { | ||||
| 		newAccumulationTime := v0_15incentive.NewGenesisAccumulationTime(t.CollateralType, t.PreviousAccumulationTime) | ||||
| 		usdxAccumulationTimes = append(usdxAccumulationTimes, newAccumulationTime) | ||||
| 	} | ||||
| 
 | ||||
| 	var hardSupplyAccumulationTimes v0_15incentive.GenesisAccumulationTimes | ||||
| 	for _, t := range incentiveGS.HardSupplyAccumulationTimes { | ||||
| 		newAccumulationTime := v0_15incentive.NewGenesisAccumulationTime(t.CollateralType, t.PreviousAccumulationTime) | ||||
| 		hardSupplyAccumulationTimes = append(hardSupplyAccumulationTimes, newAccumulationTime) | ||||
| 	} | ||||
| 
 | ||||
| 	var hardBorrowAccumulationTimes v0_15incentive.GenesisAccumulationTimes | ||||
| 	for _, t := range incentiveGS.HardBorrowAccumulationTimes { | ||||
| 		newAccumulationTime := v0_15incentive.NewGenesisAccumulationTime(t.CollateralType, t.PreviousAccumulationTime) | ||||
| 		hardBorrowAccumulationTimes = append(hardBorrowAccumulationTimes, newAccumulationTime) | ||||
| 	} | ||||
| 
 | ||||
| 	var hardDelegatorAccumulationTimes v0_15incentive.GenesisAccumulationTimes | ||||
| 	for _, t := range incentiveGS.HardDelegatorAccumulationTimes { | ||||
| 		newAccumulationTime := v0_15incentive.NewGenesisAccumulationTime(t.CollateralType, t.PreviousAccumulationTime) | ||||
| 		hardDelegatorAccumulationTimes = append(hardDelegatorAccumulationTimes, newAccumulationTime) | ||||
| 	} | ||||
| 
 | ||||
| 	// Migrate USDX minting claims
 | ||||
| 	var usdxMintingClaims v0_15incentive.USDXMintingClaims | ||||
| 	for _, claim := range incentiveGS.USDXMintingClaims { | ||||
| 		var rewardIndexes v0_15incentive.RewardIndexes | ||||
| 		for _, ri := range claim.RewardIndexes { | ||||
| 			rewardIndex := v0_15incentive.NewRewardIndex(ri.CollateralType, ri.RewardFactor) | ||||
| 			rewardIndexes = append(rewardIndexes, rewardIndex) | ||||
| 		} | ||||
| 		usdxMintingClaim := v0_15incentive.NewUSDXMintingClaim(claim.Owner, claim.Reward, rewardIndexes) | ||||
| 		usdxMintingClaims = append(usdxMintingClaims, usdxMintingClaim) | ||||
| 	} | ||||
| 
 | ||||
| 	// Migrate Hard protocol claims (including delegation rewards)
 | ||||
| 	var hardClaims v0_15incentive.HardLiquidityProviderClaims | ||||
| 	for _, claim := range incentiveGS.HardLiquidityProviderClaims { | ||||
| 		// Migrate supply multi reward indexes
 | ||||
| 		var supplyMultiRewardIndexes v0_15incentive.MultiRewardIndexes | ||||
| 		for _, sri := range claim.SupplyRewardIndexes { | ||||
| 			var rewardIndexes v0_15incentive.RewardIndexes | ||||
| 			for _, ri := range sri.RewardIndexes { | ||||
| 				rewardIndex := v0_15incentive.NewRewardIndex(ri.CollateralType, ri.RewardFactor) | ||||
| 				rewardIndexes = append(rewardIndexes, rewardIndex) | ||||
| 			} | ||||
| 			supplyMultiRewardIndex := v0_15incentive.NewMultiRewardIndex(sri.CollateralType, rewardIndexes) | ||||
| 			supplyMultiRewardIndexes = append(supplyMultiRewardIndexes, supplyMultiRewardIndex) | ||||
| 		} | ||||
| 
 | ||||
| 		// Migrate borrow multi reward indexes
 | ||||
| 		var borrowMultiRewardIndexes v0_15incentive.MultiRewardIndexes | ||||
| 		for _, bri := range claim.BorrowRewardIndexes { | ||||
| 			var rewardIndexes v0_15incentive.RewardIndexes | ||||
| 			for _, ri := range bri.RewardIndexes { | ||||
| 				rewardIndex := v0_15incentive.NewRewardIndex(ri.CollateralType, ri.RewardFactor) | ||||
| 				rewardIndexes = append(rewardIndexes, rewardIndex) | ||||
| 			} | ||||
| 			borrowMultiRewardIndex := v0_15incentive.NewMultiRewardIndex(bri.CollateralType, rewardIndexes) | ||||
| 			borrowMultiRewardIndexes = append(borrowMultiRewardIndexes, borrowMultiRewardIndex) | ||||
| 		} | ||||
| 
 | ||||
| 		// Migrate delegator reward indexes to multi reward indexes under BondDenom
 | ||||
| 		var delegatorMultiRewardIndexes v0_15incentive.MultiRewardIndexes | ||||
| 		var delegatorRewardIndexes v0_15incentive.RewardIndexes | ||||
| 		for _, ri := range claim.DelegatorRewardIndexes { | ||||
| 			delegatorRewardIndex := v0_15incentive.NewRewardIndex(ri.CollateralType, ri.RewardFactor) | ||||
| 			delegatorRewardIndexes = append(delegatorRewardIndexes, delegatorRewardIndex) | ||||
| 		} | ||||
| 		delegatorMultiRewardIndex := v0_15incentive.NewMultiRewardIndex(v0_15incentive.BondDenom, delegatorRewardIndexes) | ||||
| 		delegatorMultiRewardIndexes = append(delegatorMultiRewardIndexes, delegatorMultiRewardIndex) | ||||
| 
 | ||||
| 		hardClaim := v0_15incentive.NewHardLiquidityProviderClaim(claim.Owner, claim.Reward, | ||||
| 			supplyMultiRewardIndexes, borrowMultiRewardIndexes, delegatorMultiRewardIndexes) | ||||
| 		hardClaims = append(hardClaims, hardClaim) | ||||
| 	} | ||||
| 
 | ||||
| 	return v0_15incentive.NewGenesisState( | ||||
| 		params, | ||||
| 		usdxAccumulationTimes, | ||||
| 		hardSupplyAccumulationTimes, | ||||
| 		hardBorrowAccumulationTimes, | ||||
| 		hardDelegatorAccumulationTimes, | ||||
| 		usdxMintingClaims, | ||||
| 		hardClaims, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| @ -12,7 +12,8 @@ import ( | ||||
| 	"github.com/kava-labs/kava/app" | ||||
| 	v0_14committee "github.com/kava-labs/kava/x/committee/legacy/v0_14" | ||||
| 	v0_15committee "github.com/kava-labs/kava/x/committee/types" | ||||
| 
 | ||||
| 	v0_14incentive "github.com/kava-labs/kava/x/incentive/legacy/v0_14" | ||||
| 	v0_15incentive "github.com/kava-labs/kava/x/incentive/types" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
| 
 | ||||
| @ -54,3 +55,23 @@ func TestCommittee(t *testing.T) { | ||||
| 	require.Equal(t, len(oldSPCP.AllowedMarkets), len(newSPCP.AllowedMarkets)) | ||||
| 	require.Equal(t, len(oldSPCP.AllowedMoneyMarkets), len(newSPCP.AllowedMoneyMarkets)) | ||||
| } | ||||
| 
 | ||||
| func TestIncentive(t *testing.T) { | ||||
| 	bz, err := ioutil.ReadFile(filepath.Join("testdata", "kava-7-incentive-state.json")) | ||||
| 	require.NoError(t, err) | ||||
| 	var oldIncentiveGenState v0_14incentive.GenesisState | ||||
| 	cdc := app.MakeCodec() | ||||
| 	require.NotPanics(t, func() { | ||||
| 		cdc.MustUnmarshalJSON(bz, &oldIncentiveGenState) | ||||
| 	}) | ||||
| 
 | ||||
| 	newGenState := v0_15incentive.GenesisState{} | ||||
| 	require.NotPanics(t, func() { | ||||
| 		newGenState = Incentive(oldIncentiveGenState) | ||||
| 	}) | ||||
| 	err = newGenState.Validate() | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	require.Equal(t, len(oldIncentiveGenState.USDXMintingClaims), len(newGenState.USDXMintingClaims)) | ||||
| 	require.Equal(t, len(oldIncentiveGenState.HardLiquidityProviderClaims), len(newGenState.HardLiquidityProviderClaims)) | ||||
| } | ||||
|  | ||||
							
								
								
									
										1
									
								
								migrate/v0_15/testdata/kava-7-incentive-state.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								migrate/v0_15/testdata/kava-7-incentive-state.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -104,7 +104,7 @@ var ( | ||||
| 	PreviousHardSupplyRewardAccrualTimeKeyPrefix    = types.PreviousHardSupplyRewardAccrualTimeKeyPrefix | ||||
| 	HardBorrowRewardIndexesKeyPrefix                = types.HardBorrowRewardIndexesKeyPrefix | ||||
| 	PreviousHardBorrowRewardAccrualTimeKeyPrefix    = types.PreviousHardBorrowRewardAccrualTimeKeyPrefix | ||||
| 	HardDelegatorRewardFactorKeyPrefix              = types.HardDelegatorRewardFactorKeyPrefix | ||||
| 	HardDelegatorRewardIndexesKeyPrefix             = types.HardDelegatorRewardIndexesKeyPrefix | ||||
| 	PreviousHardDelegatorRewardAccrualTimeKeyPrefix = types.PreviousHardDelegatorRewardAccrualTimeKeyPrefix | ||||
| 	USDXMintingRewardDenom                          = types.USDXMintingRewardDenom | ||||
| 	HardLiquidityRewardDenom                        = types.HardLiquidityRewardDenom | ||||
|  | ||||
| @ -48,8 +48,13 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, supplyKeeper types.SupplyKeep | ||||
| 		k.SetHardBorrowRewardIndexes(ctx, mrp.CollateralType, newRewardIndexes) | ||||
| 	} | ||||
| 
 | ||||
| 	for _, rp := range gs.Params.HardDelegatorRewardPeriods { | ||||
| 		k.SetHardDelegatorRewardFactor(ctx, rp.CollateralType, sdk.ZeroDec()) | ||||
| 	for _, drp := range gs.Params.HardDelegatorRewardPeriods { | ||||
| 		newRewardIndexes := types.RewardIndexes{} | ||||
| 		for _, rc := range drp.RewardsPerSecond { | ||||
| 			ri := types.NewRewardIndex(rc.Denom, sdk.ZeroDec()) | ||||
| 			newRewardIndexes = append(newRewardIndexes, ri) | ||||
| 		} | ||||
| 		k.SetHardDelegatorRewardIndexes(ctx, drp.CollateralType, newRewardIndexes) | ||||
| 	} | ||||
| 
 | ||||
| 	k.SetParams(ctx, gs.Params) | ||||
| @ -94,9 +99,11 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, supplyKeeper types.SupplyKeep | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		for j, ri := range claim.DelegatorRewardIndexes { | ||||
| 			if ri.RewardFactor != sdk.ZeroDec() { | ||||
| 				gs.HardLiquidityProviderClaims[i].DelegatorRewardIndexes[j].RewardFactor = sdk.ZeroDec() | ||||
| 		for j, dri := range claim.DelegatorRewardIndexes { | ||||
| 			for k, ri := range dri.RewardIndexes { | ||||
| 				if ri.RewardFactor != sdk.ZeroDec() { | ||||
| 					gs.HardLiquidityProviderClaims[i].DelegatorRewardIndexes[j].RewardIndexes[k].RewardFactor = sdk.ZeroDec() | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		k.SetHardLiquidityProviderClaim(ctx, claim) | ||||
| @ -140,8 +147,10 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState { | ||||
| 				claim.SupplyRewardIndexes[i].RewardIndexes[j].RewardFactor = sdk.ZeroDec() | ||||
| 			} | ||||
| 		} | ||||
| 		for i := range claim.DelegatorRewardIndexes { | ||||
| 			claim.DelegatorRewardIndexes[i].RewardFactor = sdk.ZeroDec() | ||||
| 		for i, dri := range claim.DelegatorRewardIndexes { | ||||
| 			for j := range dri.RewardIndexes { | ||||
| 				claim.DelegatorRewardIndexes[i].RewardIndexes[j].RewardFactor = sdk.ZeroDec() | ||||
| 			} | ||||
| 		} | ||||
| 		synchronizedHardClaims = append(synchronizedHardClaims, claim) | ||||
| 	} | ||||
|  | ||||
| @ -64,8 +64,7 @@ func (suite *GenesisTestSuite) SetupTest() { | ||||
| 			incentive.RewardPeriods{incentive.NewRewardPeriod(true, "bnb-a", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), c("ukava", 122354))}, | ||||
| 			incentive.MultiRewardPeriods{incentive.NewMultiRewardPeriod(true, "bnb", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("hard", 122354)))}, | ||||
| 			incentive.MultiRewardPeriods{incentive.NewMultiRewardPeriod(true, "bnb", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("hard", 122354)))}, | ||||
| 			incentive.RewardPeriods{incentive.NewRewardPeriod(true, "ukava", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), c("hard", 122354))}, | ||||
| 			incentive.Multipliers{incentive.NewMultiplier(incentive.Small, 1, d("0.25")), incentive.NewMultiplier(incentive.Large, 12, d("1.0"))}, | ||||
| 			incentive.MultiRewardPeriods{incentive.NewMultiRewardPeriod(true, "ukava", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("hard", 122354)))}, incentive.Multipliers{incentive.NewMultiplier(incentive.Small, 1, d("0.25")), incentive.NewMultiplier(incentive.Large, 12, d("1.0"))}, | ||||
| 			suite.genesisTime.Add(5*oneYear), | ||||
| 		), | ||||
| 		incentive.DefaultGenesisAccumulationTimes, | ||||
|  | ||||
| @ -47,7 +47,7 @@ func (suite *HandlerTestSuite) SetupTest() { | ||||
| 			incentive.RewardPeriods{incentive.NewRewardPeriod(true, "bnb-a", time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 12, 15, 14, 0, 0, 0, time.UTC), c("ukava", 122354))}, | ||||
| 			incentive.MultiRewardPeriods{incentive.NewMultiRewardPeriod(true, "bnb-a", time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 12, 15, 14, 0, 0, 0, time.UTC), cs(c("ukava", 122354)))}, | ||||
| 			incentive.MultiRewardPeriods{incentive.NewMultiRewardPeriod(true, "bnb-a", time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 12, 15, 14, 0, 0, 0, time.UTC), cs(c("ukava", 122354)))}, | ||||
| 			incentive.RewardPeriods{incentive.NewRewardPeriod(true, "bnb-a", time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 12, 15, 14, 0, 0, 0, time.UTC), c("ukava", 122354))}, | ||||
| 			incentive.MultiRewardPeriods{incentive.NewMultiRewardPeriod(true, "bnb-a", time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 12, 15, 14, 0, 0, 0, time.UTC), cs(c("ukava", 122354)))}, | ||||
| 			incentive.Multipliers{incentive.NewMultiplier(incentive.MultiplierName("small"), 1, d("0.25")), incentive.NewMultiplier(incentive.MultiplierName("large"), 12, d("1.0"))}, | ||||
| 			time.Date(2025, 12, 15, 14, 0, 0, 0, time.UTC), | ||||
| 		), | ||||
| @ -88,10 +88,9 @@ func (suite *HandlerTestSuite) addHardLiquidityProviderClaim() { | ||||
| 	err := sk.MintCoins(suite.ctx, kavadist.ModuleName, cs(c("ukava", 1000000000000))) | ||||
| 	suite.Require().NoError(err) | ||||
| 	rewardPeriod := types.RewardIndexes{types.NewRewardIndex("bnb-s", sdk.ZeroDec())} | ||||
| 
 | ||||
| 	multiRewardIndex := types.NewMultiRewardIndex("bnb-s", rewardPeriod) | ||||
| 	multiRewardIndexes := types.MultiRewardIndexes{multiRewardIndex} | ||||
| 	c1 := incentive.NewHardLiquidityProviderClaim(suite.addrs[0], cs(c("ukava", 1000000)), multiRewardIndexes, multiRewardIndexes, rewardPeriod) | ||||
| 	c1 := incentive.NewHardLiquidityProviderClaim(suite.addrs[0], cs(c("ukava", 1000000)), multiRewardIndexes, multiRewardIndexes, multiRewardIndexes) | ||||
| 	suite.NotPanics(func() { | ||||
| 		suite.keeper.SetHardLiquidityProviderClaim(suite.ctx, c1) | ||||
| 	}) | ||||
|  | ||||
| @ -157,7 +157,7 @@ func NewIncentiveGenState(previousAccumTime, endTime time.Time, rewardPeriods .. | ||||
| 			rewardPeriods, | ||||
| 			types.MultiRewardPeriods{}, | ||||
| 			types.MultiRewardPeriods{}, | ||||
| 			types.RewardPeriods{}, | ||||
| 			types.MultiRewardPeriods{}, | ||||
| 			incentive.Multipliers{ | ||||
| 				incentive.NewMultiplier(incentive.Small, 1, d("0.25")), | ||||
| 				incentive.NewMultiplier(incentive.Large, 12, d("1.0")), | ||||
|  | ||||
| @ -278,7 +278,7 @@ func (builder IncentiveGenesisBuilder) WithSimpleSupplyRewardPeriod(ctype string | ||||
| 		rewardsPerSecond, | ||||
| 	)) | ||||
| } | ||||
| func (builder IncentiveGenesisBuilder) WithInitializedDelegatorRewardPeriod(period types.RewardPeriod) IncentiveGenesisBuilder { | ||||
| func (builder IncentiveGenesisBuilder) WithInitializedDelegatorRewardPeriod(period types.MultiRewardPeriod) IncentiveGenesisBuilder { | ||||
| 	builder.Params.HardDelegatorRewardPeriods = append(builder.Params.HardDelegatorRewardPeriods, period) | ||||
| 
 | ||||
| 	accumulationTimeForPeriod := types.NewGenesisAccumulationTime(period.CollateralType, builder.genesisTime) | ||||
| @ -286,8 +286,8 @@ func (builder IncentiveGenesisBuilder) WithInitializedDelegatorRewardPeriod(peri | ||||
| 	return builder | ||||
| } | ||||
| 
 | ||||
| func (builder IncentiveGenesisBuilder) WithSimpleDelegatorRewardPeriod(ctype string, rewardsPerSecond sdk.Coin) IncentiveGenesisBuilder { | ||||
| 	return builder.WithInitializedDelegatorRewardPeriod(types.NewRewardPeriod( | ||||
| func (builder IncentiveGenesisBuilder) WithSimpleDelegatorRewardPeriod(ctype string, rewardsPerSecond sdk.Coins) IncentiveGenesisBuilder { | ||||
| 	return builder.WithInitializedDelegatorRewardPeriod(types.NewMultiRewardPeriod( | ||||
| 		true, | ||||
| 		ctype, | ||||
| 		builder.genesisTime, | ||||
|  | ||||
| @ -273,32 +273,34 @@ func (k Keeper) IterateHardBorrowRewardIndexes(ctx sdk.Context, cb func(denom st | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // GetHardDelegatorRewardFactor returns the current reward factor for an individual collateral type
 | ||||
| func (k Keeper) GetHardDelegatorRewardFactor(ctx sdk.Context, ctype string) (factor sdk.Dec, found bool) { | ||||
| 	store := prefix.NewStore(ctx.KVStore(k.key), types.HardDelegatorRewardFactorKeyPrefix) | ||||
| 	bz := store.Get([]byte(ctype)) | ||||
| // GetHardDelegatorRewardIndexes gets the current reward indexes for an individual denom
 | ||||
| func (k Keeper) GetHardDelegatorRewardIndexes(ctx sdk.Context, denom string) (types.RewardIndexes, bool) { | ||||
| 	store := prefix.NewStore(ctx.KVStore(k.key), types.HardDelegatorRewardIndexesKeyPrefix) | ||||
| 	bz := store.Get([]byte(denom)) | ||||
| 	if bz == nil { | ||||
| 		return sdk.ZeroDec(), false | ||||
| 		return types.RewardIndexes{}, false | ||||
| 	} | ||||
| 	k.cdc.MustUnmarshalBinaryBare(bz, &factor) | ||||
| 	return factor, true | ||||
| 	var rewardIndexes types.RewardIndexes | ||||
| 	k.cdc.MustUnmarshalBinaryBare(bz, &rewardIndexes) | ||||
| 	return rewardIndexes, true | ||||
| } | ||||
| 
 | ||||
| // SetHardDelegatorRewardFactor sets the current reward factor for an individual collateral type
 | ||||
| func (k Keeper) SetHardDelegatorRewardFactor(ctx sdk.Context, ctype string, factor sdk.Dec) { | ||||
| 	store := prefix.NewStore(ctx.KVStore(k.key), types.HardDelegatorRewardFactorKeyPrefix) | ||||
| 	store.Set([]byte(ctype), k.cdc.MustMarshalBinaryBare(factor)) | ||||
| // SetHardDelegatorRewardIndexes sets the current reward indexes for an individual denom
 | ||||
| func (k Keeper) SetHardDelegatorRewardIndexes(ctx sdk.Context, denom string, indexes types.RewardIndexes) { | ||||
| 	store := prefix.NewStore(ctx.KVStore(k.key), types.HardDelegatorRewardIndexesKeyPrefix) | ||||
| 	bz := k.cdc.MustMarshalBinaryBare(indexes) | ||||
| 	store.Set([]byte(denom), bz) | ||||
| } | ||||
| 
 | ||||
| // IterateHardDelegatorRewardFactors iterates over all Hard delegator reward factor objects in the store and preforms a callback function
 | ||||
| func (k Keeper) IterateHardDelegatorRewardFactors(ctx sdk.Context, cb func(denom string, factor sdk.Dec) (stop bool)) { | ||||
| 	store := prefix.NewStore(ctx.KVStore(k.key), types.HardDelegatorRewardFactorKeyPrefix) | ||||
| // IterateHardDelegatorRewardIndexes iterates over all Delegator reward index objects in the store and preforms a callback function
 | ||||
| func (k Keeper) IterateHardDelegatorRewardIndexes(ctx sdk.Context, cb func(denom string, indexes types.RewardIndexes) (stop bool)) { | ||||
| 	store := prefix.NewStore(ctx.KVStore(k.key), types.HardDelegatorRewardIndexesKeyPrefix) | ||||
| 	iterator := sdk.KVStorePrefixIterator(store, []byte{}) | ||||
| 	defer iterator.Close() | ||||
| 	for ; iterator.Valid(); iterator.Next() { | ||||
| 		var factor sdk.Dec | ||||
| 		k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &factor) | ||||
| 		if cb(string(iterator.Key()), factor) { | ||||
| 		var indexes types.RewardIndexes | ||||
| 		k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &indexes) | ||||
| 		if cb(string(iterator.Key()), indexes) { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -54,14 +54,14 @@ func (k Keeper) GetHardBorrowRewardPeriods(ctx sdk.Context, denom string) (types | ||||
| } | ||||
| 
 | ||||
| // GetHardDelegatorRewardPeriod returns the reward period with the specified collateral type if it's found in the params
 | ||||
| func (k Keeper) GetHardDelegatorRewardPeriod(ctx sdk.Context, denom string) (types.RewardPeriod, bool) { | ||||
| func (k Keeper) GetHardDelegatorRewardPeriods(ctx sdk.Context, denom string) (types.MultiRewardPeriod, bool) { | ||||
| 	params := k.GetParams(ctx) | ||||
| 	for _, rp := range params.HardDelegatorRewardPeriods { | ||||
| 		if rp.CollateralType == denom { | ||||
| 			return rp, true | ||||
| 		} | ||||
| 	} | ||||
| 	return types.RewardPeriod{}, false | ||||
| 	return types.MultiRewardPeriod{}, false | ||||
| } | ||||
| 
 | ||||
| // GetMultiplier returns the multiplier with the specified name if it's found in the params
 | ||||
|  | ||||
| @ -223,9 +223,9 @@ func queryGetRewardFactors(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([] | ||||
| 		if found { | ||||
| 			rewardFactor.HardBorrowRewardFactors = hardBorrowRewardIndexes | ||||
| 		} | ||||
| 		hardDelegatorRewardFactor, found := k.GetHardDelegatorRewardFactor(ctx, params.Denom) | ||||
| 		hardDelegatorRewardIndexes, found := k.GetHardDelegatorRewardIndexes(ctx, params.Denom) | ||||
| 		if found { | ||||
| 			rewardFactor.HardDelegatorRewardFactor = hardDelegatorRewardFactor | ||||
| 			rewardFactor.HardDelegatorRewardFactors = hardDelegatorRewardIndexes | ||||
| 		} | ||||
| 		rewardFactors = append(rewardFactors, rewardFactor) | ||||
| 	} else { | ||||
| @ -263,12 +263,12 @@ func queryGetRewardFactors(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([] | ||||
| 		}) | ||||
| 
 | ||||
| 		// Populate mapping with Hard delegator reward factors
 | ||||
| 		k.IterateHardDelegatorRewardFactors(ctx, func(denom string, factor sdk.Dec) (stop bool) { | ||||
| 		k.IterateHardDelegatorRewardIndexes(ctx, func(denom string, indexes types.RewardIndexes) (stop bool) { | ||||
| 			rewardFactor, ok := rewardFactorMap[denom] | ||||
| 			if !ok { | ||||
| 				rewardFactor = types.RewardFactor{Denom: denom, HardDelegatorRewardFactor: factor} | ||||
| 				rewardFactor = types.RewardFactor{Denom: denom, HardDelegatorRewardFactors: indexes} | ||||
| 			} else { | ||||
| 				rewardFactor.HardDelegatorRewardFactor = factor | ||||
| 				rewardFactor.HardDelegatorRewardFactors = indexes | ||||
| 			} | ||||
| 			rewardFactorMap[denom] = rewardFactor | ||||
| 			return false | ||||
|  | ||||
| @ -9,37 +9,57 @@ import ( | ||||
| ) | ||||
| 
 | ||||
| // AccumulateHardDelegatorRewards updates the rewards accumulated for the input reward period
 | ||||
| func (k Keeper) AccumulateHardDelegatorRewards(ctx sdk.Context, rewardPeriod types.RewardPeriod) error { | ||||
| 	previousAccrualTime, found := k.GetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriod.CollateralType) | ||||
| func (k Keeper) AccumulateHardDelegatorRewards(ctx sdk.Context, rewardPeriods types.MultiRewardPeriod) error { | ||||
| 	previousAccrualTime, found := k.GetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriods.CollateralType) | ||||
| 	if !found { | ||||
| 		k.SetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime()) | ||||
| 		k.SetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriods.CollateralType, ctx.BlockTime()) | ||||
| 		return nil | ||||
| 	} | ||||
| 	timeElapsed := CalculateTimeElapsed(rewardPeriod.Start, rewardPeriod.End, ctx.BlockTime(), previousAccrualTime) | ||||
| 	timeElapsed := CalculateTimeElapsed(rewardPeriods.Start, rewardPeriods.End, ctx.BlockTime(), previousAccrualTime) | ||||
| 	if timeElapsed.IsZero() { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if rewardPeriod.RewardsPerSecond.Amount.IsZero() { | ||||
| 		k.SetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime()) | ||||
| 	if rewardPeriods.RewardsPerSecond.IsZero() { | ||||
| 		k.SetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriods.CollateralType, ctx.BlockTime()) | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	totalBonded := k.stakingKeeper.TotalBondedTokens(ctx).ToDec() | ||||
| 	if totalBonded.IsZero() { | ||||
| 		k.SetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime()) | ||||
| 		k.SetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriods.CollateralType, ctx.BlockTime()) | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	newRewards := timeElapsed.Mul(rewardPeriod.RewardsPerSecond.Amount) | ||||
| 	rewardFactor := newRewards.ToDec().Quo(totalBonded) | ||||
| 
 | ||||
| 	previousRewardFactor, found := k.GetHardDelegatorRewardFactor(ctx, rewardPeriod.CollateralType) | ||||
| 	previousRewardIndexes, found := k.GetHardDelegatorRewardIndexes(ctx, rewardPeriods.CollateralType) | ||||
| 	if !found { | ||||
| 		previousRewardFactor = sdk.ZeroDec() | ||||
| 		for _, rewardCoin := range rewardPeriods.RewardsPerSecond { | ||||
| 			rewardIndex := types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) | ||||
| 			previousRewardIndexes = append(previousRewardIndexes, rewardIndex) | ||||
| 		} | ||||
| 		k.SetHardDelegatorRewardIndexes(ctx, rewardPeriods.CollateralType, previousRewardIndexes) | ||||
| 	} | ||||
| 	newRewardFactor := previousRewardFactor.Add(rewardFactor) | ||||
| 	k.SetHardDelegatorRewardFactor(ctx, rewardPeriod.CollateralType, newRewardFactor) | ||||
| 	k.SetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime()) | ||||
| 
 | ||||
| 	newRewardIndexes := previousRewardIndexes | ||||
| 	for _, rewardCoin := range rewardPeriods.RewardsPerSecond { | ||||
| 		newRewards := rewardCoin.Amount.ToDec().Mul(timeElapsed.ToDec()) | ||||
| 		previousRewardIndex, found := previousRewardIndexes.GetRewardIndex(rewardCoin.Denom) | ||||
| 		if !found { | ||||
| 			previousRewardIndex = types.NewRewardIndex(rewardCoin.Denom, sdk.ZeroDec()) | ||||
| 		} | ||||
| 
 | ||||
| 		// Calculate new reward factor and update reward index
 | ||||
| 		rewardFactor := newRewards.Quo(totalBonded) | ||||
| 		newRewardFactorValue := previousRewardIndex.RewardFactor.Add(rewardFactor) | ||||
| 		newRewardIndex := types.NewRewardIndex(rewardCoin.Denom, newRewardFactorValue) | ||||
| 		i, found := newRewardIndexes.GetFactorIndex(rewardCoin.Denom) | ||||
| 		if found { | ||||
| 			newRewardIndexes[i] = newRewardIndex | ||||
| 		} else { | ||||
| 			newRewardIndexes = append(newRewardIndexes, newRewardIndex) | ||||
| 		} | ||||
| 	} | ||||
| 	k.SetHardDelegatorRewardIndexes(ctx, rewardPeriods.CollateralType, newRewardIndexes) | ||||
| 	k.SetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriods.CollateralType, ctx.BlockTime()) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| @ -53,13 +73,14 @@ func (k Keeper) InitializeHardDelegatorReward(ctx sdk.Context, delegator sdk.Acc | ||||
| 		claim, _ = k.GetHardLiquidityProviderClaim(ctx, delegator) | ||||
| 	} | ||||
| 
 | ||||
| 	globalRewardFactor, found := k.GetHardDelegatorRewardFactor(ctx, types.BondDenom) | ||||
| 	var delegatorRewardIndexes types.MultiRewardIndexes | ||||
| 	globalRewardIndexes, found := k.GetHardDelegatorRewardIndexes(ctx, types.BondDenom) | ||||
| 	if !found { | ||||
| 		// If there's no global delegator reward factor, initialize the claim with a delegator factor of zero.
 | ||||
| 		globalRewardFactor = sdk.ZeroDec() | ||||
| 		globalRewardIndexes = types.RewardIndexes{} | ||||
| 	} | ||||
| 	delegatorRewardIndexes = delegatorRewardIndexes.With(types.BondDenom, globalRewardIndexes) | ||||
| 
 | ||||
| 	claim.DelegatorRewardIndexes = types.RewardIndexes{types.NewRewardIndex(types.BondDenom, globalRewardFactor)} | ||||
| 	claim.DelegatorRewardIndexes = delegatorRewardIndexes | ||||
| 	k.SetHardLiquidityProviderClaim(ctx, claim) | ||||
| } | ||||
| 
 | ||||
| @ -72,7 +93,7 @@ func (k Keeper) SynchronizeHardDelegatorRewards(ctx sdk.Context, delegator sdk.A | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	globalRewardFactor, found := k.GetHardDelegatorRewardFactor(ctx, types.BondDenom) | ||||
| 	globalRewardIndexes, found := k.GetHardDelegatorRewardIndexes(ctx, types.BondDenom) | ||||
| 	if !found { | ||||
| 		// The global factor is only not found if
 | ||||
| 		// - the bond denom has not started accumulating rewards yet (either there is no reward specified in params, or the reward start time hasn't been hit)
 | ||||
| @ -83,27 +104,25 @@ func (k Keeper) SynchronizeHardDelegatorRewards(ctx sdk.Context, delegator sdk.A | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	userRewardFactor, found := claim.DelegatorRewardIndexes.Get(types.BondDenom) | ||||
| 	userRewardIndexes, found := claim.DelegatorRewardIndexes.Get(types.BondDenom) | ||||
| 	if !found { | ||||
| 		// Normally the factor should always be found, as it is added in InitializeHardDelegatorReward when a user delegates.
 | ||||
| 		// However if there were no delegator rewards (ie no reward period in params) then a reward period is added, existing claims will not have the factor.
 | ||||
| 		// So assume the factor is the starting value for any global factor: 0.
 | ||||
| 		userRewardFactor = sdk.ZeroDec() | ||||
| 		userRewardIndexes = types.RewardIndexes{} | ||||
| 	} | ||||
| 
 | ||||
| 	totalDelegated := k.GetTotalDelegated(ctx, delegator, valAddr, shouldIncludeValidator) | ||||
| 
 | ||||
| 	rewardsEarned, err := k.CalculateSingleReward(userRewardFactor, globalRewardFactor, totalDelegated) | ||||
| 	rewardsEarned, err := k.CalculateRewards(userRewardIndexes, globalRewardIndexes, totalDelegated) | ||||
| 	if err != nil { | ||||
| 		// Global reward factors should never decrease, as it would lead to a negative update to claim.Rewards.
 | ||||
| 		// This panics if a global reward factor decreases or disappears between the old and new indexes.
 | ||||
| 		panic(fmt.Sprintf("corrupted global reward indexes found: %v", err)) | ||||
| 	} | ||||
| 	newRewardsCoin := sdk.NewCoin(types.HardLiquidityRewardDenom, rewardsEarned) | ||||
| 
 | ||||
| 	claim.Reward = claim.Reward.Add(newRewardsCoin) | ||||
| 	claim.DelegatorRewardIndexes = claim.DelegatorRewardIndexes.With(types.BondDenom, globalRewardFactor) | ||||
| 
 | ||||
| 	claim.Reward = claim.Reward.Add(rewardsEarned...) | ||||
| 	claim.DelegatorRewardIndexes = claim.DelegatorRewardIndexes.With(types.BondDenom, globalRewardIndexes) | ||||
| 	k.SetHardLiquidityProviderClaim(ctx, claim) | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -27,9 +27,10 @@ func TestInitializeHardDelegatorReward(t *testing.T) { | ||||
| 	suite.Run(t, new(InitializeHardDelegatorRewardTests)) | ||||
| } | ||||
| 
 | ||||
| func (suite *InitializeHardDelegatorRewardTests) storeGlobalDelegatorFactor(rewardIndexes types.RewardIndexes) { | ||||
| 	factor := rewardIndexes[0] | ||||
| 	suite.keeper.SetHardDelegatorRewardFactor(suite.ctx, factor.CollateralType, factor.RewardFactor) | ||||
| // Hardcoded to use bond denom
 | ||||
| func (suite *InitializeHardDelegatorRewardTests) storeGlobalDelegatorFactor(multiRewardIndexes types.MultiRewardIndexes) { | ||||
| 	multiRewardIndex, _ := multiRewardIndexes.GetRewardIndex(types.BondDenom) | ||||
| 	suite.keeper.SetHardDelegatorRewardIndexes(suite.ctx, types.BondDenom, multiRewardIndex.RewardIndexes) | ||||
| } | ||||
| 
 | ||||
| func (suite *InitializeHardDelegatorRewardTests) TestClaimIndexesAreSetWhenClaimDoesNotExist() { | ||||
| @ -70,19 +71,30 @@ func (suite *InitializeHardDelegatorRewardTests) TestClaimIsSyncedAndIndexesAreS | ||||
| 
 | ||||
| 	// Set the global factor to a value different to one in claim so
 | ||||
| 	// we can detect if it is overwritten.
 | ||||
| 	globalIndex := increaseRewardFactors(claim.DelegatorRewardIndexes) | ||||
| 	suite.storeGlobalDelegatorFactor(globalIndex) | ||||
| 	rewardIndexes, _ := claim.DelegatorRewardIndexes.Get(types.BondDenom) | ||||
| 	globalIndexes := increaseRewardFactors(rewardIndexes) | ||||
| 
 | ||||
| 	// Update the claim object with the new global factor
 | ||||
| 	bondIndex, _ := claim.DelegatorRewardIndexes.GetRewardIndexIndex(types.BondDenom) | ||||
| 	claim.DelegatorRewardIndexes[bondIndex].RewardIndexes = globalIndexes | ||||
| 	suite.storeGlobalDelegatorFactor(claim.DelegatorRewardIndexes) | ||||
| 
 | ||||
| 	suite.keeper.InitializeHardDelegatorReward(suite.ctx, claim.Owner) | ||||
| 
 | ||||
| 	syncedClaim, _ := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, claim.Owner) | ||||
| 	suite.Equal(globalIndex, syncedClaim.DelegatorRewardIndexes) | ||||
| 	suite.Equal(globalIndexes, syncedClaim.DelegatorRewardIndexes[bondIndex].RewardIndexes) | ||||
| 	suite.Truef(syncedClaim.Reward.IsAllGT(claim.Reward), "'%s' not greater than '%s'", syncedClaim.Reward, claim.Reward) | ||||
| } | ||||
| 
 | ||||
| // arbitraryDelegatorRewardIndexes contains only one reward index as there is only every one bond denom
 | ||||
| var arbitraryDelegatorRewardIndexes = types.RewardIndexes{ | ||||
| 	types.NewRewardIndex(types.BondDenom, d("0.2")), | ||||
| var arbitraryDelegatorRewardIndexes = types.MultiRewardIndexes{ | ||||
| 	types.NewMultiRewardIndex( | ||||
| 		types.BondDenom, | ||||
| 		types.RewardIndexes{ | ||||
| 			types.NewRewardIndex("hard", d("0.2")), | ||||
| 			types.NewRewardIndex("swp", d("0.2")), | ||||
| 		}, | ||||
| 	), | ||||
| } | ||||
| 
 | ||||
| type fakeStakingKeeper struct { | ||||
|  | ||||
| @ -28,9 +28,9 @@ func TestSynchronizeHardDelegatorReward(t *testing.T) { | ||||
| 	suite.Run(t, new(SynchronizeHardDelegatorRewardTests)) | ||||
| } | ||||
| 
 | ||||
| func (suite *SynchronizeHardDelegatorRewardTests) storeGlobalDelegatorFactor(rewardIndexes types.RewardIndexes) { | ||||
| 	factor := rewardIndexes[0] | ||||
| 	suite.keeper.SetHardDelegatorRewardFactor(suite.ctx, factor.CollateralType, factor.RewardFactor) | ||||
| func (suite *SynchronizeHardDelegatorRewardTests) storeGlobalDelegatorFactor(multiRewardIndexes types.MultiRewardIndexes) { | ||||
| 	multiRewardIndex, _ := multiRewardIndexes.GetRewardIndex(types.BondDenom) | ||||
| 	suite.keeper.SetHardDelegatorRewardIndexes(suite.ctx, types.BondDenom, multiRewardIndex.RewardIndexes) | ||||
| } | ||||
| 
 | ||||
| func (suite *SynchronizeHardDelegatorRewardTests) TestClaimIndexesAreUnchangedWhenGlobalFactorUnchanged() { | ||||
| @ -68,14 +68,20 @@ func (suite *SynchronizeHardDelegatorRewardTests) TestClaimIndexesAreUpdatedWhen | ||||
| 	} | ||||
| 	suite.storeClaim(claim) | ||||
| 
 | ||||
| 	globalIndexes := increaseRewardFactors(claim.DelegatorRewardIndexes) | ||||
| 	suite.storeGlobalDelegatorFactor(globalIndexes) | ||||
| 	rewardIndexes, _ := claim.DelegatorRewardIndexes.Get(types.BondDenom) | ||||
| 	globalIndexes := increaseRewardFactors(rewardIndexes) | ||||
| 
 | ||||
| 	// Update the claim object with the new global factor
 | ||||
| 	bondIndex, _ := claim.DelegatorRewardIndexes.GetRewardIndexIndex(types.BondDenom) | ||||
| 	claim.DelegatorRewardIndexes[bondIndex].RewardIndexes = globalIndexes | ||||
| 	suite.storeGlobalDelegatorFactor(claim.DelegatorRewardIndexes) | ||||
| 
 | ||||
| 	suite.keeper.SynchronizeHardDelegatorRewards(suite.ctx, claim.Owner, nil, false) | ||||
| 
 | ||||
| 	syncedClaim, _ := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, claim.Owner) | ||||
| 	suite.Equal(globalIndexes, syncedClaim.DelegatorRewardIndexes) | ||||
| 	suite.Equal(globalIndexes, syncedClaim.DelegatorRewardIndexes[bondIndex].RewardIndexes) | ||||
| } | ||||
| 
 | ||||
| func (suite *SynchronizeHardDelegatorRewardTests) TestRewardIsUnchangedWhenGlobalFactorUnchanged() { | ||||
| 	delegator := arbitraryAddress() | ||||
| 	validatorAddress := arbitraryValidatorAddress() | ||||
| @ -98,9 +104,16 @@ func (suite *SynchronizeHardDelegatorRewardTests) TestRewardIsUnchangedWhenGloba | ||||
| 			Owner:  delegator, | ||||
| 			Reward: arbitraryCoins(), | ||||
| 		}, | ||||
| 		DelegatorRewardIndexes: types.RewardIndexes{{ | ||||
| 		DelegatorRewardIndexes: types.MultiRewardIndexes{{ | ||||
| 			CollateralType: types.BondDenom, | ||||
| 			RewardFactor:   d("0.1"), | ||||
| 			RewardIndexes: types.RewardIndexes{ | ||||
| 				{ | ||||
| 					CollateralType: "hard", RewardFactor: d("0.1"), | ||||
| 				}, | ||||
| 				{ | ||||
| 					CollateralType: "swp", RewardFactor: d("0.2"), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}}, | ||||
| 	} | ||||
| 	suite.storeClaim(claim) | ||||
| @ -136,13 +149,20 @@ func (suite *SynchronizeHardDelegatorRewardTests) TestRewardIsIncreasedWhenNewRe | ||||
| 			Owner:  delegator, | ||||
| 			Reward: arbitraryCoins(), | ||||
| 		}, | ||||
| 		DelegatorRewardIndexes: types.RewardIndexes{}, | ||||
| 		DelegatorRewardIndexes: types.MultiRewardIndexes{}, | ||||
| 	} | ||||
| 	suite.storeClaim(claim) | ||||
| 
 | ||||
| 	newGlobalIndexes := types.RewardIndexes{{ | ||||
| 	newGlobalIndexes := types.MultiRewardIndexes{{ | ||||
| 		CollateralType: types.BondDenom, | ||||
| 		RewardFactor:   d("0.1"), | ||||
| 		RewardIndexes: types.RewardIndexes{ | ||||
| 			{ | ||||
| 				CollateralType: "hard", RewardFactor: d("0.1"), | ||||
| 			}, | ||||
| 			{ | ||||
| 				CollateralType: "swp", RewardFactor: d("0.2"), | ||||
| 			}, | ||||
| 		}, | ||||
| 	}} | ||||
| 	suite.storeGlobalDelegatorFactor(newGlobalIndexes) | ||||
| 
 | ||||
| @ -152,7 +172,10 @@ func (suite *SynchronizeHardDelegatorRewardTests) TestRewardIsIncreasedWhenNewRe | ||||
| 
 | ||||
| 	suite.Equal(newGlobalIndexes, syncedClaim.DelegatorRewardIndexes) | ||||
| 	suite.Equal( | ||||
| 		cs(c(types.HardLiquidityRewardDenom, 100)).Add(claim.Reward...), | ||||
| 		cs( | ||||
| 			c(types.HardLiquidityRewardDenom, 100), | ||||
| 			c("swp", 200), | ||||
| 		).Add(claim.Reward...), | ||||
| 		syncedClaim.Reward, | ||||
| 	) | ||||
| } | ||||
| @ -179,16 +202,33 @@ func (suite *SynchronizeHardDelegatorRewardTests) TestRewardIsIncreasedWhenGloba | ||||
| 			Owner:  delegator, | ||||
| 			Reward: arbitraryCoins(), | ||||
| 		}, | ||||
| 		DelegatorRewardIndexes: types.RewardIndexes{{ | ||||
| 		DelegatorRewardIndexes: types.MultiRewardIndexes{{ | ||||
| 			CollateralType: types.BondDenom, | ||||
| 			RewardFactor:   d("0.1"), | ||||
| 			RewardIndexes: types.RewardIndexes{ | ||||
| 				{ | ||||
| 					CollateralType: "hard", RewardFactor: d("0.1"), | ||||
| 				}, | ||||
| 				{ | ||||
| 					CollateralType: "swp", RewardFactor: d("0.2"), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}}, | ||||
| 	} | ||||
| 	suite.storeClaim(claim) | ||||
| 
 | ||||
| 	suite.storeGlobalDelegatorFactor( | ||||
| 		types.RewardIndexes{ | ||||
| 			types.NewRewardIndex(types.BondDenom, d("0.2")), | ||||
| 		types.MultiRewardIndexes{ | ||||
| 			types.NewMultiRewardIndex( | ||||
| 				types.BondDenom, | ||||
| 				types.RewardIndexes{ | ||||
| 					{ | ||||
| 						CollateralType: "hard", RewardFactor: d("0.2"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						CollateralType: "swp", RewardFactor: d("0.4"), | ||||
| 					}, | ||||
| 				}, | ||||
| 			), | ||||
| 		}, | ||||
| 	) | ||||
| 
 | ||||
| @ -197,7 +237,10 @@ func (suite *SynchronizeHardDelegatorRewardTests) TestRewardIsIncreasedWhenGloba | ||||
| 	syncedClaim, _ := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, claim.Owner) | ||||
| 
 | ||||
| 	suite.Equal( | ||||
| 		cs(c(types.HardLiquidityRewardDenom, 100)).Add(claim.Reward...), | ||||
| 		cs( | ||||
| 			c(types.HardLiquidityRewardDenom, 100), | ||||
| 			c("swp", 200), | ||||
| 		).Add(claim.Reward...), | ||||
| 		syncedClaim.Reward, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| @ -66,10 +66,10 @@ func (suite *DelegatorRewardsTestSuite) SetupWithGenState(authBuilder app.AuthGe | ||||
| 
 | ||||
| func (suite *DelegatorRewardsTestSuite) TestAccumulateHardDelegatorRewards() { | ||||
| 	type args struct { | ||||
| 		delegation           sdk.Coin | ||||
| 		rewardsPerSecond     sdk.Coin | ||||
| 		timeElapsed          int | ||||
| 		expectedRewardFactor sdk.Dec | ||||
| 		delegation            sdk.Coin | ||||
| 		rewardsPerSecond      sdk.Coins | ||||
| 		timeElapsed           int | ||||
| 		expectedRewardIndexes types.RewardIndexes | ||||
| 	} | ||||
| 	type test struct { | ||||
| 		name string | ||||
| @ -79,28 +79,46 @@ func (suite *DelegatorRewardsTestSuite) TestAccumulateHardDelegatorRewards() { | ||||
| 		{ | ||||
| 			"7 seconds", | ||||
| 			args{ | ||||
| 				delegation:           c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond:     c("hard", 122354), | ||||
| 				timeElapsed:          7, | ||||
| 				expectedRewardFactor: d("0.428239000000000000"), | ||||
| 				delegation:       c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond: cs(c("hard", 122354)), | ||||
| 				timeElapsed:      7, | ||||
| 				expectedRewardIndexes: types.RewardIndexes{ | ||||
| 					types.NewRewardIndex("hard", d("0.428239000000000000")), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"1 day", | ||||
| 			args{ | ||||
| 				delegation:           c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond:     c("hard", 122354), | ||||
| 				timeElapsed:          86400, | ||||
| 				expectedRewardFactor: d("5285.692800000000000000"), | ||||
| 				delegation:       c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond: cs(c("hard", 122354)), | ||||
| 				timeElapsed:      86400, | ||||
| 				expectedRewardIndexes: types.RewardIndexes{ | ||||
| 					types.NewRewardIndex("hard", d("5285.692800000000000000")), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"0 seconds", | ||||
| 			args{ | ||||
| 				delegation:           c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond:     c("hard", 122354), | ||||
| 				timeElapsed:          0, | ||||
| 				expectedRewardFactor: d("0.0"), | ||||
| 				delegation:       c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond: cs(c("hard", 122354)), | ||||
| 				timeElapsed:      0, | ||||
| 				expectedRewardIndexes: types.RewardIndexes{ | ||||
| 					types.NewRewardIndex("hard", d("0.0")), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"multiple reward coins", | ||||
| 			args{ | ||||
| 				delegation:       c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond: cs(c("hard", 122354), c("swp", 567889)), | ||||
| 				timeElapsed:      7, | ||||
| 				expectedRewardIndexes: types.RewardIndexes{ | ||||
| 					types.NewRewardIndex("hard", d("0.428239000000000000")), | ||||
| 					types.NewRewardIndex("swp", d("1.987611500000000000")), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| @ -127,24 +145,24 @@ func (suite *DelegatorRewardsTestSuite) TestAccumulateHardDelegatorRewards() { | ||||
| 			runAtTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed)) | ||||
| 			runCtx := suite.ctx.WithBlockTime(runAtTime) | ||||
| 
 | ||||
| 			rewardPeriod, found := suite.keeper.GetHardDelegatorRewardPeriod(runCtx, tc.args.delegation.Denom) | ||||
| 			rewardPeriods, found := suite.keeper.GetHardDelegatorRewardPeriods(runCtx, tc.args.delegation.Denom) | ||||
| 			suite.Require().True(found) | ||||
| 			err = suite.keeper.AccumulateHardDelegatorRewards(runCtx, rewardPeriod) | ||||
| 			err = suite.keeper.AccumulateHardDelegatorRewards(runCtx, rewardPeriods) | ||||
| 			suite.Require().NoError(err) | ||||
| 
 | ||||
| 			rewardFactor, _ := suite.keeper.GetHardDelegatorRewardFactor(runCtx, tc.args.delegation.Denom) | ||||
| 			suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) | ||||
| 			rewardIndexes, _ := suite.keeper.GetHardDelegatorRewardIndexes(runCtx, tc.args.delegation.Denom) | ||||
| 			suite.Require().Equal(tc.args.expectedRewardIndexes, rewardIndexes) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *DelegatorRewardsTestSuite) TestSynchronizeHardDelegatorReward() { | ||||
| 	type args struct { | ||||
| 		delegation           sdk.Coin | ||||
| 		rewardsPerSecond     sdk.Coin | ||||
| 		blockTimes           []int | ||||
| 		expectedRewardFactor sdk.Dec | ||||
| 		expectedRewards      sdk.Coins | ||||
| 		delegation            sdk.Coin | ||||
| 		rewardsPerSecond      sdk.Coins | ||||
| 		blockTimes            []int | ||||
| 		expectedRewardIndexes types.RewardIndexes | ||||
| 		expectedRewards       sdk.Coins | ||||
| 	} | ||||
| 	type test struct { | ||||
| 		name string | ||||
| @ -155,31 +173,50 @@ func (suite *DelegatorRewardsTestSuite) TestSynchronizeHardDelegatorReward() { | ||||
| 		{ | ||||
| 			"10 blocks", | ||||
| 			args{ | ||||
| 				delegation:           c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond:     c("hard", 122354), | ||||
| 				blockTimes:           []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, | ||||
| 				expectedRewardFactor: d("6.117700000000000000"), | ||||
| 				expectedRewards:      cs(c("hard", 6117700)), | ||||
| 				delegation:       c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond: cs(c("hard", 122354)), | ||||
| 				blockTimes:       []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, | ||||
| 				expectedRewardIndexes: types.RewardIndexes{ | ||||
| 					types.NewRewardIndex("hard", d("6.117700000000000000")), | ||||
| 				}, | ||||
| 				expectedRewards: cs(c("hard", 6117700)), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"10 blocks - long block time", | ||||
| 			args{ | ||||
| 				delegation:           c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond:     c("hard", 122354), | ||||
| 				blockTimes:           []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, | ||||
| 				expectedRewardFactor: d("52856.928000000000000000"), | ||||
| 				expectedRewards:      cs(c("hard", 52856928000)), | ||||
| 				delegation:       c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond: cs(c("hard", 122354)), | ||||
| 				blockTimes:       []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, | ||||
| 				expectedRewardIndexes: types.RewardIndexes{ | ||||
| 					types.NewRewardIndex("hard", d("52856.928000000000000000")), | ||||
| 				}, | ||||
| 				expectedRewards: cs(c("hard", 52856928000)), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"delegator reward index updated when reward is zero", | ||||
| 			args{ | ||||
| 				delegation:           c("ukava", 1), | ||||
| 				rewardsPerSecond:     c("hard", 1), | ||||
| 				blockTimes:           []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, | ||||
| 				expectedRewardFactor: d("0.000099999900000100"), | ||||
| 				expectedRewards:      nil, | ||||
| 				delegation:       c("ukava", 1), | ||||
| 				rewardsPerSecond: cs(c("hard", 1)), | ||||
| 				blockTimes:       []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, | ||||
| 				expectedRewardIndexes: types.RewardIndexes{ | ||||
| 					types.NewRewardIndex("hard", d("0.000099999900000100")), | ||||
| 				}, | ||||
| 				expectedRewards: nil, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"multiple reward coins", | ||||
| 			args{ | ||||
| 				delegation:       c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond: cs(c("hard", 122354), c("swp", 56789)), | ||||
| 				blockTimes:       []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, | ||||
| 				expectedRewardIndexes: types.RewardIndexes{ | ||||
| 					types.NewRewardIndex("hard", d("6.117700000000000000")), | ||||
| 					types.NewRewardIndex("swp", d("2.839450000000000000")), | ||||
| 				}, | ||||
| 				expectedRewards: cs(c("hard", 6117700), c("swp", 2839450)), | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| @ -215,7 +252,9 @@ func (suite *DelegatorRewardsTestSuite) TestSynchronizeHardDelegatorReward() { | ||||
| 			// 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) | ||||
| 			for _, rewardIndex := range claim.DelegatorRewardIndexes[0].RewardIndexes { | ||||
| 				suite.Require().Equal(sdk.ZeroDec(), rewardIndex.RewardFactor) | ||||
| 			} | ||||
| 
 | ||||
| 			// Run accumulator at several intervals
 | ||||
| 			var timeElapsed int | ||||
| @ -226,10 +265,10 @@ func (suite *DelegatorRewardsTestSuite) TestSynchronizeHardDelegatorReward() { | ||||
| 				previousBlockTime = updatedBlockTime | ||||
| 				blockCtx := suite.ctx.WithBlockTime(updatedBlockTime) | ||||
| 
 | ||||
| 				rewardPeriod, found := suite.keeper.GetHardDelegatorRewardPeriod(blockCtx, tc.args.delegation.Denom) | ||||
| 				rewardPeriods, found := suite.keeper.GetHardDelegatorRewardPeriods(blockCtx, tc.args.delegation.Denom) | ||||
| 				suite.Require().True(found) | ||||
| 
 | ||||
| 				err := suite.keeper.AccumulateHardDelegatorRewards(blockCtx, rewardPeriod) | ||||
| 				err := suite.keeper.AccumulateHardDelegatorRewards(blockCtx, rewardPeriods) | ||||
| 				suite.Require().NoError(err) | ||||
| 			} | ||||
| 			updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed)) | ||||
| @ -241,12 +280,17 @@ func (suite *DelegatorRewardsTestSuite) TestSynchronizeHardDelegatorReward() { | ||||
| 			}) | ||||
| 
 | ||||
| 			// Check that reward factor and claim have been updated as expected
 | ||||
| 			rewardFactor, _ := suite.keeper.GetHardDelegatorRewardFactor(suite.ctx, tc.args.delegation.Denom) | ||||
| 			suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor) | ||||
| 			rewardIndexes, _ := suite.keeper.GetHardDelegatorRewardIndexes(suite.ctx, tc.args.delegation.Denom) | ||||
| 			for i, rewardPerSecond := range tc.args.rewardsPerSecond { | ||||
| 				rewardFactor, _ := rewardIndexes.Get(rewardPerSecond.Denom) | ||||
| 				suite.Require().Equal(tc.args.expectedRewardIndexes[i].RewardFactor, 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) | ||||
| 			for i, delegatorRewardIndex := range claim.DelegatorRewardIndexes[0].RewardIndexes { | ||||
| 				suite.Require().Equal(tc.args.expectedRewardIndexes[i].RewardFactor, delegatorRewardIndex.RewardFactor) | ||||
| 			} | ||||
| 			suite.Require().Equal(tc.args.expectedRewards, claim.Reward) | ||||
| 		}) | ||||
| 	} | ||||
| @ -255,7 +299,7 @@ func (suite *DelegatorRewardsTestSuite) TestSynchronizeHardDelegatorReward() { | ||||
| func (suite *DelegatorRewardsTestSuite) TestSimulateHardDelegatorRewardSynchronization() { | ||||
| 	type args struct { | ||||
| 		delegation            sdk.Coin | ||||
| 		rewardsPerSecond      sdk.Coin | ||||
| 		rewardsPerSecond      sdk.Coins | ||||
| 		blockTimes            []int | ||||
| 		expectedRewardIndexes types.RewardIndexes | ||||
| 		expectedRewards       sdk.Coins | ||||
| @ -270,9 +314,9 @@ func (suite *DelegatorRewardsTestSuite) TestSimulateHardDelegatorRewardSynchroni | ||||
| 			"10 blocks", | ||||
| 			args{ | ||||
| 				delegation:            c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond:      c("hard", 122354), | ||||
| 				rewardsPerSecond:      cs(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
 | ||||
| 				expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("6.117700000000000000"))}, | ||||
| 				expectedRewards:       cs(c("hard", 6117700)), | ||||
| 			}, | ||||
| 		}, | ||||
| @ -280,12 +324,25 @@ func (suite *DelegatorRewardsTestSuite) TestSimulateHardDelegatorRewardSynchroni | ||||
| 			"10 blocks - long block time", | ||||
| 			args{ | ||||
| 				delegation:            c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond:      c("hard", 122354), | ||||
| 				rewardsPerSecond:      cs(c("hard", 122354)), | ||||
| 				blockTimes:            []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400}, | ||||
| 				expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("ukava", d("52856.928000000000000000"))}, | ||||
| 				expectedRewardIndexes: types.RewardIndexes{types.NewRewardIndex("hard", d("52856.928000000000000000"))}, | ||||
| 				expectedRewards:       cs(c("hard", 52856928000)), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"multiple rewards coins", | ||||
| 			args{ | ||||
| 				delegation:       c("ukava", 1_000_000), | ||||
| 				rewardsPerSecond: cs(c("hard", 122354), c("swp", 56789)), | ||||
| 				blockTimes:       []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, | ||||
| 				expectedRewardIndexes: types.RewardIndexes{ | ||||
| 					types.NewRewardIndex("hard", d("6.117700000000000000")), | ||||
| 					types.NewRewardIndex("swp", d("2.839450000000000000")), | ||||
| 				}, | ||||
| 				expectedRewards: cs(c("hard", 6117700), c("swp", 2839450)), | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCases { | ||||
| @ -311,7 +368,9 @@ func (suite *DelegatorRewardsTestSuite) TestSimulateHardDelegatorRewardSynchroni | ||||
| 			// 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) | ||||
| 			for _, rewardIndex := range claim.DelegatorRewardIndexes[0].RewardIndexes { | ||||
| 				suite.Require().Equal(sdk.ZeroDec(), rewardIndex.RewardFactor) | ||||
| 			} | ||||
| 
 | ||||
| 			// Run accumulator at several intervals
 | ||||
| 			var timeElapsed int | ||||
| @ -323,9 +382,9 @@ func (suite *DelegatorRewardsTestSuite) TestSimulateHardDelegatorRewardSynchroni | ||||
| 				blockCtx := suite.ctx.WithBlockTime(updatedBlockTime) | ||||
| 
 | ||||
| 				// Accumulate hard delegator rewards
 | ||||
| 				rewardPeriod, found := suite.keeper.GetHardDelegatorRewardPeriod(blockCtx, tc.args.delegation.Denom) | ||||
| 				rewardPeriods, found := suite.keeper.GetHardDelegatorRewardPeriods(blockCtx, tc.args.delegation.Denom) | ||||
| 				suite.Require().True(found) | ||||
| 				err := suite.keeper.AccumulateHardDelegatorRewards(blockCtx, rewardPeriod) | ||||
| 				err := suite.keeper.AccumulateHardDelegatorRewards(blockCtx, rewardPeriods) | ||||
| 				suite.Require().NoError(err) | ||||
| 			} | ||||
| 			updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed)) | ||||
| @ -333,11 +392,12 @@ func (suite *DelegatorRewardsTestSuite) TestSimulateHardDelegatorRewardSynchroni | ||||
| 
 | ||||
| 			// Check that the synced claim held in memory has properly simulated syncing
 | ||||
| 			syncedClaim := suite.keeper.SimulateHardSynchronization(suite.ctx, claim) | ||||
| 			for _, expectedRewardIndex := range tc.args.expectedRewardIndexes { | ||||
| 
 | ||||
| 			for i, expectedRewardIndex := range tc.args.expectedRewardIndexes { | ||||
| 				// Check that the user's claim's reward index matches the expected reward index
 | ||||
| 				rewardIndex, found := syncedClaim.DelegatorRewardIndexes.GetRewardIndex(expectedRewardIndex.CollateralType) | ||||
| 				multiRewardIndex, found := syncedClaim.DelegatorRewardIndexes.Get(types.BondDenom) | ||||
| 				suite.Require().True(found) | ||||
| 				suite.Require().Equal(expectedRewardIndex, rewardIndex) | ||||
| 				suite.Require().Equal(expectedRewardIndex, multiRewardIndex[i]) | ||||
| 
 | ||||
| 				// Check that the user's claim holds the expected amount of reward coins
 | ||||
| 				suite.Require().Equal( | ||||
| @ -395,7 +455,7 @@ func (suite *DelegatorRewardsTestSuite) TestUnbondingValidatorSyncsClaim() { | ||||
| 		WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[1]), cs(c("ukava", 1e9))). | ||||
| 		WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[2]), cs(c("ukava", 1e9))) | ||||
| 
 | ||||
| 	rewardsPerSecond := c("hard", 122354) | ||||
| 	rewardsPerSecond := cs(c("hard", 122354)) | ||||
| 	bondDenom := "ukava" | ||||
| 
 | ||||
| 	incentBuilder := NewIncentiveGenesisBuilder(). | ||||
| @ -446,14 +506,16 @@ func (suite *DelegatorRewardsTestSuite) TestUnbondingValidatorSyncsClaim() { | ||||
| 	claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[0]) | ||||
| 	suite.Require().True(found) | ||||
| 
 | ||||
| 	globalIndex, found := suite.keeper.GetHardDelegatorRewardFactor(suite.ctx, bondDenom) | ||||
| 	rewardIndexes, found := suite.keeper.GetHardDelegatorRewardIndexes(suite.ctx, bondDenom) | ||||
| 	suite.Require().True(found) | ||||
| 	globalIndex, found := rewardIndexes.Get(rewardsPerSecond[0].Denom) | ||||
| 	suite.Require().True(found) | ||||
| 	claimIndex, found := claim.DelegatorRewardIndexes.GetRewardIndex(bondDenom) | ||||
| 	suite.Require().True(found) | ||||
| 	suite.Require().Equal(globalIndex, claimIndex.RewardFactor) | ||||
| 	suite.Require().Equal(globalIndex, claimIndex.RewardIndexes[0].RewardFactor) | ||||
| 
 | ||||
| 	suite.Require().Equal( | ||||
| 		cs(c(rewardsPerSecond.Denom, 76471)), | ||||
| 		cs(c(rewardsPerSecond[0].Denom, 76471)), | ||||
| 		claim.Reward, | ||||
| 	) | ||||
| 
 | ||||
| @ -471,9 +533,11 @@ func (suite *DelegatorRewardsTestSuite) TestUnbondingValidatorSyncsClaim() { | ||||
| 	// claim index has been updated to latest global value
 | ||||
| 	laterClaimIndex, found := laterClaim.DelegatorRewardIndexes.GetRewardIndex(bondDenom) | ||||
| 	suite.Require().True(found) | ||||
| 	globalIndex, found = suite.keeper.GetHardDelegatorRewardFactor(suite.ctx, bondDenom) | ||||
| 	rewardIndexes, found = suite.keeper.GetHardDelegatorRewardIndexes(suite.ctx, bondDenom) | ||||
| 	suite.Require().True(found) | ||||
| 	suite.Require().Equal(globalIndex, laterClaimIndex.RewardFactor) | ||||
| 	globalIndex, found = rewardIndexes.Get(rewardsPerSecond[0].Denom) | ||||
| 	suite.Require().True(found) | ||||
| 	suite.Require().Equal(globalIndex, laterClaimIndex.RewardIndexes[0].RewardFactor) | ||||
| } | ||||
| 
 | ||||
| // given a user has a delegation to an unbonded validator, when the validator becomes bonded, the user starts accumulating rewards
 | ||||
| @ -485,7 +549,7 @@ func (suite *DelegatorRewardsTestSuite) TestBondingValidatorSyncsClaim() { | ||||
| 		WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[1]), cs(c("ukava", 1e9))). | ||||
| 		WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[2]), cs(c("ukava", 1e9))) | ||||
| 
 | ||||
| 	rewardsPerSecond := c("hard", 122354) | ||||
| 	rewardsPerSecond := cs(c("hard", 122354)) | ||||
| 	bondDenom := "ukava" | ||||
| 
 | ||||
| 	incentBuilder := NewIncentiveGenesisBuilder(). | ||||
| @ -536,11 +600,13 @@ func (suite *DelegatorRewardsTestSuite) TestBondingValidatorSyncsClaim() { | ||||
| 	claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[0]) | ||||
| 	suite.Require().True(found) | ||||
| 
 | ||||
| 	globalIndex, found := suite.keeper.GetHardDelegatorRewardFactor(suite.ctx, bondDenom) | ||||
| 	rewardIndexes, found := suite.keeper.GetHardDelegatorRewardIndexes(suite.ctx, bondDenom) | ||||
| 	suite.Require().True(found) | ||||
| 	globalIndex, found := rewardIndexes.Get(rewardsPerSecond[0].Denom) | ||||
| 	suite.Require().True(found) | ||||
| 	claimIndex, found := claim.DelegatorRewardIndexes.GetRewardIndex(bondDenom) | ||||
| 	suite.Require().True(found) | ||||
| 	suite.Require().Equal(globalIndex, claimIndex.RewardFactor) | ||||
| 	suite.Require().Equal(globalIndex, claimIndex.RewardIndexes[0].RewardFactor) | ||||
| 
 | ||||
| 	suite.Require().Equal( | ||||
| 		sdk.Coins(nil), | ||||
| @ -561,9 +627,11 @@ func (suite *DelegatorRewardsTestSuite) TestBondingValidatorSyncsClaim() { | ||||
| 	// claim index has been updated to latest global value
 | ||||
| 	laterClaimIndex, found := laterClaim.DelegatorRewardIndexes.GetRewardIndex(bondDenom) | ||||
| 	suite.Require().True(found) | ||||
| 	globalIndex, found = suite.keeper.GetHardDelegatorRewardFactor(suite.ctx, bondDenom) | ||||
| 	rewardIndexes, found = suite.keeper.GetHardDelegatorRewardIndexes(suite.ctx, bondDenom) | ||||
| 	suite.Require().True(found) | ||||
| 	suite.Require().Equal(globalIndex, laterClaimIndex.RewardFactor) | ||||
| 	globalIndex, found = rewardIndexes.Get(rewardsPerSecond[0].Denom) | ||||
| 	suite.Require().True(found) | ||||
| 	suite.Require().Equal(globalIndex, laterClaimIndex.RewardIndexes[0].RewardFactor) | ||||
| } | ||||
| 
 | ||||
| // If a validator is slashed delegators should have their claims synced
 | ||||
| @ -573,7 +641,7 @@ func (suite *DelegatorRewardsTestSuite) TestSlashingValidatorSyncsClaim() { | ||||
| 		WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[0]), cs(c("ukava", 1e9))). | ||||
| 		WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[1]), cs(c("ukava", 1e9))) | ||||
| 
 | ||||
| 	rewardsPerSecond := c("hard", 122354) | ||||
| 	rewardsPerSecond := cs(c("hard", 122354)) | ||||
| 	bondDenom := "ukava" | ||||
| 
 | ||||
| 	incentBuilder := NewIncentiveGenesisBuilder(). | ||||
| @ -608,11 +676,11 @@ func (suite *DelegatorRewardsTestSuite) TestSlashingValidatorSyncsClaim() { | ||||
| 	// Check that claim has been created with synced reward index but no reward coins
 | ||||
| 	initialClaim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[0]) | ||||
| 	suite.True(found) | ||||
| 	initialGlobalIndex, found := suite.keeper.GetHardDelegatorRewardFactor(suite.ctx, bondDenom) | ||||
| 	initialGlobalIndex, found := suite.keeper.GetHardDelegatorRewardIndexes(suite.ctx, bondDenom) | ||||
| 	suite.True(found) | ||||
| 	initialClaimIndex, found := initialClaim.DelegatorRewardIndexes.GetRewardIndex(bondDenom) | ||||
| 	suite.True(found) | ||||
| 	suite.Require().Equal(initialGlobalIndex, initialClaimIndex.RewardFactor) | ||||
| 	suite.Require().Equal(initialGlobalIndex, initialClaimIndex.RewardIndexes) | ||||
| 	suite.True(initialClaim.Reward.Empty()) // Initial claim should not have any rewards
 | ||||
| 
 | ||||
| 	// Start a new block to accumulate some delegation rewards for the user.
 | ||||
| @ -631,20 +699,20 @@ func (suite *DelegatorRewardsTestSuite) TestSlashingValidatorSyncsClaim() { | ||||
| 	// Check that the user's claim has been synced. ie rewards added, index updated
 | ||||
| 	claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[0]) | ||||
| 	suite.Require().True(found) | ||||
| 	globalIndex, found := suite.keeper.GetHardDelegatorRewardFactor(suite.ctx, bondDenom) | ||||
| 	globalIndex, found := suite.keeper.GetHardDelegatorRewardIndexes(suite.ctx, bondDenom) | ||||
| 	suite.Require().True(found) | ||||
| 	claimIndex, found := claim.DelegatorRewardIndexes.GetRewardIndex(bondDenom) | ||||
| 	suite.Require().True(found) | ||||
| 	suite.Require().Equal(globalIndex, claimIndex.RewardFactor) | ||||
| 	suite.Require().Equal(globalIndex, claimIndex.RewardIndexes) | ||||
| 
 | ||||
| 	// Check that rewards were added
 | ||||
| 	suite.Require().Equal( | ||||
| 		cs(c(rewardsPerSecond.Denom, 58264)), | ||||
| 		cs(c(rewardsPerSecond[0].Denom, 58264)), | ||||
| 		claim.Reward, | ||||
| 	) | ||||
| 
 | ||||
| 	// Check that reward factor increased from initial value
 | ||||
| 	suite.True(claimIndex.RewardFactor.GT(initialClaimIndex.RewardFactor)) | ||||
| 	suite.True(claimIndex.RewardIndexes[0].RewardFactor.GT(initialClaimIndex.RewardIndexes[0].RewardFactor)) | ||||
| } | ||||
| 
 | ||||
| // Given a delegation to a bonded validator, when a user redelegates everything to another (bonded) validator, the user's claim is synced
 | ||||
| @ -654,7 +722,7 @@ func (suite *DelegatorRewardsTestSuite) TestRedelegationSyncsClaim() { | ||||
| 		WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[0]), cs(c("ukava", 1e9))). | ||||
| 		WithSimpleAccount(sdk.AccAddress(suite.validatorAddrs[1]), cs(c("ukava", 1e9))) | ||||
| 
 | ||||
| 	rewardsPerSecond := c("hard", 122354) | ||||
| 	rewardsPerSecond := cs(c("hard", 122354)) | ||||
| 	bondDenom := "ukava" | ||||
| 
 | ||||
| 	incentBuilder := NewIncentiveGenesisBuilder(). | ||||
| @ -689,13 +757,13 @@ func (suite *DelegatorRewardsTestSuite) TestRedelegationSyncsClaim() { | ||||
| 	claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[0]) | ||||
| 	suite.Require().True(found) | ||||
| 
 | ||||
| 	globalIndex, found := suite.keeper.GetHardDelegatorRewardFactor(suite.ctx, bondDenom) | ||||
| 	globalIndex, found := suite.keeper.GetHardDelegatorRewardIndexes(suite.ctx, bondDenom) | ||||
| 	suite.Require().True(found) | ||||
| 	claimIndex, found := claim.DelegatorRewardIndexes.GetRewardIndex(bondDenom) | ||||
| 	suite.Require().True(found) | ||||
| 	suite.Require().Equal(globalIndex, claimIndex.RewardFactor) | ||||
| 	suite.Require().Equal(globalIndex, claimIndex.RewardIndexes) | ||||
| 	suite.Require().Equal( | ||||
| 		cs(c(rewardsPerSecond.Denom, 76471)), | ||||
| 		cs(c(rewardsPerSecond[0].Denom, 76471)), | ||||
| 		claim.Reward, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| @ -300,58 +300,56 @@ func (k Keeper) SimulateHardSynchronization(ctx sdk.Context, claim types.HardLiq | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// 3. Simulate Hard delegator rewards
 | ||||
| 	delagatorFactor, found := k.GetHardDelegatorRewardFactor(ctx, types.BondDenom) | ||||
| 	if !found { | ||||
| 		return claim | ||||
| 	} | ||||
| 
 | ||||
| 	delegatorIndex, hasDelegatorRewardIndex := claim.HasDelegatorRewardIndex(types.BondDenom) | ||||
| 	if !hasDelegatorRewardIndex { | ||||
| 		return claim | ||||
| 	} | ||||
| 
 | ||||
| 	userRewardFactor := claim.DelegatorRewardIndexes[delegatorIndex].RewardFactor | ||||
| 	rewardsAccumulatedFactor := delagatorFactor.Sub(userRewardFactor) | ||||
| 	if rewardsAccumulatedFactor.IsZero() { | ||||
| 		return claim | ||||
| 	} | ||||
| 	claim.DelegatorRewardIndexes[delegatorIndex].RewardFactor = delagatorFactor | ||||
| 
 | ||||
| 	totalDelegated := sdk.ZeroDec() | ||||
| 
 | ||||
| 	delegations := k.stakingKeeper.GetDelegatorDelegations(ctx, claim.GetOwner(), 200) | ||||
| 	for _, delegation := range delegations { | ||||
| 		validator, found := k.stakingKeeper.GetValidator(ctx, delegation.GetValidatorAddr()) | ||||
| 		if !found { | ||||
| 	// 3. Simulate delegator rewards
 | ||||
| 	for _, ri := range claim.DelegatorRewardIndexes { | ||||
| 		// For each Delegator reward index (there's only one: the bond denom 'ukava')
 | ||||
| 		globalRewardIndexes, foundGlobalRewardIndexes := k.GetHardDelegatorRewardIndexes(ctx, ri.CollateralType) | ||||
| 		if !foundGlobalRewardIndexes { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// Delegators don't accumulate rewards if their validator is unbonded/slashed
 | ||||
| 		if validator.GetStatus() != sdk.Bonded { | ||||
| 		userRewardIndexes, foundUserRewardIndexes := claim.DelegatorRewardIndexes.GetRewardIndex(ri.CollateralType) | ||||
| 		if !foundUserRewardIndexes { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		if validator.GetTokens().IsZero() { | ||||
| 		userRewardIndexIndex, foundUserRewardIndexIndex := claim.DelegatorRewardIndexes.GetRewardIndexIndex(ri.CollateralType) | ||||
| 		if !foundUserRewardIndexIndex { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		delegatedTokens := validator.TokensFromShares(delegation.GetShares()) | ||||
| 		if delegatedTokens.IsZero() || delegatedTokens.IsNegative() { | ||||
| 			continue | ||||
| 		amtDelegated := k.GetTotalDelegated(ctx, claim.GetOwner(), sdk.ValAddress(claim.Owner.String()), true) | ||||
| 
 | ||||
| 		for _, globalRewardIndex := range globalRewardIndexes { | ||||
| 			userRewardIndex, foundUserRewardIndex := userRewardIndexes.RewardIndexes.GetRewardIndex(globalRewardIndex.CollateralType) | ||||
| 			if !foundUserRewardIndex { | ||||
| 				userRewardIndex = types.NewRewardIndex(globalRewardIndex.CollateralType, sdk.ZeroDec()) | ||||
| 				userRewardIndexes.RewardIndexes = append(userRewardIndexes.RewardIndexes, userRewardIndex) | ||||
| 				claim.DelegatorRewardIndexes[userRewardIndexIndex].RewardIndexes = append(claim.DelegatorRewardIndexes[userRewardIndexIndex].RewardIndexes, userRewardIndex) | ||||
| 			} | ||||
| 
 | ||||
| 			globalRewardFactor := globalRewardIndex.RewardFactor | ||||
| 			userRewardFactor := userRewardIndex.RewardFactor | ||||
| 			rewardsAccumulatedFactor := globalRewardFactor.Sub(userRewardFactor) | ||||
| 			if rewardsAccumulatedFactor.IsZero() { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			rewardsEarned := rewardsAccumulatedFactor.Mul(amtDelegated).RoundInt() | ||||
| 			if rewardsEarned.IsZero() || rewardsEarned.IsNegative() { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			factorIndex, foundFactorIndex := userRewardIndexes.RewardIndexes.GetFactorIndex(globalRewardIndex.CollateralType) | ||||
| 			if !foundFactorIndex { | ||||
| 				continue | ||||
| 			} | ||||
| 			claim.DelegatorRewardIndexes[userRewardIndexIndex].RewardIndexes[factorIndex].RewardFactor = globalRewardIndex.RewardFactor | ||||
| 			newRewardsCoin := sdk.NewCoin(userRewardIndex.CollateralType, rewardsEarned) | ||||
| 			claim.Reward = claim.Reward.Add(newRewardsCoin) | ||||
| 		} | ||||
| 		totalDelegated = totalDelegated.Add(delegatedTokens) | ||||
| 	} | ||||
| 
 | ||||
| 	rewardsEarned := rewardsAccumulatedFactor.Mul(totalDelegated).RoundInt() | ||||
| 	if rewardsEarned.IsZero() || rewardsEarned.IsNegative() { | ||||
| 		return claim | ||||
| 	} | ||||
| 
 | ||||
| 	// Add rewards to delegator's hard claim
 | ||||
| 	newRewardsCoin := sdk.NewCoin(types.HardLiquidityRewardDenom, rewardsEarned) | ||||
| 	claim.Reward = claim.Reward.Add(newRewardsCoin) | ||||
| 
 | ||||
| 	return claim | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										965
									
								
								x/incentive/legacy/v0_14/types.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										965
									
								
								x/incentive/legacy/v0_14/types.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,965 @@ | ||||
| package v0_14 | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 	"github.com/cosmos/cosmos-sdk/x/params" | ||||
| 
 | ||||
| 	tmtime "github.com/tendermint/tendermint/types/time" | ||||
| 
 | ||||
| 	cdptypes "github.com/kava-labs/kava/x/cdp/types" | ||||
| 	kavadistTypes "github.com/kava-labs/kava/x/kavadist/types" | ||||
| ) | ||||
| 
 | ||||
| // Valid reward multipliers
 | ||||
| const ( | ||||
| 	Small                          MultiplierName = "small" | ||||
| 	Medium                         MultiplierName = "medium" | ||||
| 	Large                          MultiplierName = "large" | ||||
| 	USDXMintingClaimType                          = "usdx_minting" | ||||
| 	HardLiquidityProviderClaimType                = "hard_liquidity_provider" | ||||
| 	BondDenom                                     = "ukava" | ||||
| 	ModuleName                                    = "incentive" | ||||
| ) | ||||
| 
 | ||||
| // Parameter keys and default values
 | ||||
| var ( | ||||
| 	KeyUSDXMintingRewardPeriods     = []byte("USDXMintingRewardPeriods") | ||||
| 	KeyHardSupplyRewardPeriods      = []byte("HardSupplyRewardPeriods") | ||||
| 	KeyHardBorrowRewardPeriods      = []byte("HardBorrowRewardPeriods") | ||||
| 	KeyHardDelegatorRewardPeriods   = []byte("HardDelegatorRewardPeriods") | ||||
| 	KeyClaimEnd                     = []byte("ClaimEnd") | ||||
| 	KeyMultipliers                  = []byte("ClaimMultipliers") | ||||
| 	DefaultActive                   = false | ||||
| 	DefaultRewardPeriods            = RewardPeriods{} | ||||
| 	DefaultMultiRewardPeriods       = MultiRewardPeriods{} | ||||
| 	DefaultMultipliers              = Multipliers{} | ||||
| 	DefaultUSDXClaims               = USDXMintingClaims{} | ||||
| 	DefaultHardClaims               = HardLiquidityProviderClaims{} | ||||
| 	DefaultGenesisAccumulationTimes = GenesisAccumulationTimes{} | ||||
| 	DefaultClaimEnd                 = tmtime.Canonical(time.Unix(1, 0)) | ||||
| 	GovDenom                        = cdptypes.DefaultGovDenom | ||||
| 	PrincipalDenom                  = "usdx" | ||||
| 	IncentiveMacc                   = kavadistTypes.ModuleName | ||||
| ) | ||||
| 
 | ||||
| // GenesisState is the state that must be provided at genesis.
 | ||||
| type GenesisState struct { | ||||
| 	Params                         Params                      `json:"params" yaml:"params"` | ||||
| 	USDXAccumulationTimes          GenesisAccumulationTimes    `json:"usdx_accumulation_times" yaml:"usdx_accumulation_times"` | ||||
| 	HardSupplyAccumulationTimes    GenesisAccumulationTimes    `json:"hard_supply_accumulation_times" yaml:"hard_supply_accumulation_times"` | ||||
| 	HardBorrowAccumulationTimes    GenesisAccumulationTimes    `json:"hard_borrow_accumulation_times" yaml:"hard_borrow_accumulation_times"` | ||||
| 	HardDelegatorAccumulationTimes GenesisAccumulationTimes    `json:"hard_delegator_accumulation_times" yaml:"hard_delegator_accumulation_times"` | ||||
| 	USDXMintingClaims              USDXMintingClaims           `json:"usdx_minting_claims" yaml:"usdx_minting_claims"` | ||||
| 	HardLiquidityProviderClaims    HardLiquidityProviderClaims `json:"hard_liquidity_provider_claims" yaml:"hard_liquidity_provider_claims"` | ||||
| } | ||||
| 
 | ||||
| // NewGenesisState returns a new genesis state
 | ||||
| func NewGenesisState(params Params, usdxAccumTimes, hardSupplyAccumTimes, hardBorrowAccumTimes, hardDelegatorAccumTimes GenesisAccumulationTimes, c USDXMintingClaims, hc HardLiquidityProviderClaims) GenesisState { | ||||
| 	return GenesisState{ | ||||
| 		Params:                         params, | ||||
| 		USDXAccumulationTimes:          usdxAccumTimes, | ||||
| 		HardSupplyAccumulationTimes:    hardSupplyAccumTimes, | ||||
| 		HardBorrowAccumulationTimes:    hardBorrowAccumTimes, | ||||
| 		HardDelegatorAccumulationTimes: hardDelegatorAccumTimes, | ||||
| 		USDXMintingClaims:              c, | ||||
| 		HardLiquidityProviderClaims:    hc, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DefaultGenesisState returns a default genesis state
 | ||||
| func DefaultGenesisState() GenesisState { | ||||
| 	return GenesisState{ | ||||
| 		Params:                         DefaultParams(), | ||||
| 		USDXAccumulationTimes:          GenesisAccumulationTimes{}, | ||||
| 		HardSupplyAccumulationTimes:    GenesisAccumulationTimes{}, | ||||
| 		HardBorrowAccumulationTimes:    GenesisAccumulationTimes{}, | ||||
| 		HardDelegatorAccumulationTimes: GenesisAccumulationTimes{}, | ||||
| 		USDXMintingClaims:              DefaultUSDXClaims, | ||||
| 		HardLiquidityProviderClaims:    DefaultHardClaims, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Validate performs basic validation of genesis data returning an
 | ||||
| // error for any failed validation criteria.
 | ||||
| func (gs GenesisState) Validate() error { | ||||
| 	if err := gs.Params.Validate(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := gs.USDXAccumulationTimes.Validate(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := gs.HardSupplyAccumulationTimes.Validate(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := gs.HardBorrowAccumulationTimes.Validate(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := gs.HardDelegatorAccumulationTimes.Validate(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := gs.HardLiquidityProviderClaims.Validate(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return gs.USDXMintingClaims.Validate() | ||||
| } | ||||
| 
 | ||||
| // GenesisAccumulationTime stores the previous reward distribution time and its corresponding collateral type
 | ||||
| type GenesisAccumulationTime struct { | ||||
| 	CollateralType           string    `json:"collateral_type" yaml:"collateral_type"` | ||||
| 	PreviousAccumulationTime time.Time `json:"previous_accumulation_time" yaml:"previous_accumulation_time"` | ||||
| } | ||||
| 
 | ||||
| // NewGenesisAccumulationTime returns a new GenesisAccumulationTime
 | ||||
| func NewGenesisAccumulationTime(ctype string, prevTime time.Time) GenesisAccumulationTime { | ||||
| 	return GenesisAccumulationTime{ | ||||
| 		CollateralType:           ctype, | ||||
| 		PreviousAccumulationTime: prevTime, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // GenesisAccumulationTimes slice of GenesisAccumulationTime
 | ||||
| type GenesisAccumulationTimes []GenesisAccumulationTime | ||||
| 
 | ||||
| // Validate performs validation of GenesisAccumulationTimes
 | ||||
| func (gats GenesisAccumulationTimes) Validate() error { | ||||
| 	for _, gat := range gats { | ||||
| 		if err := gat.Validate(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Validate performs validation of GenesisAccumulationTime
 | ||||
| func (gat GenesisAccumulationTime) Validate() error { | ||||
| 	if len(gat.CollateralType) == 0 { | ||||
| 		return fmt.Errorf("genesis accumulation time's collateral type must be defined") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Params governance parameters for the incentive module
 | ||||
| type Params struct { | ||||
| 	USDXMintingRewardPeriods   RewardPeriods      `json:"usdx_minting_reward_periods" yaml:"usdx_minting_reward_periods"` | ||||
| 	HardSupplyRewardPeriods    MultiRewardPeriods `json:"hard_supply_reward_periods" yaml:"hard_supply_reward_periods"` | ||||
| 	HardBorrowRewardPeriods    MultiRewardPeriods `json:"hard_borrow_reward_periods" yaml:"hard_borrow_reward_periods"` | ||||
| 	HardDelegatorRewardPeriods RewardPeriods      `json:"hard_delegator_reward_periods" yaml:"hard_delegator_reward_periods"` | ||||
| 	ClaimMultipliers           Multipliers        `json:"claim_multipliers" yaml:"claim_multipliers"` | ||||
| 	ClaimEnd                   time.Time          `json:"claim_end" yaml:"claim_end"` | ||||
| } | ||||
| 
 | ||||
| // NewParams returns a new params object
 | ||||
| func NewParams(usdxMinting RewardPeriods, hardSupply, hardBorrow MultiRewardPeriods, | ||||
| 	hardDelegator RewardPeriods, multipliers Multipliers, claimEnd time.Time) Params { | ||||
| 	return Params{ | ||||
| 		USDXMintingRewardPeriods:   usdxMinting, | ||||
| 		HardSupplyRewardPeriods:    hardSupply, | ||||
| 		HardBorrowRewardPeriods:    hardBorrow, | ||||
| 		HardDelegatorRewardPeriods: hardDelegator, | ||||
| 		ClaimMultipliers:           multipliers, | ||||
| 		ClaimEnd:                   claimEnd, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DefaultParams returns default params for incentive module
 | ||||
| func DefaultParams() Params { | ||||
| 	return NewParams(DefaultRewardPeriods, DefaultMultiRewardPeriods, | ||||
| 		DefaultMultiRewardPeriods, DefaultRewardPeriods, DefaultMultipliers, DefaultClaimEnd) | ||||
| } | ||||
| 
 | ||||
| // String implements fmt.Stringer
 | ||||
| func (p Params) String() string { | ||||
| 	return fmt.Sprintf(`Params: | ||||
| 	USDX Minting Reward Periods: %s | ||||
| 	Hard Supply Reward Periods: %s | ||||
| 	Hard Borrow Reward Periods: %s | ||||
| 	Hard Delegator Reward Periods: %s | ||||
| 	Claim Multipliers :%s | ||||
| 	Claim End Time: %s | ||||
| 	`, p.USDXMintingRewardPeriods, p.HardSupplyRewardPeriods, p.HardBorrowRewardPeriods, | ||||
| 		p.HardDelegatorRewardPeriods, p.ClaimMultipliers, p.ClaimEnd) | ||||
| } | ||||
| 
 | ||||
| // ParamKeyTable Key declaration for parameters
 | ||||
| func ParamKeyTable() params.KeyTable { | ||||
| 	return params.NewKeyTable().RegisterParamSet(&Params{}) | ||||
| } | ||||
| 
 | ||||
| // ParamSetPairs implements the ParamSet interface and returns all the key/value pairs
 | ||||
| func (p *Params) ParamSetPairs() params.ParamSetPairs { | ||||
| 	return params.ParamSetPairs{ | ||||
| 		params.NewParamSetPair(KeyUSDXMintingRewardPeriods, &p.USDXMintingRewardPeriods, validateRewardPeriodsParam), | ||||
| 		params.NewParamSetPair(KeyHardSupplyRewardPeriods, &p.HardSupplyRewardPeriods, validateMultiRewardPeriodsParam), | ||||
| 		params.NewParamSetPair(KeyHardBorrowRewardPeriods, &p.HardBorrowRewardPeriods, validateMultiRewardPeriodsParam), | ||||
| 		params.NewParamSetPair(KeyHardDelegatorRewardPeriods, &p.HardDelegatorRewardPeriods, validateRewardPeriodsParam), | ||||
| 		params.NewParamSetPair(KeyClaimEnd, &p.ClaimEnd, validateClaimEndParam), | ||||
| 		params.NewParamSetPair(KeyMultipliers, &p.ClaimMultipliers, validateMultipliersParam), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Validate checks that the parameters have valid values.
 | ||||
| func (p Params) Validate() error { | ||||
| 
 | ||||
| 	if err := validateMultipliersParam(p.ClaimMultipliers); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := validateRewardPeriodsParam(p.USDXMintingRewardPeriods); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := validateMultiRewardPeriodsParam(p.HardSupplyRewardPeriods); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := validateMultiRewardPeriodsParam(p.HardBorrowRewardPeriods); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return validateRewardPeriodsParam(p.HardDelegatorRewardPeriods) | ||||
| } | ||||
| 
 | ||||
| func validateRewardPeriodsParam(i interface{}) error { | ||||
| 	rewards, ok := i.(RewardPeriods) | ||||
| 	if !ok { | ||||
| 		return fmt.Errorf("invalid parameter type: %T", i) | ||||
| 	} | ||||
| 
 | ||||
| 	return rewards.Validate() | ||||
| } | ||||
| 
 | ||||
| func validateMultiRewardPeriodsParam(i interface{}) error { | ||||
| 	rewards, ok := i.(MultiRewardPeriods) | ||||
| 	if !ok { | ||||
| 		return fmt.Errorf("invalid parameter type: %T", i) | ||||
| 	} | ||||
| 
 | ||||
| 	return rewards.Validate() | ||||
| } | ||||
| 
 | ||||
| func validateMultipliersParam(i interface{}) error { | ||||
| 	multipliers, ok := i.(Multipliers) | ||||
| 	if !ok { | ||||
| 		return fmt.Errorf("invalid parameter type: %T", i) | ||||
| 	} | ||||
| 	return multipliers.Validate() | ||||
| } | ||||
| 
 | ||||
| func validateClaimEndParam(i interface{}) error { | ||||
| 	endTime, ok := i.(time.Time) | ||||
| 	if !ok { | ||||
| 		return fmt.Errorf("invalid parameter type: %T", i) | ||||
| 	} | ||||
| 	if endTime.Unix() <= 0 { | ||||
| 		return fmt.Errorf("end time should not be zero") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // RewardPeriod stores the state of an ongoing reward
 | ||||
| type RewardPeriod struct { | ||||
| 	Active           bool      `json:"active" yaml:"active"` | ||||
| 	CollateralType   string    `json:"collateral_type" yaml:"collateral_type"` | ||||
| 	Start            time.Time `json:"start" yaml:"start"` | ||||
| 	End              time.Time `json:"end" yaml:"end"` | ||||
| 	RewardsPerSecond sdk.Coin  `json:"rewards_per_second" yaml:"rewards_per_second"` // per second reward payouts
 | ||||
| } | ||||
| 
 | ||||
| // String implements fmt.Stringer
 | ||||
| func (rp RewardPeriod) String() string { | ||||
| 	return fmt.Sprintf(`Reward Period: | ||||
| 	Collateral Type: %s, | ||||
| 	Start: %s, | ||||
| 	End: %s, | ||||
| 	Rewards Per Second: %s, | ||||
| 	Active %t, | ||||
| 	`, rp.CollateralType, rp.Start, rp.End, rp.RewardsPerSecond, rp.Active) | ||||
| } | ||||
| 
 | ||||
| // NewRewardPeriod returns a new RewardPeriod
 | ||||
| func NewRewardPeriod(active bool, collateralType string, start time.Time, end time.Time, reward sdk.Coin) RewardPeriod { | ||||
| 	return RewardPeriod{ | ||||
| 		Active:           active, | ||||
| 		CollateralType:   collateralType, | ||||
| 		Start:            start, | ||||
| 		End:              end, | ||||
| 		RewardsPerSecond: reward, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Validate performs a basic check of a RewardPeriod fields.
 | ||||
| func (rp RewardPeriod) Validate() error { | ||||
| 	if rp.Start.Unix() <= 0 { | ||||
| 		return errors.New("reward period start time cannot be 0") | ||||
| 	} | ||||
| 	if rp.End.Unix() <= 0 { | ||||
| 		return errors.New("reward period end time cannot be 0") | ||||
| 	} | ||||
| 	if rp.Start.After(rp.End) { | ||||
| 		return fmt.Errorf("end period time %s cannot be before start time %s", rp.End, rp.Start) | ||||
| 	} | ||||
| 	if !rp.RewardsPerSecond.IsValid() { | ||||
| 		return fmt.Errorf("invalid reward amount: %s", rp.RewardsPerSecond) | ||||
| 	} | ||||
| 	if strings.TrimSpace(rp.CollateralType) == "" { | ||||
| 		return fmt.Errorf("reward period collateral type cannot be blank: %s", rp) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // RewardPeriods array of RewardPeriod
 | ||||
| type RewardPeriods []RewardPeriod | ||||
| 
 | ||||
| // Validate checks if all the RewardPeriods are valid and there are no duplicated
 | ||||
| // entries.
 | ||||
| func (rps RewardPeriods) Validate() error { | ||||
| 	seenPeriods := make(map[string]bool) | ||||
| 	for _, rp := range rps { | ||||
| 		if seenPeriods[rp.CollateralType] { | ||||
| 			return fmt.Errorf("duplicated reward period with collateral type %s", rp.CollateralType) | ||||
| 		} | ||||
| 
 | ||||
| 		if err := rp.Validate(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		seenPeriods[rp.CollateralType] = true | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Multiplier amount the claim rewards get increased by, along with how long the claim rewards are locked
 | ||||
| type Multiplier struct { | ||||
| 	Name         MultiplierName `json:"name" yaml:"name"` | ||||
| 	MonthsLockup int64          `json:"months_lockup" yaml:"months_lockup"` | ||||
| 	Factor       sdk.Dec        `json:"factor" yaml:"factor"` | ||||
| } | ||||
| 
 | ||||
| // NewMultiplier returns a new Multiplier
 | ||||
| func NewMultiplier(name MultiplierName, lockup int64, factor sdk.Dec) Multiplier { | ||||
| 	return Multiplier{ | ||||
| 		Name:         name, | ||||
| 		MonthsLockup: lockup, | ||||
| 		Factor:       factor, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Validate multiplier param
 | ||||
| func (m Multiplier) Validate() error { | ||||
| 	if err := m.Name.IsValid(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if m.MonthsLockup < 0 { | ||||
| 		return fmt.Errorf("expected non-negative lockup, got %d", m.MonthsLockup) | ||||
| 	} | ||||
| 	if m.Factor.IsNegative() { | ||||
| 		return fmt.Errorf("expected non-negative factor, got %s", m.Factor.String()) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // String implements fmt.Stringer
 | ||||
| func (m Multiplier) String() string { | ||||
| 	return fmt.Sprintf(`Claim Multiplier: | ||||
| 	Name: %s | ||||
| 	Months Lockup %d | ||||
| 	Factor %s | ||||
| 	`, m.Name, m.MonthsLockup, m.Factor) | ||||
| } | ||||
| 
 | ||||
| // Multipliers slice of Multiplier
 | ||||
| type Multipliers []Multiplier | ||||
| 
 | ||||
| // Validate validates each multiplier
 | ||||
| func (ms Multipliers) Validate() error { | ||||
| 	for _, m := range ms { | ||||
| 		if err := m.Validate(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // String implements fmt.Stringer
 | ||||
| func (ms Multipliers) String() string { | ||||
| 	out := "Claim Multipliers\n" | ||||
| 	for _, s := range ms { | ||||
| 		out += fmt.Sprintf("%s\n", s) | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // MultiplierName name for valid multiplier
 | ||||
| type MultiplierName string | ||||
| 
 | ||||
| // IsValid checks if the input is one of the expected strings
 | ||||
| func (mn MultiplierName) IsValid() error { | ||||
| 	switch mn { | ||||
| 	case Small, Medium, Large: | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fmt.Errorf("invalid multiplier name: %s", mn) | ||||
| } | ||||
| 
 | ||||
| // Claim is an interface for handling common claim actions
 | ||||
| type Claim interface { | ||||
| 	GetOwner() sdk.AccAddress | ||||
| 	GetReward() sdk.Coin | ||||
| 	GetType() string | ||||
| } | ||||
| 
 | ||||
| // Claims is a slice of Claim
 | ||||
| type Claims []Claim | ||||
| 
 | ||||
| // BaseClaim is a common type shared by all Claims
 | ||||
| type BaseClaim struct { | ||||
| 	Owner  sdk.AccAddress `json:"owner" yaml:"owner"` | ||||
| 	Reward sdk.Coin       `json:"reward" yaml:"reward"` | ||||
| } | ||||
| 
 | ||||
| // GetOwner is a getter for Claim Owner
 | ||||
| func (c BaseClaim) GetOwner() sdk.AccAddress { return c.Owner } | ||||
| 
 | ||||
| // GetReward is a getter for Claim Reward
 | ||||
| func (c BaseClaim) GetReward() sdk.Coin { return c.Reward } | ||||
| 
 | ||||
| // GetType returns the claim type, used to identify auctions in event attributes
 | ||||
| func (c BaseClaim) GetType() string { return "base" } | ||||
| 
 | ||||
| // Validate performs a basic check of a BaseClaim fields
 | ||||
| func (c BaseClaim) Validate() error { | ||||
| 	if c.Owner.Empty() { | ||||
| 		return errors.New("claim owner cannot be empty") | ||||
| 	} | ||||
| 	if !c.Reward.IsValid() { | ||||
| 		return fmt.Errorf("invalid reward amount: %s", c.Reward) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // String implements fmt.Stringer
 | ||||
| func (c BaseClaim) String() string { | ||||
| 	return fmt.Sprintf(`Claim: | ||||
| 	Owner: %s, | ||||
| 	Reward: %s, | ||||
| 	`, c.Owner, c.Reward) | ||||
| } | ||||
| 
 | ||||
| // BaseMultiClaim is a common type shared by all Claims with multiple reward denoms
 | ||||
| type BaseMultiClaim struct { | ||||
| 	Owner  sdk.AccAddress `json:"owner" yaml:"owner"` | ||||
| 	Reward sdk.Coins      `json:"reward" yaml:"reward"` | ||||
| } | ||||
| 
 | ||||
| // GetOwner is a getter for Claim Owner
 | ||||
| func (c BaseMultiClaim) GetOwner() sdk.AccAddress { return c.Owner } | ||||
| 
 | ||||
| // GetReward is a getter for Claim Reward
 | ||||
| func (c BaseMultiClaim) GetReward() sdk.Coins { return c.Reward } | ||||
| 
 | ||||
| // GetType returns the claim type, used to identify auctions in event attributes
 | ||||
| func (c BaseMultiClaim) GetType() string { return "base" } | ||||
| 
 | ||||
| // Validate performs a basic check of a BaseClaim fields
 | ||||
| func (c BaseMultiClaim) Validate() error { | ||||
| 	if c.Owner.Empty() { | ||||
| 		return errors.New("claim owner cannot be empty") | ||||
| 	} | ||||
| 	if !c.Reward.IsValid() { | ||||
| 		return fmt.Errorf("invalid reward amount: %s", c.Reward) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // String implements fmt.Stringer
 | ||||
| func (c BaseMultiClaim) String() string { | ||||
| 	return fmt.Sprintf(`Claim: | ||||
| 	Owner: %s, | ||||
| 	Reward: %s, | ||||
| 	`, c.Owner, c.Reward) | ||||
| } | ||||
| 
 | ||||
| // -------------- Custom Claim Types --------------
 | ||||
| 
 | ||||
| // USDXMintingClaim is for USDX minting rewards
 | ||||
| type USDXMintingClaim struct { | ||||
| 	BaseClaim     `json:"base_claim" yaml:"base_claim"` | ||||
| 	RewardIndexes RewardIndexes `json:"reward_indexes" yaml:"reward_indexes"` | ||||
| } | ||||
| 
 | ||||
| // NewUSDXMintingClaim returns a new USDXMintingClaim
 | ||||
| func NewUSDXMintingClaim(owner sdk.AccAddress, reward sdk.Coin, rewardIndexes RewardIndexes) USDXMintingClaim { | ||||
| 	return USDXMintingClaim{ | ||||
| 		BaseClaim: BaseClaim{ | ||||
| 			Owner:  owner, | ||||
| 			Reward: reward, | ||||
| 		}, | ||||
| 		RewardIndexes: rewardIndexes, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // GetType returns the claim's type
 | ||||
| func (c USDXMintingClaim) GetType() string { return USDXMintingClaimType } | ||||
| 
 | ||||
| // GetReward returns the claim's reward coin
 | ||||
| func (c USDXMintingClaim) GetReward() sdk.Coin { return c.Reward } | ||||
| 
 | ||||
| // GetOwner returns the claim's owner
 | ||||
| func (c USDXMintingClaim) GetOwner() sdk.AccAddress { return c.Owner } | ||||
| 
 | ||||
| // Validate performs a basic check of a Claim fields
 | ||||
| func (c USDXMintingClaim) Validate() error { | ||||
| 	if err := c.RewardIndexes.Validate(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return c.BaseClaim.Validate() | ||||
| } | ||||
| 
 | ||||
| // String implements fmt.Stringer
 | ||||
| func (c USDXMintingClaim) String() string { | ||||
| 	return fmt.Sprintf(`%s | ||||
| 	Reward Indexes: %s, | ||||
| 	`, c.BaseClaim, c.RewardIndexes) | ||||
| } | ||||
| 
 | ||||
| // HasRewardIndex check if a claim has a reward index for the input collateral type
 | ||||
| func (c USDXMintingClaim) HasRewardIndex(collateralType string) (int64, bool) { | ||||
| 	for index, ri := range c.RewardIndexes { | ||||
| 		if ri.CollateralType == collateralType { | ||||
| 			return int64(index), true | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, false | ||||
| } | ||||
| 
 | ||||
| // USDXMintingClaims slice of USDXMintingClaim
 | ||||
| type USDXMintingClaims []USDXMintingClaim | ||||
| 
 | ||||
| // Validate checks if all the claims are valid and there are no duplicated
 | ||||
| // entries.
 | ||||
| func (cs USDXMintingClaims) Validate() error { | ||||
| 	for _, c := range cs { | ||||
| 		if err := c.Validate(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // HardLiquidityProviderClaim stores the hard liquidity provider rewards that can be claimed by owner
 | ||||
| type HardLiquidityProviderClaim struct { | ||||
| 	BaseMultiClaim         `json:"base_claim" yaml:"base_claim"` | ||||
| 	SupplyRewardIndexes    MultiRewardIndexes `json:"supply_reward_indexes" yaml:"supply_reward_indexes"` | ||||
| 	BorrowRewardIndexes    MultiRewardIndexes `json:"borrow_reward_indexes" yaml:"borrow_reward_indexes"` | ||||
| 	DelegatorRewardIndexes RewardIndexes      `json:"delegator_reward_indexes" yaml:"delegator_reward_indexes"` | ||||
| } | ||||
| 
 | ||||
| // NewHardLiquidityProviderClaim returns a new HardLiquidityProviderClaim
 | ||||
| func NewHardLiquidityProviderClaim(owner sdk.AccAddress, rewards sdk.Coins, supplyRewardIndexes, | ||||
| 	borrowRewardIndexes MultiRewardIndexes, delegatorRewardIndexes RewardIndexes) HardLiquidityProviderClaim { | ||||
| 	return HardLiquidityProviderClaim{ | ||||
| 		BaseMultiClaim: BaseMultiClaim{ | ||||
| 			Owner:  owner, | ||||
| 			Reward: rewards, | ||||
| 		}, | ||||
| 		SupplyRewardIndexes:    supplyRewardIndexes, | ||||
| 		BorrowRewardIndexes:    borrowRewardIndexes, | ||||
| 		DelegatorRewardIndexes: delegatorRewardIndexes, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // GetType returns the claim's type
 | ||||
| func (c HardLiquidityProviderClaim) GetType() string { return HardLiquidityProviderClaimType } | ||||
| 
 | ||||
| // GetReward returns the claim's reward coin
 | ||||
| func (c HardLiquidityProviderClaim) GetReward() sdk.Coins { return c.Reward } | ||||
| 
 | ||||
| // GetOwner returns the claim's owner
 | ||||
| func (c HardLiquidityProviderClaim) GetOwner() sdk.AccAddress { return c.Owner } | ||||
| 
 | ||||
| // Validate performs a basic check of a HardLiquidityProviderClaim fields
 | ||||
| func (c HardLiquidityProviderClaim) Validate() error { | ||||
| 	if err := c.SupplyRewardIndexes.Validate(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := c.BorrowRewardIndexes.Validate(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := c.DelegatorRewardIndexes.Validate(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return c.BaseMultiClaim.Validate() | ||||
| } | ||||
| 
 | ||||
| // String implements fmt.Stringer
 | ||||
| func (c HardLiquidityProviderClaim) String() string { | ||||
| 	return fmt.Sprintf(`%s | ||||
| 	Supply Reward Indexes: %s, | ||||
| 	Borrow Reward Indexes: %s, | ||||
| 	Delegator Reward Indexes: %s, | ||||
| 	`, c.BaseMultiClaim, c.SupplyRewardIndexes, c.BorrowRewardIndexes, c.DelegatorRewardIndexes) | ||||
| } | ||||
| 
 | ||||
| // HasSupplyRewardIndex check if a claim has a supply reward index for the input collateral type
 | ||||
| func (c HardLiquidityProviderClaim) HasSupplyRewardIndex(denom string) (int64, bool) { | ||||
| 	for index, ri := range c.SupplyRewardIndexes { | ||||
| 		if ri.CollateralType == denom { | ||||
| 			return int64(index), true | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, false | ||||
| } | ||||
| 
 | ||||
| // HasBorrowRewardIndex check if a claim has a borrow reward index for the input collateral type
 | ||||
| func (c HardLiquidityProviderClaim) HasBorrowRewardIndex(denom string) (int64, bool) { | ||||
| 	for index, ri := range c.BorrowRewardIndexes { | ||||
| 		if ri.CollateralType == denom { | ||||
| 			return int64(index), true | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, false | ||||
| } | ||||
| 
 | ||||
| // HasDelegatorRewardIndex check if a claim has a delegator reward index for the input collateral type
 | ||||
| func (c HardLiquidityProviderClaim) HasDelegatorRewardIndex(collateralType string) (int64, bool) { | ||||
| 	for index, ri := range c.DelegatorRewardIndexes { | ||||
| 		if ri.CollateralType == collateralType { | ||||
| 			return int64(index), true | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, false | ||||
| } | ||||
| 
 | ||||
| // HardLiquidityProviderClaims slice of HardLiquidityProviderClaim
 | ||||
| type HardLiquidityProviderClaims []HardLiquidityProviderClaim | ||||
| 
 | ||||
| // Validate checks if all the claims are valid and there are no duplicated
 | ||||
| // entries.
 | ||||
| func (cs HardLiquidityProviderClaims) Validate() error { | ||||
| 	for _, c := range cs { | ||||
| 		if err := c.Validate(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // ---------------------- Reward periods are used by the params ----------------------
 | ||||
| 
 | ||||
| // MultiRewardPeriod supports multiple reward types
 | ||||
| type MultiRewardPeriod struct { | ||||
| 	Active           bool      `json:"active" yaml:"active"` | ||||
| 	CollateralType   string    `json:"collateral_type" yaml:"collateral_type"` | ||||
| 	Start            time.Time `json:"start" yaml:"start"` | ||||
| 	End              time.Time `json:"end" yaml:"end"` | ||||
| 	RewardsPerSecond sdk.Coins `json:"rewards_per_second" yaml:"rewards_per_second"` // per second reward payouts
 | ||||
| } | ||||
| 
 | ||||
| // String implements fmt.Stringer
 | ||||
| func (mrp MultiRewardPeriod) String() string { | ||||
| 	return fmt.Sprintf(`Reward Period: | ||||
| 	Collateral Type: %s, | ||||
| 	Start: %s, | ||||
| 	End: %s, | ||||
| 	Rewards Per Second: %s, | ||||
| 	Active %t, | ||||
| 	`, mrp.CollateralType, mrp.Start, mrp.End, mrp.RewardsPerSecond, mrp.Active) | ||||
| } | ||||
| 
 | ||||
| // NewMultiRewardPeriod returns a new MultiRewardPeriod
 | ||||
| func NewMultiRewardPeriod(active bool, collateralType string, start time.Time, end time.Time, reward sdk.Coins) MultiRewardPeriod { | ||||
| 	return MultiRewardPeriod{ | ||||
| 		Active:           active, | ||||
| 		CollateralType:   collateralType, | ||||
| 		Start:            start, | ||||
| 		End:              end, | ||||
| 		RewardsPerSecond: reward, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Validate performs a basic check of a MultiRewardPeriod.
 | ||||
| func (mrp MultiRewardPeriod) Validate() error { | ||||
| 	if mrp.Start.IsZero() { | ||||
| 		return errors.New("reward period start time cannot be 0") | ||||
| 	} | ||||
| 	if mrp.End.IsZero() { | ||||
| 		return errors.New("reward period end time cannot be 0") | ||||
| 	} | ||||
| 	if mrp.Start.After(mrp.End) { | ||||
| 		return fmt.Errorf("end period time %s cannot be before start time %s", mrp.End, mrp.Start) | ||||
| 	} | ||||
| 	if !mrp.RewardsPerSecond.IsValid() { | ||||
| 		return fmt.Errorf("invalid reward amount: %s", mrp.RewardsPerSecond) | ||||
| 	} | ||||
| 	if strings.TrimSpace(mrp.CollateralType) == "" { | ||||
| 		return fmt.Errorf("reward period collateral type cannot be blank: %s", mrp) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // MultiRewardPeriods array of MultiRewardPeriod
 | ||||
| type MultiRewardPeriods []MultiRewardPeriod | ||||
| 
 | ||||
| // GetMultiRewardPeriod fetches a MultiRewardPeriod from an array of MultiRewardPeriods by its denom
 | ||||
| func (mrps MultiRewardPeriods) GetMultiRewardPeriod(denom string) (MultiRewardPeriod, bool) { | ||||
| 	for _, rp := range mrps { | ||||
| 		if rp.CollateralType == denom { | ||||
| 			return rp, true | ||||
| 		} | ||||
| 	} | ||||
| 	return MultiRewardPeriod{}, false | ||||
| } | ||||
| 
 | ||||
| // GetMultiRewardPeriodIndex returns the index of a MultiRewardPeriod inside array MultiRewardPeriods
 | ||||
| func (mrps MultiRewardPeriods) GetMultiRewardPeriodIndex(denom string) (int, bool) { | ||||
| 	for i, rp := range mrps { | ||||
| 		if rp.CollateralType == denom { | ||||
| 			return i, true | ||||
| 		} | ||||
| 	} | ||||
| 	return -1, false | ||||
| } | ||||
| 
 | ||||
| // Validate checks if all the RewardPeriods are valid and there are no duplicated
 | ||||
| // entries.
 | ||||
| func (mrps MultiRewardPeriods) Validate() error { | ||||
| 	seenPeriods := make(map[string]bool) | ||||
| 	for _, rp := range mrps { | ||||
| 		if seenPeriods[rp.CollateralType] { | ||||
| 			return fmt.Errorf("duplicated reward period with collateral type %s", rp.CollateralType) | ||||
| 		} | ||||
| 
 | ||||
| 		if err := rp.Validate(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		seenPeriods[rp.CollateralType] = true | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // ---------------------- Reward indexes are used internally in the store ----------------------
 | ||||
| 
 | ||||
| // RewardIndex stores reward accumulation information
 | ||||
| type RewardIndex struct { | ||||
| 	CollateralType string  `json:"collateral_type" yaml:"collateral_type"` | ||||
| 	RewardFactor   sdk.Dec `json:"reward_factor" yaml:"reward_factor"` | ||||
| } | ||||
| 
 | ||||
| // NewRewardIndex returns a new RewardIndex
 | ||||
| func NewRewardIndex(collateralType string, factor sdk.Dec) RewardIndex { | ||||
| 	return RewardIndex{ | ||||
| 		CollateralType: collateralType, | ||||
| 		RewardFactor:   factor, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (ri RewardIndex) String() string { | ||||
| 	return fmt.Sprintf(`Collateral Type: %s, RewardFactor: %s`, ri.CollateralType, ri.RewardFactor) | ||||
| } | ||||
| 
 | ||||
| // Validate validates reward index
 | ||||
| func (ri RewardIndex) Validate() error { | ||||
| 	if ri.RewardFactor.IsNegative() { | ||||
| 		return fmt.Errorf("reward factor value should be positive, is %s for %s", ri.RewardFactor, ri.CollateralType) | ||||
| 	} | ||||
| 	if strings.TrimSpace(ri.CollateralType) == "" { | ||||
| 		return fmt.Errorf("collateral type should not be empty") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // RewardIndexes slice of RewardIndex
 | ||||
| type RewardIndexes []RewardIndex | ||||
| 
 | ||||
| // GetRewardIndex fetches a RewardIndex by its denom
 | ||||
| func (ris RewardIndexes) GetRewardIndex(denom string) (RewardIndex, bool) { | ||||
| 	for _, ri := range ris { | ||||
| 		if ri.CollateralType == denom { | ||||
| 			return ri, true | ||||
| 		} | ||||
| 	} | ||||
| 	return RewardIndex{}, false | ||||
| } | ||||
| 
 | ||||
| // Get fetches a RewardFactor by it's denom
 | ||||
| func (ris RewardIndexes) Get(denom string) (sdk.Dec, bool) { | ||||
| 	for _, ri := range ris { | ||||
| 		if ri.CollateralType == denom { | ||||
| 			return ri.RewardFactor, true | ||||
| 		} | ||||
| 	} | ||||
| 	return sdk.Dec{}, false | ||||
| } | ||||
| 
 | ||||
| // With returns a copy of the indexes with a new reward factor added
 | ||||
| func (ris RewardIndexes) With(denom string, factor sdk.Dec) RewardIndexes { | ||||
| 	newIndexes := make(RewardIndexes, len(ris)) | ||||
| 	copy(newIndexes, ris) | ||||
| 
 | ||||
| 	for i, ri := range newIndexes { | ||||
| 		if ri.CollateralType == denom { | ||||
| 			newIndexes[i].RewardFactor = factor | ||||
| 			return newIndexes | ||||
| 		} | ||||
| 	} | ||||
| 	return append(newIndexes, NewRewardIndex(denom, factor)) | ||||
| } | ||||
| 
 | ||||
| // GetFactorIndex gets the index of a specific reward index inside the array by its index
 | ||||
| func (ris RewardIndexes) GetFactorIndex(denom string) (int, bool) { | ||||
| 	for i, ri := range ris { | ||||
| 		if ri.CollateralType == denom { | ||||
| 			return i, true | ||||
| 		} | ||||
| 	} | ||||
| 	return -1, false | ||||
| } | ||||
| 
 | ||||
| // Validate validation for reward indexes
 | ||||
| func (ris RewardIndexes) Validate() error { | ||||
| 	for _, ri := range ris { | ||||
| 		if err := ri.Validate(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // MultiRewardIndex stores reward accumulation information on multiple reward types
 | ||||
| type MultiRewardIndex struct { | ||||
| 	CollateralType string        `json:"collateral_type" yaml:"collateral_type"` | ||||
| 	RewardIndexes  RewardIndexes `json:"reward_indexes" yaml:"reward_indexes"` | ||||
| } | ||||
| 
 | ||||
| // NewMultiRewardIndex returns a new MultiRewardIndex
 | ||||
| func NewMultiRewardIndex(collateralType string, indexes RewardIndexes) MultiRewardIndex { | ||||
| 	return MultiRewardIndex{ | ||||
| 		CollateralType: collateralType, | ||||
| 		RewardIndexes:  indexes, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // GetFactorIndex gets the index of a specific reward index inside the array by its index
 | ||||
| func (mri MultiRewardIndex) GetFactorIndex(denom string) (int, bool) { | ||||
| 	for i, ri := range mri.RewardIndexes { | ||||
| 		if ri.CollateralType == denom { | ||||
| 			return i, true | ||||
| 		} | ||||
| 	} | ||||
| 	return -1, false | ||||
| } | ||||
| 
 | ||||
| func (mri MultiRewardIndex) String() string { | ||||
| 	return fmt.Sprintf(`Collateral Type: %s, Reward Indexes: %s`, mri.CollateralType, mri.RewardIndexes) | ||||
| } | ||||
| 
 | ||||
| // Validate validates multi-reward index
 | ||||
| func (mri MultiRewardIndex) Validate() error { | ||||
| 	for _, rf := range mri.RewardIndexes { | ||||
| 		if rf.RewardFactor.IsNegative() { | ||||
| 			return fmt.Errorf("reward index's factor value cannot be negative: %s", rf) | ||||
| 		} | ||||
| 	} | ||||
| 	if strings.TrimSpace(mri.CollateralType) == "" { | ||||
| 		return fmt.Errorf("collateral type should not be empty") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // MultiRewardIndexes slice of MultiRewardIndex
 | ||||
| type MultiRewardIndexes []MultiRewardIndex | ||||
| 
 | ||||
| // GetRewardIndex fetches a RewardIndex from a MultiRewardIndex by its denom
 | ||||
| func (mris MultiRewardIndexes) GetRewardIndex(denom string) (MultiRewardIndex, bool) { | ||||
| 	for _, ri := range mris { | ||||
| 		if ri.CollateralType == denom { | ||||
| 			return ri, true | ||||
| 		} | ||||
| 	} | ||||
| 	return MultiRewardIndex{}, false | ||||
| } | ||||
| 
 | ||||
| // Get fetches a RewardIndexes by it's denom
 | ||||
| func (mris MultiRewardIndexes) Get(denom string) (RewardIndexes, bool) { | ||||
| 	for _, mri := range mris { | ||||
| 		if mri.CollateralType == denom { | ||||
| 			return mri.RewardIndexes, true | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, false | ||||
| } | ||||
| 
 | ||||
| // GetRewardIndexIndex fetches a specific reward index inside the array by its denom
 | ||||
| func (mris MultiRewardIndexes) GetRewardIndexIndex(denom string) (int, bool) { | ||||
| 	for i, ri := range mris { | ||||
| 		if ri.CollateralType == denom { | ||||
| 			return i, true | ||||
| 		} | ||||
| 	} | ||||
| 	return -1, false | ||||
| } | ||||
| 
 | ||||
| // With returns a copy of the indexes with a new RewardIndexes added
 | ||||
| func (mris MultiRewardIndexes) With(denom string, indexes RewardIndexes) MultiRewardIndexes { | ||||
| 	newIndexes := mris.copy() | ||||
| 
 | ||||
| 	for i, mri := range newIndexes { | ||||
| 		if mri.CollateralType == denom { | ||||
| 			newIndexes[i].RewardIndexes = indexes | ||||
| 			return newIndexes | ||||
| 		} | ||||
| 	} | ||||
| 	return append(newIndexes, NewMultiRewardIndex(denom, indexes)) | ||||
| } | ||||
| 
 | ||||
| // GetCollateralTypes returns a slice of containing all collateral types
 | ||||
| func (mris MultiRewardIndexes) GetCollateralTypes() []string { | ||||
| 	var collateralTypes []string | ||||
| 	for _, ri := range mris { | ||||
| 		collateralTypes = append(collateralTypes, ri.CollateralType) | ||||
| 	} | ||||
| 	return collateralTypes | ||||
| } | ||||
| 
 | ||||
| // RemoveRewardIndex removes a denom's reward interest factor value
 | ||||
| func (mris MultiRewardIndexes) RemoveRewardIndex(denom string) MultiRewardIndexes { | ||||
| 	for i, ri := range mris { | ||||
| 		if ri.CollateralType == denom { | ||||
| 			// copy the slice and underlying array to avoid altering the original
 | ||||
| 			copy := mris.copy() | ||||
| 			return append(copy[:i], copy[i+1:]...) | ||||
| 		} | ||||
| 	} | ||||
| 	return mris | ||||
| } | ||||
| 
 | ||||
| // Validate validation for reward indexes
 | ||||
| func (mris MultiRewardIndexes) Validate() error { | ||||
| 	for _, mri := range mris { | ||||
| 		if err := mri.Validate(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // copy returns a copy of the slice and underlying array
 | ||||
| func (mris MultiRewardIndexes) copy() MultiRewardIndexes { | ||||
| 	newIndexes := make(MultiRewardIndexes, len(mris)) | ||||
| 	copy(newIndexes, mris) | ||||
| 	return newIndexes | ||||
| } | ||||
| @ -167,12 +167,12 @@ type HardLiquidityProviderClaim struct { | ||||
| 	BaseMultiClaim         `json:"base_claim" yaml:"base_claim"` | ||||
| 	SupplyRewardIndexes    MultiRewardIndexes `json:"supply_reward_indexes" yaml:"supply_reward_indexes"` | ||||
| 	BorrowRewardIndexes    MultiRewardIndexes `json:"borrow_reward_indexes" yaml:"borrow_reward_indexes"` | ||||
| 	DelegatorRewardIndexes RewardIndexes      `json:"delegator_reward_indexes" yaml:"delegator_reward_indexes"` | ||||
| 	DelegatorRewardIndexes MultiRewardIndexes `json:"delegator_reward_indexes" yaml:"delegator_reward_indexes"` | ||||
| } | ||||
| 
 | ||||
| // NewHardLiquidityProviderClaim returns a new HardLiquidityProviderClaim
 | ||||
| func NewHardLiquidityProviderClaim(owner sdk.AccAddress, rewards sdk.Coins, supplyRewardIndexes, | ||||
| 	borrowRewardIndexes MultiRewardIndexes, delegatorRewardIndexes RewardIndexes) HardLiquidityProviderClaim { | ||||
| 	borrowRewardIndexes, delegatorRewardIndexes MultiRewardIndexes) HardLiquidityProviderClaim { | ||||
| 	return HardLiquidityProviderClaim{ | ||||
| 		BaseMultiClaim: BaseMultiClaim{ | ||||
| 			Owner:  owner, | ||||
|  | ||||
| @ -54,7 +54,7 @@ func TestGenesisStateValidate(t *testing.T) { | ||||
| 					}, | ||||
| 					DefaultMultiRewardPeriods, | ||||
| 					DefaultMultiRewardPeriods, | ||||
| 					DefaultRewardPeriods, | ||||
| 					DefaultMultiRewardPeriods, | ||||
| 					Multipliers{ | ||||
| 						NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33")), | ||||
| 					}, | ||||
|  | ||||
| @ -27,11 +27,11 @@ var ( | ||||
| 	USDXMintingRewardFactorKeyPrefix                = []byte{0x02} // prefix for key that stores USDX minting reward factors
 | ||||
| 	PreviousUSDXMintingRewardAccrualTimeKeyPrefix   = []byte{0x03} // prefix for key that stores the blocktime
 | ||||
| 	HardLiquidityClaimKeyPrefix                     = []byte{0x04} // prefix for keys that store Hard liquidity claims
 | ||||
| 	HardSupplyRewardIndexesKeyPrefix                = []byte{0x05} // prefix for key that stores Hard supply reward factors
 | ||||
| 	HardSupplyRewardIndexesKeyPrefix                = []byte{0x05} // prefix for key that stores Hard supply reward indexes
 | ||||
| 	PreviousHardSupplyRewardAccrualTimeKeyPrefix    = []byte{0x06} // prefix for key that stores the previous time Hard supply rewards accrued
 | ||||
| 	HardBorrowRewardIndexesKeyPrefix                = []byte{0x07} // prefix for key that stores Hard borrow reward factors
 | ||||
| 	HardBorrowRewardIndexesKeyPrefix                = []byte{0x07} // prefix for key that stores Hard borrow reward indexes
 | ||||
| 	PreviousHardBorrowRewardAccrualTimeKeyPrefix    = []byte{0x08} // prefix for key that stores the previous time Hard borrow rewards accrued
 | ||||
| 	HardDelegatorRewardFactorKeyPrefix              = []byte{0x09} // prefix for key that stores Hard delegator reward factors
 | ||||
| 	HardDelegatorRewardIndexesKeyPrefix             = []byte{0x09} // prefix for key that stores Hard delegator reward indexes
 | ||||
| 	PreviousHardDelegatorRewardAccrualTimeKeyPrefix = []byte{0x10} // prefix for key that stores the previous time Hard delegator rewards accrued
 | ||||
| 
 | ||||
| 	USDXMintingRewardDenom   = "ukava" | ||||
|  | ||||
| @ -48,14 +48,14 @@ type Params struct { | ||||
| 	USDXMintingRewardPeriods   RewardPeriods      `json:"usdx_minting_reward_periods" yaml:"usdx_minting_reward_periods"` | ||||
| 	HardSupplyRewardPeriods    MultiRewardPeriods `json:"hard_supply_reward_periods" yaml:"hard_supply_reward_periods"` | ||||
| 	HardBorrowRewardPeriods    MultiRewardPeriods `json:"hard_borrow_reward_periods" yaml:"hard_borrow_reward_periods"` | ||||
| 	HardDelegatorRewardPeriods RewardPeriods      `json:"hard_delegator_reward_periods" yaml:"hard_delegator_reward_periods"` | ||||
| 	HardDelegatorRewardPeriods MultiRewardPeriods `json:"hard_delegator_reward_periods" yaml:"hard_delegator_reward_periods"` | ||||
| 	ClaimMultipliers           Multipliers        `json:"claim_multipliers" yaml:"claim_multipliers"` | ||||
| 	ClaimEnd                   time.Time          `json:"claim_end" yaml:"claim_end"` | ||||
| } | ||||
| 
 | ||||
| // NewParams returns a new params object
 | ||||
| func NewParams(usdxMinting RewardPeriods, hardSupply, hardBorrow MultiRewardPeriods, | ||||
| 	hardDelegator RewardPeriods, multipliers Multipliers, claimEnd time.Time) Params { | ||||
| func NewParams(usdxMinting RewardPeriods, hardSupply, hardBorrow, hardDelegator MultiRewardPeriods, | ||||
| 	multipliers Multipliers, claimEnd time.Time) Params { | ||||
| 	return Params{ | ||||
| 		USDXMintingRewardPeriods:   usdxMinting, | ||||
| 		HardSupplyRewardPeriods:    hardSupply, | ||||
| @ -69,7 +69,9 @@ func NewParams(usdxMinting RewardPeriods, hardSupply, hardBorrow MultiRewardPeri | ||||
| // DefaultParams returns default params for incentive module
 | ||||
| func DefaultParams() Params { | ||||
| 	return NewParams(DefaultRewardPeriods, DefaultMultiRewardPeriods, | ||||
| 		DefaultMultiRewardPeriods, DefaultRewardPeriods, DefaultMultipliers, DefaultClaimEnd) | ||||
| 		DefaultMultiRewardPeriods, DefaultMultiRewardPeriods, | ||||
| 		DefaultMultipliers, DefaultClaimEnd, | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| // String implements fmt.Stringer
 | ||||
| @ -96,7 +98,7 @@ func (p *Params) ParamSetPairs() params.ParamSetPairs { | ||||
| 		params.NewParamSetPair(KeyUSDXMintingRewardPeriods, &p.USDXMintingRewardPeriods, validateRewardPeriodsParam), | ||||
| 		params.NewParamSetPair(KeyHardSupplyRewardPeriods, &p.HardSupplyRewardPeriods, validateMultiRewardPeriodsParam), | ||||
| 		params.NewParamSetPair(KeyHardBorrowRewardPeriods, &p.HardBorrowRewardPeriods, validateMultiRewardPeriodsParam), | ||||
| 		params.NewParamSetPair(KeyHardDelegatorRewardPeriods, &p.HardDelegatorRewardPeriods, validateRewardPeriodsParam), | ||||
| 		params.NewParamSetPair(KeyHardDelegatorRewardPeriods, &p.HardDelegatorRewardPeriods, validateMultiRewardPeriodsParam), | ||||
| 		params.NewParamSetPair(KeyClaimEnd, &p.ClaimEnd, validateClaimEndParam), | ||||
| 		params.NewParamSetPair(KeyMultipliers, &p.ClaimMultipliers, validateMultipliersParam), | ||||
| 	} | ||||
| @ -121,7 +123,7 @@ func (p Params) Validate() error { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return validateRewardPeriodsParam(p.HardDelegatorRewardPeriods) | ||||
| 	return validateMultiRewardPeriodsParam(p.HardDelegatorRewardPeriods) | ||||
| } | ||||
| 
 | ||||
| func validateRewardPeriodsParam(i interface{}) error { | ||||
|  | ||||
| @ -23,7 +23,7 @@ func (suite *ParamTestSuite) TestParamValidation() { | ||||
| 		usdxMintingRewardPeriods   types.RewardPeriods | ||||
| 		hardSupplyRewardPeriods    types.MultiRewardPeriods | ||||
| 		hardBorrowRewardPeriods    types.MultiRewardPeriods | ||||
| 		hardDelegatorRewardPeriods types.RewardPeriods | ||||
| 		hardDelegatorRewardPeriods types.MultiRewardPeriods | ||||
| 		multipliers                types.Multipliers | ||||
| 		end                        time.Time | ||||
| 	} | ||||
| @ -45,7 +45,7 @@ func (suite *ParamTestSuite) TestParamValidation() { | ||||
| 				usdxMintingRewardPeriods:   types.DefaultRewardPeriods, | ||||
| 				hardSupplyRewardPeriods:    types.DefaultMultiRewardPeriods, | ||||
| 				hardBorrowRewardPeriods:    types.DefaultMultiRewardPeriods, | ||||
| 				hardDelegatorRewardPeriods: types.DefaultRewardPeriods, | ||||
| 				hardDelegatorRewardPeriods: types.DefaultMultiRewardPeriods, | ||||
| 				multipliers:                types.DefaultMultipliers, | ||||
| 				end:                        types.DefaultClaimEnd, | ||||
| 			}, | ||||
| @ -70,7 +70,7 @@ func (suite *ParamTestSuite) TestParamValidation() { | ||||
| 				}, | ||||
| 				hardSupplyRewardPeriods:    types.DefaultMultiRewardPeriods, | ||||
| 				hardBorrowRewardPeriods:    types.DefaultMultiRewardPeriods, | ||||
| 				hardDelegatorRewardPeriods: types.DefaultRewardPeriods, | ||||
| 				hardDelegatorRewardPeriods: types.DefaultMultiRewardPeriods, | ||||
| 				end:                        time.Date(2025, 10, 15, 14, 0, 0, 0, time.UTC), | ||||
| 			}, | ||||
| 			errArgs{ | ||||
|  | ||||
| @ -117,22 +117,22 @@ func NewQueryRewardFactorsParams(denom string) QueryRewardFactorsParams { | ||||
| 
 | ||||
| // RewardFactor is a unique type returned by reward factor queries
 | ||||
| type RewardFactor struct { | ||||
| 	Denom                     string        `json:"denom" yaml:"denom"` | ||||
| 	USDXMintingRewardFactor   sdk.Dec       `json:"usdx_minting_reward_factor" yaml:"usdx_minting_reward_factor"` | ||||
| 	HardSupplyRewardFactors   RewardIndexes `json:"hard_supply_reward_factors" yaml:"hard_supply_reward_factors"` | ||||
| 	HardBorrowRewardFactors   RewardIndexes `json:"hard_borrow_reward_factors" yaml:"hard_borrow_reward_factors"` | ||||
| 	HardDelegatorRewardFactor sdk.Dec       `json:"hard_delegator_reward_factor" yaml:"hard_delegator_reward_factor"` | ||||
| 	Denom                      string        `json:"denom" yaml:"denom"` | ||||
| 	USDXMintingRewardFactor    sdk.Dec       `json:"usdx_minting_reward_factor" yaml:"usdx_minting_reward_factor"` | ||||
| 	HardSupplyRewardFactors    RewardIndexes `json:"hard_supply_reward_factors" yaml:"hard_supply_reward_factors"` | ||||
| 	HardBorrowRewardFactors    RewardIndexes `json:"hard_borrow_reward_factors" yaml:"hard_borrow_reward_factors"` | ||||
| 	HardDelegatorRewardFactors RewardIndexes `json:"hard_delegator_reward_factors" yaml:"hard_delegator_reward_factors"` | ||||
| } | ||||
| 
 | ||||
| // NewRewardFactor returns a new instance of RewardFactor
 | ||||
| func NewRewardFactor(denom string, usdxMintingRewardFactor sdk.Dec, hardSupplyRewardFactors, | ||||
| 	hardBorrowRewardFactors RewardIndexes, hardDelegatorRewardFactor sdk.Dec) RewardFactor { | ||||
| 	hardBorrowRewardFactors, hardDelegatorRewardFactors RewardIndexes) RewardFactor { | ||||
| 	return RewardFactor{ | ||||
| 		Denom:                     denom, | ||||
| 		USDXMintingRewardFactor:   usdxMintingRewardFactor, | ||||
| 		HardSupplyRewardFactors:   hardSupplyRewardFactors, | ||||
| 		HardBorrowRewardFactors:   hardBorrowRewardFactors, | ||||
| 		HardDelegatorRewardFactor: hardDelegatorRewardFactor, | ||||
| 		Denom:                      denom, | ||||
| 		USDXMintingRewardFactor:    usdxMintingRewardFactor, | ||||
| 		HardSupplyRewardFactors:    hardSupplyRewardFactors, | ||||
| 		HardBorrowRewardFactors:    hardBorrowRewardFactors, | ||||
| 		HardDelegatorRewardFactors: hardDelegatorRewardFactors, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Denali Marsh
						Denali Marsh