0g-chain/x/incentive/testutil/builder.go
Ruaridh 6f193c7f2a
Refactor incentive accumulators to be the same (#970)
* add test for validate multi reward periods

* tidy up: combine files

* don't accumulate global indexes containing zeros
Previously if the time since last block was 0,
indexes were added containing 0s.
Now leave them out. Missing is assumed to be 0.

* move state independent test to types folder

* clarify reward source concept to "source shares"
- rename variables and update doc comments
- extract method from swap accumulation

* tidy up and expand swap accumulation unit tests

* rename swap test file to match others

* update swap pool id format in tests

* refactor borrow accumulation, use new accumulator

* refactor supply accumulation, use new accumulator

* refactor delegator accumulation, use accumulator

* refactor usdx accumulation, use new accumulator

* fix types const

* remove unsed methods

* more usdx minting param validation.
Protect against the rewards per second denom changing.
It should always be "ukava".

* add safety check in InitGenesis
It prevents huge accumulations on the first block by limiting all
previous accumulation times to be within one year of genesis

* add todo for adding swp token distirbution info
2021-07-22 13:53:18 +01:00

250 lines
9.4 KiB
Go

package testutil
import (
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/hard"
hardtypes "github.com/kava-labs/kava/x/hard/types"
"github.com/kava-labs/kava/x/incentive/types"
)
const (
oneYear time.Duration = time.Hour * 24 * 365
)
// IncentiveGenesisBuilder is a tool for creating an incentive genesis state.
// Helper methods add values onto a default genesis state.
// All methods are immutable and return updated copies of the builder.
type IncentiveGenesisBuilder struct {
types.GenesisState
genesisTime time.Time
}
func NewIncentiveGenesisBuilder() IncentiveGenesisBuilder {
return IncentiveGenesisBuilder{
GenesisState: types.DefaultGenesisState(),
genesisTime: time.Time{},
}
}
func (builder IncentiveGenesisBuilder) Build() types.GenesisState {
return builder.GenesisState
}
func (builder IncentiveGenesisBuilder) BuildMarshalled() app.GenesisState {
return app.GenesisState{
types.ModuleName: types.ModuleCdc.MustMarshalJSON(builder.Build()),
}
}
func (builder IncentiveGenesisBuilder) WithGenesisTime(time time.Time) IncentiveGenesisBuilder {
builder.genesisTime = time
builder.Params.ClaimEnd = time.Add(5 * oneYear)
return builder
}
// WithInitializedBorrowRewardPeriod sets the genesis time as the previous accumulation time for the specified period.
// This can be helpful in tests. With no prev time set, the first block accrues no rewards as it just sets the prev time to the current.
func (builder IncentiveGenesisBuilder) WithInitializedBorrowRewardPeriod(period types.MultiRewardPeriod) IncentiveGenesisBuilder {
builder.Params.HardBorrowRewardPeriods = append(builder.Params.HardBorrowRewardPeriods, period)
accumulationTimeForPeriod := types.NewAccumulationTime(period.CollateralType, builder.genesisTime)
builder.HardBorrowRewardState.AccumulationTimes = append(
builder.HardBorrowRewardState.AccumulationTimes,
accumulationTimeForPeriod,
)
// TODO remove to better reflect real states
builder.HardBorrowRewardState.MultiRewardIndexes = builder.HardBorrowRewardState.MultiRewardIndexes.With(
period.CollateralType,
newZeroRewardIndexesFromCoins(period.RewardsPerSecond...),
)
return builder
}
func (builder IncentiveGenesisBuilder) WithSimpleBorrowRewardPeriod(ctype string, rewardsPerSecond sdk.Coins) IncentiveGenesisBuilder {
return builder.WithInitializedBorrowRewardPeriod(builder.simpleRewardPeriod(ctype, rewardsPerSecond))
}
// WithInitializedSupplyRewardPeriod sets the genesis time as the previous accumulation time for the specified period.
// This can be helpful in tests. With no prev time set, the first block accrues no rewards as it just sets the prev time to the current.
func (builder IncentiveGenesisBuilder) WithInitializedSupplyRewardPeriod(period types.MultiRewardPeriod) IncentiveGenesisBuilder {
builder.Params.HardSupplyRewardPeriods = append(builder.Params.HardSupplyRewardPeriods, period)
accumulationTimeForPeriod := types.NewAccumulationTime(period.CollateralType, builder.genesisTime)
builder.HardSupplyRewardState.AccumulationTimes = append(
builder.HardSupplyRewardState.AccumulationTimes,
accumulationTimeForPeriod,
)
// TODO remove to better reflect real states
builder.HardSupplyRewardState.MultiRewardIndexes = builder.HardSupplyRewardState.MultiRewardIndexes.With(
period.CollateralType,
newZeroRewardIndexesFromCoins(period.RewardsPerSecond...),
)
return builder
}
func (builder IncentiveGenesisBuilder) WithSimpleSupplyRewardPeriod(ctype string, rewardsPerSecond sdk.Coins) IncentiveGenesisBuilder {
return builder.WithInitializedSupplyRewardPeriod(builder.simpleRewardPeriod(ctype, rewardsPerSecond))
}
// WithInitializedDelegatorRewardPeriod sets the genesis time as the previous accumulation time for the specified period.
// This can be helpful in tests. With no prev time set, the first block accrues no rewards as it just sets the prev time to the current.
func (builder IncentiveGenesisBuilder) WithInitializedDelegatorRewardPeriod(period types.MultiRewardPeriod) IncentiveGenesisBuilder {
builder.Params.DelegatorRewardPeriods = append(builder.Params.DelegatorRewardPeriods, period)
accumulationTimeForPeriod := types.NewAccumulationTime(period.CollateralType, builder.genesisTime)
builder.DelegatorRewardState.AccumulationTimes = append(
builder.DelegatorRewardState.AccumulationTimes,
accumulationTimeForPeriod,
)
// TODO remove to better reflect real states
builder.DelegatorRewardState.MultiRewardIndexes = builder.DelegatorRewardState.MultiRewardIndexes.With(
period.CollateralType,
newZeroRewardIndexesFromCoins(period.RewardsPerSecond...),
)
return builder
}
func (builder IncentiveGenesisBuilder) WithSimpleDelegatorRewardPeriod(ctype string, rewardsPerSecond sdk.Coins) IncentiveGenesisBuilder {
return builder.WithInitializedDelegatorRewardPeriod(builder.simpleRewardPeriod(ctype, rewardsPerSecond))
}
// WithInitializedSwapRewardPeriod sets the genesis time as the previous accumulation time for the specified period.
// This can be helpful in tests. With no prev time set, the first block accrues no rewards as it just sets the prev time to the current.
func (builder IncentiveGenesisBuilder) WithInitializedSwapRewardPeriod(period types.MultiRewardPeriod) IncentiveGenesisBuilder {
builder.Params.SwapRewardPeriods = append(builder.Params.SwapRewardPeriods, period)
accumulationTimeForPeriod := types.NewAccumulationTime(period.CollateralType, builder.genesisTime)
builder.SwapRewardState.AccumulationTimes = append(
builder.SwapRewardState.AccumulationTimes,
accumulationTimeForPeriod,
)
return builder
}
func (builder IncentiveGenesisBuilder) WithSimpleSwapRewardPeriod(poolID string, rewardsPerSecond sdk.Coins) IncentiveGenesisBuilder {
return builder.WithInitializedSwapRewardPeriod(builder.simpleRewardPeriod(poolID, rewardsPerSecond))
}
// WithInitializedUSDXRewardPeriod sets the genesis time as the previous accumulation time for the specified period.
// This can be helpful in tests. With no prev time set, the first block accrues no rewards as it just sets the prev time to the current.
func (builder IncentiveGenesisBuilder) WithInitializedUSDXRewardPeriod(period types.RewardPeriod) IncentiveGenesisBuilder {
builder.Params.USDXMintingRewardPeriods = append(builder.Params.USDXMintingRewardPeriods, period)
accumulationTimeForPeriod := types.NewAccumulationTime(period.CollateralType, builder.genesisTime)
builder.USDXRewardState.AccumulationTimes = append(
builder.USDXRewardState.AccumulationTimes,
accumulationTimeForPeriod,
)
// TODO remove to better reflect real states
builder.USDXRewardState.MultiRewardIndexes = builder.USDXRewardState.MultiRewardIndexes.With(
period.CollateralType,
newZeroRewardIndexesFromCoins(period.RewardsPerSecond),
)
return builder
}
func (builder IncentiveGenesisBuilder) WithSimpleUSDXRewardPeriod(ctype string, rewardsPerSecond sdk.Coin) IncentiveGenesisBuilder {
return builder.WithInitializedUSDXRewardPeriod(types.NewRewardPeriod(
true,
ctype,
builder.genesisTime,
builder.genesisTime.Add(4*oneYear),
rewardsPerSecond,
))
}
func (builder IncentiveGenesisBuilder) WithMultipliers(multipliers types.Multipliers) IncentiveGenesisBuilder {
builder.Params.ClaimMultipliers = multipliers
return builder
}
func (builder IncentiveGenesisBuilder) simpleRewardPeriod(ctype string, rewardsPerSecond sdk.Coins) types.MultiRewardPeriod {
return types.NewMultiRewardPeriod(
true,
ctype,
builder.genesisTime,
builder.genesisTime.Add(4*oneYear),
rewardsPerSecond,
)
}
func newZeroRewardIndexesFromCoins(coins ...sdk.Coin) types.RewardIndexes {
var ri types.RewardIndexes
for _, coin := range coins {
ri = ri.With(coin.Denom, sdk.ZeroDec())
}
return ri
}
// HardGenesisBuilder is a tool for creating a hard genesis state.
// Helper methods add values onto a default genesis state.
// All methods are immutable and return updated copies of the builder.
type HardGenesisBuilder struct {
hardtypes.GenesisState
genesisTime time.Time
}
func NewHardGenesisBuilder() HardGenesisBuilder {
return HardGenesisBuilder{
GenesisState: hardtypes.DefaultGenesisState(),
}
}
func (builder HardGenesisBuilder) Build() hardtypes.GenesisState {
return builder.GenesisState
}
func (builder HardGenesisBuilder) BuildMarshalled() app.GenesisState {
return app.GenesisState{
hardtypes.ModuleName: hardtypes.ModuleCdc.MustMarshalJSON(builder.Build()),
}
}
func (builder HardGenesisBuilder) WithGenesisTime(genTime time.Time) HardGenesisBuilder {
builder.genesisTime = genTime
return builder
}
func (builder HardGenesisBuilder) WithInitializedMoneyMarket(market hard.MoneyMarket) HardGenesisBuilder {
builder.Params.MoneyMarkets = append(builder.Params.MoneyMarkets, market)
builder.PreviousAccumulationTimes = append(
builder.PreviousAccumulationTimes,
hardtypes.NewGenesisAccumulationTime(market.Denom, builder.genesisTime, sdk.OneDec(), sdk.OneDec()),
)
return builder
}
func (builder HardGenesisBuilder) WithMinBorrow(minUSDValue sdk.Dec) HardGenesisBuilder {
builder.Params.MinimumBorrowUSDValue = minUSDValue
return builder
}
func NewStandardMoneyMarket(denom string) hardtypes.MoneyMarket {
return hardtypes.NewMoneyMarket(
denom,
hard.NewBorrowLimit(
false,
sdk.NewDec(1e15),
sdk.MustNewDecFromStr("0.6"),
),
denom+":usd",
sdk.NewInt(1e6),
hard.NewInterestRateModel(
sdk.MustNewDecFromStr("0.05"),
sdk.MustNewDecFromStr("2"),
sdk.MustNewDecFromStr("0.8"),
sdk.MustNewDecFromStr("10"),
),
sdk.MustNewDecFromStr("0.05"),
sdk.ZeroDec(),
)
}