mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 15:25:18 +00:00
[R4R] feat: add variable length lockups for incentive rewards (#655)
* fix: update params in spec to match implementation * feat: add variable length lockups for incentive rewards * fix typos * update spec * address review comments * feat: improve claim test
This commit is contained in:
parent
b1493d307c
commit
7292b8843a
@ -1,10 +1,6 @@
|
||||
package incentive
|
||||
|
||||
// nolint
|
||||
// autogenerated code using github.com/rigelrozanski/multitool
|
||||
// aliases generated for the following subdirectories:
|
||||
// ALIASGEN: github.com/kava-labs/kava/x/incentive/keeper
|
||||
// ALIASGEN: github.com/kava-labs/kava/x/incentive/types
|
||||
// DO NOT EDIT - generated by aliasgen tool (github.com/rhuairahrighairidh/aliasgen)
|
||||
|
||||
import (
|
||||
"github.com/kava-labs/kava/x/incentive/keeper"
|
||||
@ -12,89 +8,104 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
AttributeKeyClaimAmount = types.AttributeKeyClaimAmount
|
||||
AttributeKeyClaimPeriod = types.AttributeKeyClaimPeriod
|
||||
AttributeKeyClaimedBy = types.AttributeKeyClaimedBy
|
||||
AttributeKeyRewardPeriod = types.AttributeKeyRewardPeriod
|
||||
AttributeValueCategory = types.AttributeValueCategory
|
||||
DefaultParamspace = types.DefaultParamspace
|
||||
EventTypeClaim = types.EventTypeClaim
|
||||
EventTypeRewardPeriod = types.EventTypeRewardPeriod
|
||||
EventTypeClaimPeriod = types.EventTypeClaimPeriod
|
||||
EventTypeClaimPeriodExpiry = types.EventTypeClaimPeriodExpiry
|
||||
AttributeValueCategory = types.AttributeValueCategory
|
||||
AttributeKeyClaimedBy = types.AttributeKeyClaimedBy
|
||||
AttributeKeyClaimAmount = types.AttributeKeyClaimAmount
|
||||
AttributeKeyRewardPeriod = types.AttributeKeyRewardPeriod
|
||||
AttributeKeyClaimPeriod = types.AttributeKeyClaimPeriod
|
||||
EventTypeRewardPeriod = types.EventTypeRewardPeriod
|
||||
Large = types.Large
|
||||
Medium = types.Medium
|
||||
ModuleName = types.ModuleName
|
||||
StoreKey = types.StoreKey
|
||||
RouterKey = types.RouterKey
|
||||
DefaultParamspace = types.DefaultParamspace
|
||||
QuerierRoute = types.QuerierRoute
|
||||
QueryGetClaimPeriods = types.QueryGetClaimPeriods
|
||||
QueryGetClaims = types.QueryGetClaims
|
||||
RestClaimOwner = types.RestClaimOwner
|
||||
RestClaimCollateralType = types.RestClaimCollateralType
|
||||
QueryGetParams = types.QueryGetParams
|
||||
QueryGetRewardPeriods = types.QueryGetRewardPeriods
|
||||
RestClaimCollateralType = types.RestClaimCollateralType
|
||||
RestClaimOwner = types.RestClaimOwner
|
||||
RouterKey = types.RouterKey
|
||||
Small = types.Small
|
||||
StoreKey = types.StoreKey
|
||||
)
|
||||
|
||||
var (
|
||||
// functions aliases
|
||||
// function aliases
|
||||
NewKeeper = keeper.NewKeeper
|
||||
NewQuerier = keeper.NewQuerier
|
||||
GetTotalVestingPeriodLength = types.GetTotalVestingPeriodLength
|
||||
RegisterCodec = types.RegisterCodec
|
||||
NewGenesisState = types.NewGenesisState
|
||||
DefaultGenesisState = types.DefaultGenesisState
|
||||
BytesToUint64 = types.BytesToUint64
|
||||
DefaultGenesisState = types.DefaultGenesisState
|
||||
DefaultParams = types.DefaultParams
|
||||
GetClaimPeriodPrefix = types.GetClaimPeriodPrefix
|
||||
GetClaimPrefix = types.GetClaimPrefix
|
||||
GetTotalVestingPeriodLength = types.GetTotalVestingPeriodLength
|
||||
NewAugmentedClaim = types.NewAugmentedClaim
|
||||
NewClaim = types.NewClaim
|
||||
NewClaimPeriod = types.NewClaimPeriod
|
||||
NewGenesisState = types.NewGenesisState
|
||||
NewMsgClaimReward = types.NewMsgClaimReward
|
||||
NewMultiplier = types.NewMultiplier
|
||||
NewParams = types.NewParams
|
||||
DefaultParams = types.DefaultParams
|
||||
ParamKeyTable = types.ParamKeyTable
|
||||
NewReward = types.NewReward
|
||||
NewPeriod = types.NewPeriod
|
||||
NewQueryClaimsParams = types.NewQueryClaimsParams
|
||||
NewReward = types.NewReward
|
||||
NewRewardPeriod = types.NewRewardPeriod
|
||||
NewClaimPeriod = types.NewClaimPeriod
|
||||
NewClaim = types.NewClaim
|
||||
NewRewardPeriodFromReward = types.NewRewardPeriodFromReward
|
||||
ParamKeyTable = types.ParamKeyTable
|
||||
RegisterCodec = types.RegisterCodec
|
||||
|
||||
// variable aliases
|
||||
ModuleCdc = types.ModuleCdc
|
||||
ClaimKeyPrefix = types.ClaimKeyPrefix
|
||||
ClaimPeriodKeyPrefix = types.ClaimPeriodKeyPrefix
|
||||
DefaultActive = types.DefaultActive
|
||||
DefaultPreviousBlockTime = types.DefaultPreviousBlockTime
|
||||
DefaultRewards = types.DefaultRewards
|
||||
ErrAccountNotFound = types.ErrAccountNotFound
|
||||
ErrClaimNotFound = types.ErrClaimNotFound
|
||||
ErrClaimPeriodNotFound = types.ErrClaimPeriodNotFound
|
||||
ErrInvalidAccountType = types.ErrInvalidAccountType
|
||||
ErrNoClaimsFound = types.ErrNoClaimsFound
|
||||
ErrInsufficientModAccountBalance = types.ErrInsufficientModAccountBalance
|
||||
RewardPeriodKeyPrefix = types.RewardPeriodKeyPrefix
|
||||
ClaimPeriodKeyPrefix = types.ClaimPeriodKeyPrefix
|
||||
ClaimKeyPrefix = types.ClaimKeyPrefix
|
||||
NextClaimPeriodIDPrefix = types.NextClaimPeriodIDPrefix
|
||||
PreviousBlockTimeKey = types.PreviousBlockTimeKey
|
||||
ErrInvalidAccountType = types.ErrInvalidAccountType
|
||||
ErrInvalidMultiplier = types.ErrInvalidMultiplier
|
||||
ErrNoClaimsFound = types.ErrNoClaimsFound
|
||||
ErrZeroClaim = types.ErrZeroClaim
|
||||
GovDenom = types.GovDenom
|
||||
IncentiveMacc = types.IncentiveMacc
|
||||
KeyActive = types.KeyActive
|
||||
KeyRewards = types.KeyRewards
|
||||
DefaultActive = types.DefaultActive
|
||||
DefaultRewards = types.DefaultRewards
|
||||
DefaultPreviousBlockTime = types.DefaultPreviousBlockTime
|
||||
GovDenom = types.GovDenom
|
||||
ModuleCdc = types.ModuleCdc
|
||||
NextClaimPeriodIDPrefix = types.NextClaimPeriodIDPrefix
|
||||
PreviousBlockTimeKey = types.PreviousBlockTimeKey
|
||||
PrincipalDenom = types.PrincipalDenom
|
||||
IncentiveMacc = types.IncentiveMacc
|
||||
RewardPeriodKeyPrefix = types.RewardPeriodKeyPrefix
|
||||
)
|
||||
|
||||
type (
|
||||
Keeper = keeper.Keeper
|
||||
SupplyKeeper = types.SupplyKeeper
|
||||
CdpKeeper = types.CdpKeeper
|
||||
AccountKeeper = types.AccountKeeper
|
||||
AugmentedClaim = types.AugmentedClaim
|
||||
AugmentedClaims = types.AugmentedClaims
|
||||
CdpKeeper = types.CdpKeeper
|
||||
Claim = types.Claim
|
||||
ClaimPeriod = types.ClaimPeriod
|
||||
ClaimPeriods = types.ClaimPeriods
|
||||
Claims = types.Claims
|
||||
GenesisClaimPeriodID = types.GenesisClaimPeriodID
|
||||
GenesisClaimPeriodIDs = types.GenesisClaimPeriodIDs
|
||||
GenesisState = types.GenesisState
|
||||
MsgClaimReward = types.MsgClaimReward
|
||||
Multiplier = types.Multiplier
|
||||
MultiplierName = types.MultiplierName
|
||||
Multipliers = types.Multipliers
|
||||
Params = types.Params
|
||||
Reward = types.Reward
|
||||
Rewards = types.Rewards
|
||||
QueryClaimsParams = types.QueryClaimsParams
|
||||
PostClaimReq = types.PostClaimReq
|
||||
QueryClaimsParams = types.QueryClaimsParams
|
||||
Reward = types.Reward
|
||||
RewardPeriod = types.RewardPeriod
|
||||
RewardPeriods = types.RewardPeriods
|
||||
ClaimPeriod = types.ClaimPeriod
|
||||
ClaimPeriods = types.ClaimPeriods
|
||||
Claim = types.Claim
|
||||
Claims = types.Claims
|
||||
Rewards = types.Rewards
|
||||
SupplyKeeper = types.SupplyKeeper
|
||||
)
|
||||
|
@ -44,7 +44,7 @@ func getCmdClaim(cdc *codec.Codec) *cobra.Command {
|
||||
$ %s tx %s claim kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw bnb
|
||||
`, version.ClientName, types.ModuleName),
|
||||
),
|
||||
Args: cobra.ExactArgs(2),
|
||||
Args: cobra.ExactArgs(3),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
@ -54,7 +54,7 @@ func getCmdClaim(cdc *codec.Codec) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := types.NewMsgClaimReward(owner, args[1])
|
||||
msg := types.NewMsgClaimReward(owner, args[1], args[2])
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -42,7 +42,7 @@ func postClaimHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
msg := types.NewMsgClaimReward(requestBody.Sender, requestBody.CollateralType)
|
||||
msg := types.NewMsgClaimReward(requestBody.Sender, requestBody.CollateralType, requestBody.MultiplierName)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
|
@ -1,6 +1,8 @@
|
||||
package incentive
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
@ -30,7 +32,7 @@ func handleMsgClaimReward(ctx sdk.Context, k keeper.Keeper, msg types.MsgClaimRe
|
||||
}
|
||||
|
||||
for _, claim := range claims {
|
||||
err := k.PayoutClaim(ctx, claim.Owner, claim.CollateralType, claim.ClaimPeriodID)
|
||||
err := k.PayoutClaim(ctx, claim.Owner, claim.CollateralType, claim.ClaimPeriodID, types.MultiplierName(strings.ToLower(msg.MultiplierName)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ func (suite *HandlerTestSuite) addClaim() {
|
||||
macc := supplyKeeper.GetModuleAccount(suite.ctx, kavadist.ModuleName)
|
||||
err := supplyKeeper.MintCoins(suite.ctx, macc.GetName(), cs(c("ukava", 1000000)))
|
||||
suite.Require().NoError(err)
|
||||
cp := incentive.NewClaimPeriod("bnb", 1, suite.ctx.BlockTime().Add(time.Hour*168), time.Hour*8766)
|
||||
cp := incentive.NewClaimPeriod("bnb", 1, suite.ctx.BlockTime().Add(time.Hour*168), incentive.Multipliers{incentive.NewMultiplier(incentive.Small, 1, sdk.MustNewDecFromStr("0.33"))})
|
||||
suite.NotPanics(func() {
|
||||
suite.keeper.SetClaimPeriod(suite.ctx, cp)
|
||||
})
|
||||
@ -67,7 +67,7 @@ func (suite *HandlerTestSuite) addClaim() {
|
||||
|
||||
func (suite *HandlerTestSuite) TestMsgClaimReward() {
|
||||
suite.addClaim()
|
||||
msg := incentive.NewMsgClaimReward(suite.addrs[0], "bnb")
|
||||
msg := incentive.NewMsgClaimReward(suite.addrs[0], "bnb", "small")
|
||||
res, err := suite.handler(suite.ctx, msg)
|
||||
suite.NoError(err)
|
||||
suite.Require().NotNil(res)
|
||||
|
@ -52,7 +52,7 @@ func (suite *KeeperTestSuite) getModuleAccount(name string) supplyexported.Modul
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestGetSetDeleteRewardPeriod() {
|
||||
rp := types.NewRewardPeriod("bnb", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), time.Hour*8766)
|
||||
rp := types.NewRewardPeriod("bnb", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))})
|
||||
_, found := suite.keeper.GetRewardPeriod(suite.ctx, "bnb")
|
||||
suite.False(found)
|
||||
suite.NotPanics(func() {
|
||||
@ -69,7 +69,7 @@ func (suite *KeeperTestSuite) TestGetSetDeleteRewardPeriod() {
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestGetSetDeleteClaimPeriod() {
|
||||
cp := types.NewClaimPeriod("bnb", 1, suite.ctx.BlockTime().Add(time.Hour*168), time.Hour*8766)
|
||||
cp := types.NewClaimPeriod("bnb", 1, suite.ctx.BlockTime().Add(time.Hour*168), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))})
|
||||
_, found := suite.keeper.GetClaimPeriod(suite.ctx, 1, "bnb")
|
||||
suite.False(found)
|
||||
suite.NotPanics(func() {
|
||||
@ -149,13 +149,13 @@ func (suite *KeeperTestSuite) TestIterateMethods() {
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) addObjectsToStore() {
|
||||
rp1 := types.NewRewardPeriod("bnb", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), time.Hour*8766)
|
||||
rp2 := types.NewRewardPeriod("xrp", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), time.Hour*8766)
|
||||
rp1 := types.NewRewardPeriod("bnb", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))})
|
||||
rp2 := types.NewRewardPeriod("xrp", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))})
|
||||
suite.keeper.SetRewardPeriod(suite.ctx, rp1)
|
||||
suite.keeper.SetRewardPeriod(suite.ctx, rp2)
|
||||
|
||||
cp1 := types.NewClaimPeriod("bnb", 1, suite.ctx.BlockTime().Add(time.Hour*168), time.Hour*8766)
|
||||
cp2 := types.NewClaimPeriod("xrp", 1, suite.ctx.BlockTime().Add(time.Hour*168), time.Hour*8766)
|
||||
cp1 := types.NewClaimPeriod("bnb", 1, suite.ctx.BlockTime().Add(time.Hour*168), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))})
|
||||
cp2 := types.NewClaimPeriod("xrp", 1, suite.ctx.BlockTime().Add(time.Hour*168), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))})
|
||||
suite.keeper.SetClaimPeriod(suite.ctx, cp1)
|
||||
suite.keeper.SetClaimPeriod(suite.ctx, cp2)
|
||||
|
||||
@ -168,7 +168,7 @@ func (suite *KeeperTestSuite) addObjectsToStore() {
|
||||
suite.keeper.SetClaim(suite.ctx, c2)
|
||||
|
||||
params := types.NewParams(
|
||||
true, types.Rewards{types.NewReward(true, "bnb", c("ukava", 1000000000), time.Hour*7*24, time.Hour*24*365, time.Hour*7*24)},
|
||||
true, types.Rewards{types.NewReward(true, "bnb", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))}, time.Hour*7*24)},
|
||||
)
|
||||
suite.keeper.SetParams(suite.ctx, params)
|
||||
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
// PayoutClaim sends the timelocked claim coins to the input address
|
||||
func (k Keeper) PayoutClaim(ctx sdk.Context, addr sdk.AccAddress, collateralType string, id uint64) error {
|
||||
func (k Keeper) PayoutClaim(ctx sdk.Context, addr sdk.AccAddress, collateralType string, id uint64, multiplierName types.MultiplierName) error {
|
||||
claim, found := k.GetClaim(ctx, addr, collateralType, id)
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrClaimNotFound, "id: %d, collateral type %s, address: %s", id, collateralType, addr)
|
||||
@ -24,7 +24,20 @@ func (k Keeper) PayoutClaim(ctx sdk.Context, addr sdk.AccAddress, collateralType
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrClaimPeriodNotFound, "id: %d, collateral type: %s", id, collateralType)
|
||||
}
|
||||
err := k.SendTimeLockedCoinsToAccount(ctx, types.IncentiveMacc, addr, sdk.NewCoins(claim.Reward), int64(claimPeriod.TimeLock.Seconds()))
|
||||
|
||||
multiplier, found := claimPeriod.GetMultiplier(multiplierName)
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrInvalidMultiplier, string(multiplierName))
|
||||
}
|
||||
|
||||
rewardAmount := sdk.NewDecFromInt(claim.Reward.Amount).Mul(multiplier.Factor).RoundInt()
|
||||
if rewardAmount.IsZero() {
|
||||
return types.ErrZeroClaim
|
||||
}
|
||||
rewardCoin := sdk.NewCoin(claim.Reward.Denom, rewardAmount)
|
||||
length := ctx.BlockTime().AddDate(0, int(multiplier.MonthsLockup), 0).Unix() - ctx.BlockTime().Unix()
|
||||
|
||||
err := k.SendTimeLockedCoinsToAccount(ctx, types.IncentiveMacc, addr, sdk.NewCoins(rewardCoin), length)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"github.com/kava-labs/kava/x/incentive/types"
|
||||
"github.com/kava-labs/kava/x/kavadist"
|
||||
validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
)
|
||||
|
||||
func (suite *KeeperTestSuite) setupChain() {
|
||||
@ -85,8 +86,8 @@ func (suite *KeeperTestSuite) setupExpiredClaims() {
|
||||
)
|
||||
|
||||
// creates two claim periods, one expired, and one that expires in the future
|
||||
cp1 := types.NewClaimPeriod("bnb", 1, time.Unix(90, 0), time.Hour*8766)
|
||||
cp2 := types.NewClaimPeriod("xrp", 1, time.Unix(110, 0), time.Hour*8766)
|
||||
cp1 := types.NewClaimPeriod("bnb", 1, time.Unix(90, 0), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})
|
||||
cp2 := types.NewClaimPeriod("xrp", 1, time.Unix(110, 0), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})
|
||||
suite.keeper = tApp.GetIncentiveKeeper()
|
||||
suite.keeper.SetClaimPeriod(ctx, cp1)
|
||||
suite.keeper.SetClaimPeriod(ctx, cp2)
|
||||
@ -417,50 +418,6 @@ func (suite *KeeperTestSuite) TestSendCoinsToInvalidAccount() {
|
||||
suite.Require().True(errors.Is(err, types.ErrInvalidAccountType))
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestPayoutClaim() {
|
||||
suite.setupChain() // adds 3 accounts - 1 periodic vesting account, 1 base account, and 1 validator vesting account
|
||||
|
||||
// add 2 claims that correspond to an existing claim period and one claim that has no corresponding claim period
|
||||
cp1 := types.NewClaimPeriod("bnb", 1, suite.ctx.BlockTime().Add(time.Hour*168), time.Hour*8766)
|
||||
suite.keeper.SetClaimPeriod(suite.ctx, cp1)
|
||||
// valid claim for addrs[0]
|
||||
c1 := types.NewClaim(suite.addrs[0], c("ukava", 100), "bnb", 1)
|
||||
// invalid claim for addrs[0]
|
||||
c2 := types.NewClaim(suite.addrs[0], c("ukava", 100), "xrp", 1)
|
||||
// valid claim for addrs[1]
|
||||
c3 := types.NewClaim(suite.addrs[1], c("ukava", 100), "bnb", 1)
|
||||
suite.keeper.SetClaim(suite.ctx, c1)
|
||||
suite.keeper.SetClaim(suite.ctx, c2)
|
||||
suite.keeper.SetClaim(suite.ctx, c3)
|
||||
|
||||
// existing claim with corresponding claim period successfully claimed by existing periodic vesting account
|
||||
err := suite.keeper.PayoutClaim(suite.ctx.WithBlockTime(time.Unix(3700, 0)), suite.addrs[0], "bnb", 1)
|
||||
suite.Require().NoError(err)
|
||||
acc := suite.getAccount(suite.addrs[0])
|
||||
// account is a periodic vesting account
|
||||
vacc, ok := acc.(*vesting.PeriodicVestingAccount)
|
||||
suite.True(ok)
|
||||
// vesting balance is correct
|
||||
suite.Equal(cs(c("ukava", 500)), vacc.OriginalVesting)
|
||||
|
||||
// existing claim with corresponding claim period successfully claimed by base account
|
||||
err = suite.keeper.PayoutClaim(suite.ctx, suite.addrs[1], "bnb", 1)
|
||||
suite.Require().NoError(err)
|
||||
acc = suite.getAccount(suite.addrs[1])
|
||||
// account has become a periodic vesting account
|
||||
vacc, ok = acc.(*vesting.PeriodicVestingAccount)
|
||||
suite.True(ok)
|
||||
// vesting balance is correct
|
||||
suite.Equal(cs(c("ukava", 100)), vacc.OriginalVesting)
|
||||
|
||||
// addrs[3] has no claims
|
||||
err = suite.keeper.PayoutClaim(suite.ctx, suite.addrs[3], "bnb", 1)
|
||||
suite.Require().True(errors.Is(err, types.ErrClaimNotFound))
|
||||
// addrs[0] has an xrp claim, but there is not corresponding claim period
|
||||
err = suite.keeper.PayoutClaim(suite.ctx, suite.addrs[0], "xrp", 1)
|
||||
suite.Require().True(errors.Is(err, types.ErrClaimPeriodNotFound))
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestDeleteExpiredClaimPeriods() {
|
||||
suite.setupExpiredClaims() // creates new app state with one non-expired claim period (xrp) and one expired claim period (bnb) as well as a claim that corresponds to each claim period
|
||||
|
||||
@ -491,3 +448,229 @@ func (suite *KeeperTestSuite) TestDeleteExpiredClaimPeriods() {
|
||||
suite.True(found)
|
||||
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestPayoutClaim() {
|
||||
type args struct {
|
||||
claimOwner sdk.AccAddress
|
||||
collateralType string
|
||||
id uint64
|
||||
multiplier types.MultiplierName
|
||||
blockTime time.Time
|
||||
rewards types.Rewards
|
||||
rewardperiods types.RewardPeriods
|
||||
claimPeriods types.ClaimPeriods
|
||||
claims types.Claims
|
||||
genIDs types.GenesisClaimPeriodIDs
|
||||
active bool
|
||||
validatorVesting bool
|
||||
expectedAccountBalance sdk.Coins
|
||||
expectedModAccountBalance sdk.Coins
|
||||
expectedVestingAccount bool
|
||||
expectedVestingLength int64
|
||||
}
|
||||
type errArgs struct {
|
||||
expectPass bool
|
||||
contains string
|
||||
}
|
||||
type claimTest struct {
|
||||
name string
|
||||
args args
|
||||
errArgs errArgs
|
||||
}
|
||||
testCases := []claimTest{
|
||||
{
|
||||
"valid small claim",
|
||||
args{
|
||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
||||
collateralType: "bnb-a",
|
||||
id: 1,
|
||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
||||
rewards: types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)},
|
||||
rewardperiods: types.RewardPeriods{types.NewRewardPeriod("bnb-a", time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), c("ukava", 1000), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})},
|
||||
claimPeriods: types.ClaimPeriods{types.NewClaimPeriod("bnb-a", 1, time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})},
|
||||
claims: types.Claims{types.NewClaim(sdk.AccAddress(crypto.AddressHash([]byte("test"))), sdk.NewCoin("ukava", sdk.NewInt(1000)), "bnb-a", 1)},
|
||||
genIDs: types.GenesisClaimPeriodIDs{types.GenesisClaimPeriodID{CollateralType: "bnb-a", ID: 2}},
|
||||
active: true,
|
||||
validatorVesting: false,
|
||||
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
||||
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500))),
|
||||
expectedVestingAccount: true,
|
||||
expectedVestingLength: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).AddDate(0, 1, 0).Unix() - time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Unix(),
|
||||
multiplier: types.Small,
|
||||
},
|
||||
errArgs{
|
||||
expectPass: true,
|
||||
contains: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
"valid large claim",
|
||||
args{
|
||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
||||
collateralType: "bnb-a",
|
||||
id: 1,
|
||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
||||
rewards: types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)},
|
||||
rewardperiods: types.RewardPeriods{types.NewRewardPeriod("bnb-a", time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), c("ukava", 1000), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})},
|
||||
claimPeriods: types.ClaimPeriods{types.NewClaimPeriod("bnb-a", 1, time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})},
|
||||
claims: types.Claims{types.NewClaim(sdk.AccAddress(crypto.AddressHash([]byte("test"))), sdk.NewCoin("ukava", sdk.NewInt(1000)), "bnb-a", 1)},
|
||||
genIDs: types.GenesisClaimPeriodIDs{types.GenesisClaimPeriodID{CollateralType: "bnb-a", ID: 2}},
|
||||
active: true,
|
||||
validatorVesting: false,
|
||||
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
||||
expectedModAccountBalance: sdk.Coins(nil),
|
||||
expectedVestingAccount: true,
|
||||
expectedVestingLength: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).AddDate(0, 12, 0).Unix() - time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Unix(),
|
||||
multiplier: types.Large,
|
||||
},
|
||||
errArgs{
|
||||
expectPass: true,
|
||||
contains: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
"valid liquid claim",
|
||||
args{
|
||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
||||
collateralType: "bnb-a",
|
||||
id: 1,
|
||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
||||
rewards: types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)},
|
||||
rewardperiods: types.RewardPeriods{types.NewRewardPeriod("bnb-a", time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), c("ukava", 1000), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24*2), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})},
|
||||
claimPeriods: types.ClaimPeriods{types.NewClaimPeriod("bnb-a", 1, time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})},
|
||||
claims: types.Claims{types.NewClaim(sdk.AccAddress(crypto.AddressHash([]byte("test"))), sdk.NewCoin("ukava", sdk.NewInt(1000)), "bnb-a", 1)},
|
||||
genIDs: types.GenesisClaimPeriodIDs{types.GenesisClaimPeriodID{CollateralType: "bnb-a", ID: 2}},
|
||||
active: true,
|
||||
validatorVesting: false,
|
||||
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
||||
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500))),
|
||||
expectedVestingAccount: false,
|
||||
expectedVestingLength: 0,
|
||||
multiplier: types.Small,
|
||||
},
|
||||
errArgs{
|
||||
expectPass: true,
|
||||
contains: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
"no matching claim",
|
||||
args{
|
||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
||||
collateralType: "btcb-a",
|
||||
id: 1,
|
||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
||||
rewards: types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)},
|
||||
rewardperiods: types.RewardPeriods{types.NewRewardPeriod("bnb-a", time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), c("ukava", 1000), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24*2), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})},
|
||||
claimPeriods: types.ClaimPeriods{types.NewClaimPeriod("bnb-a", 1, time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})},
|
||||
claims: types.Claims{types.NewClaim(sdk.AccAddress(crypto.AddressHash([]byte("test"))), sdk.NewCoin("ukava", sdk.NewInt(1000)), "bnb-a", 1)},
|
||||
genIDs: types.GenesisClaimPeriodIDs{types.GenesisClaimPeriodID{CollateralType: "bnb-a", ID: 2}},
|
||||
active: true,
|
||||
validatorVesting: false,
|
||||
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
||||
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500))),
|
||||
expectedVestingAccount: false,
|
||||
expectedVestingLength: 0,
|
||||
multiplier: types.Small,
|
||||
},
|
||||
errArgs{
|
||||
expectPass: false,
|
||||
contains: "no claim with input id found for owner and collateral type",
|
||||
},
|
||||
},
|
||||
{
|
||||
"validator vesting claim",
|
||||
args{
|
||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
||||
collateralType: "bnb-a",
|
||||
id: 1,
|
||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
||||
rewards: types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)},
|
||||
rewardperiods: types.RewardPeriods{types.NewRewardPeriod("bnb-a", time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), c("ukava", 1000), time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})},
|
||||
claimPeriods: types.ClaimPeriods{types.NewClaimPeriod("bnb-a", 1, time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC).Add(time.Hour*7*24), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})},
|
||||
claims: types.Claims{types.NewClaim(sdk.AccAddress(crypto.AddressHash([]byte("test"))), sdk.NewCoin("ukava", sdk.NewInt(1000)), "bnb-a", 1)},
|
||||
genIDs: types.GenesisClaimPeriodIDs{types.GenesisClaimPeriodID{CollateralType: "bnb-a", ID: 2}},
|
||||
active: true,
|
||||
validatorVesting: true,
|
||||
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
||||
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(500))),
|
||||
expectedVestingAccount: false,
|
||||
expectedVestingLength: 0,
|
||||
multiplier: types.Small,
|
||||
},
|
||||
errArgs{
|
||||
expectPass: false,
|
||||
contains: "account type not supported",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
// create new app with one funded account
|
||||
config := sdk.GetConfig()
|
||||
app.SetBech32AddressPrefixes(config)
|
||||
// Initialize test app and set context
|
||||
tApp := app.NewTestApp()
|
||||
ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tc.args.blockTime})
|
||||
authGS := app.NewAuthGenState(
|
||||
[]sdk.AccAddress{tc.args.claimOwner},
|
||||
[]sdk.Coins{
|
||||
sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
||||
})
|
||||
incentiveGS := types.NewGenesisState(types.NewParams(tc.args.active, tc.args.rewards), types.DefaultPreviousBlockTime, tc.args.rewardperiods, tc.args.claimPeriods, tc.args.claims, tc.args.genIDs)
|
||||
tApp.InitializeFromGenesisStates(authGS, app.GenesisState{types.ModuleName: types.ModuleCdc.MustMarshalJSON(incentiveGS)})
|
||||
if tc.args.validatorVesting {
|
||||
ak := tApp.GetAccountKeeper()
|
||||
acc := ak.GetAccount(ctx, tc.args.claimOwner)
|
||||
bacc := auth.NewBaseAccount(acc.GetAddress(), acc.GetCoins(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence())
|
||||
bva, err := vesting.NewBaseVestingAccount(
|
||||
bacc,
|
||||
sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(20))), time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC).Unix()+100)
|
||||
suite.Require().NoError(err)
|
||||
vva := validatorvesting.NewValidatorVestingAccountRaw(
|
||||
bva,
|
||||
time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC).Unix(),
|
||||
vesting.Periods{
|
||||
vesting.Period{Length: 25, Amount: cs(c("bnb", 5))},
|
||||
vesting.Period{Length: 25, Amount: cs(c("bnb", 5))},
|
||||
vesting.Period{Length: 25, Amount: cs(c("bnb", 5))},
|
||||
vesting.Period{Length: 25, Amount: cs(c("bnb", 5))}},
|
||||
sdk.ConsAddress(crypto.AddressHash([]byte("test"))),
|
||||
sdk.AccAddress{},
|
||||
95,
|
||||
)
|
||||
err = vva.Validate()
|
||||
suite.Require().NoError(err)
|
||||
ak.SetAccount(ctx, vva)
|
||||
}
|
||||
supplyKeeper := tApp.GetSupplyKeeper()
|
||||
supplyKeeper.MintCoins(ctx, types.IncentiveMacc, sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000))))
|
||||
keeper := tApp.GetIncentiveKeeper()
|
||||
suite.app = tApp
|
||||
suite.ctx = ctx
|
||||
suite.keeper = keeper
|
||||
|
||||
err := suite.keeper.PayoutClaim(suite.ctx, tc.args.claimOwner, tc.args.collateralType, tc.args.id, tc.args.multiplier)
|
||||
|
||||
if tc.errArgs.expectPass {
|
||||
suite.Require().NoError(err)
|
||||
acc := suite.getAccount(tc.args.claimOwner)
|
||||
suite.Require().Equal(tc.args.expectedAccountBalance, acc.GetCoins())
|
||||
mAcc := suite.getModuleAccount(types.IncentiveMacc)
|
||||
suite.Require().Equal(tc.args.expectedModAccountBalance, mAcc.GetCoins())
|
||||
vacc, ok := acc.(*vesting.PeriodicVestingAccount)
|
||||
if tc.args.expectedVestingAccount {
|
||||
suite.Require().True(ok)
|
||||
suite.Require().Equal(tc.args.expectedVestingLength, vacc.VestingPeriods[0].Length)
|
||||
} else {
|
||||
suite.Require().False(ok)
|
||||
}
|
||||
_, f := suite.keeper.GetClaim(ctx, tc.args.claimOwner, tc.args.collateralType, tc.args.id)
|
||||
suite.Require().False(f)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
|
||||
// HandleRewardPeriodExpiry deletes expired RewardPeriods from the store and creates a ClaimPeriod in the store for each expired RewardPeriod
|
||||
func (k Keeper) HandleRewardPeriodExpiry(ctx sdk.Context, rp types.RewardPeriod) {
|
||||
k.CreateUniqueClaimPeriod(ctx, rp.CollateralType, rp.ClaimEnd, rp.ClaimTimeLock)
|
||||
k.CreateUniqueClaimPeriod(ctx, rp.CollateralType, rp.ClaimEnd, rp.ClaimMultipliers)
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.RewardPeriodKeyPrefix)
|
||||
store.Delete([]byte(rp.CollateralType))
|
||||
return
|
||||
@ -93,9 +93,9 @@ func (k Keeper) ApplyRewardsToCdps(ctx sdk.Context) {
|
||||
}
|
||||
|
||||
// CreateUniqueClaimPeriod creates a new claim period in the store and updates the highest claim period id
|
||||
func (k Keeper) CreateUniqueClaimPeriod(ctx sdk.Context, collateralType string, end time.Time, timeLock time.Duration) {
|
||||
func (k Keeper) CreateUniqueClaimPeriod(ctx sdk.Context, collateralType string, end time.Time, multipliers types.Multipliers) {
|
||||
id := k.GetNextClaimPeriodID(ctx, collateralType)
|
||||
claimPeriod := types.NewClaimPeriod(collateralType, id, end, timeLock)
|
||||
claimPeriod := types.NewClaimPeriod(collateralType, id, end, multipliers)
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
types.EventTypeClaimPeriod,
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
func (suite *KeeperTestSuite) TestExpireRewardPeriod() {
|
||||
rp := types.NewRewardPeriod("bnb", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), time.Hour*8766)
|
||||
rp := types.NewRewardPeriod("bnb", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})
|
||||
suite.keeper.SetRewardPeriod(suite.ctx, rp)
|
||||
suite.keeper.SetNextClaimPeriodID(suite.ctx, "bnb", 1)
|
||||
suite.NotPanics(func() {
|
||||
@ -26,7 +26,7 @@ func (suite *KeeperTestSuite) TestExpireRewardPeriod() {
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestAddToClaim() {
|
||||
rp := types.NewRewardPeriod("bnb", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), time.Hour*8766)
|
||||
rp := types.NewRewardPeriod("bnb", suite.ctx.BlockTime(), suite.ctx.BlockTime().Add(time.Hour*168), c("ukava", 100000000), suite.ctx.BlockTime().Add(time.Hour*168*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})
|
||||
suite.keeper.SetRewardPeriod(suite.ctx, rp)
|
||||
suite.keeper.SetNextClaimPeriodID(suite.ctx, "bnb", 1)
|
||||
suite.keeper.HandleRewardPeriodExpiry(suite.ctx, rp)
|
||||
@ -44,7 +44,7 @@ func (suite *KeeperTestSuite) TestAddToClaim() {
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestCreateRewardPeriod() {
|
||||
reward := types.NewReward(true, "bnb", c("ukava", 1000000000), time.Hour*7*24, time.Hour*24*365, time.Hour*7*24)
|
||||
reward := types.NewReward(true, "bnb", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)
|
||||
suite.NotPanics(func() {
|
||||
suite.keeper.CreateNewRewardPeriod(suite.ctx, reward)
|
||||
})
|
||||
@ -53,9 +53,9 @@ func (suite *KeeperTestSuite) TestCreateRewardPeriod() {
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestCreateAndDeleteRewardsPeriods() {
|
||||
reward1 := types.NewReward(true, "bnb", c("ukava", 1000000000), time.Hour*7*24, time.Hour*24*365, time.Hour*7*24)
|
||||
reward2 := types.NewReward(false, "xrp", c("ukava", 1000000000), time.Hour*7*24, time.Hour*24*365, time.Hour*7*24)
|
||||
reward3 := types.NewReward(false, "btc", c("ukava", 1000000000), time.Hour*7*24, time.Hour*24*365, time.Hour*7*24)
|
||||
reward1 := types.NewReward(true, "bnb", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)
|
||||
reward2 := types.NewReward(false, "xrp", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)
|
||||
reward3 := types.NewReward(false, "btc", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)
|
||||
// add a reward period to the store for a non-active reward
|
||||
suite.NotPanics(func() {
|
||||
suite.keeper.CreateNewRewardPeriod(suite.ctx, reward3)
|
||||
@ -214,10 +214,10 @@ func (suite *KeeperTestSuite) setupCdpChain() {
|
||||
}
|
||||
incentiveGS := types.NewGenesisState(
|
||||
types.NewParams(
|
||||
true, types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, time.Hour*24*365, time.Hour*7*24)},
|
||||
true, types.Rewards{types.NewReward(true, "bnb-a", c("ukava", 1000000000), time.Hour*7*24, types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))}, time.Hour*7*24)},
|
||||
),
|
||||
types.DefaultPreviousBlockTime,
|
||||
types.RewardPeriods{types.NewRewardPeriod("bnb-a", ctx.BlockTime(), ctx.BlockTime().Add(time.Hour*7*24), c("ukava", 1000), ctx.BlockTime().Add(time.Hour*7*24*2), time.Hour*365*24)},
|
||||
types.RewardPeriods{types.NewRewardPeriod("bnb-a", ctx.BlockTime(), ctx.BlockTime().Add(time.Hour*7*24), c("ukava", 1000), ctx.BlockTime().Add(time.Hour*7*24*2), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))})},
|
||||
types.ClaimPeriods{},
|
||||
types.Claims{},
|
||||
types.GenesisClaimPeriodIDs{})
|
||||
|
@ -93,7 +93,7 @@ func (AppModuleBasic) ProposalContents(_ module.SimulationState) []sim.WeightedP
|
||||
return nil
|
||||
}
|
||||
|
||||
// WeightedOperations returns the all the bep3 module operations with their respective weights.
|
||||
// WeightedOperations returns the all the incentive module operations with their respective weights.
|
||||
func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation {
|
||||
return simulation.WeightedOperations(simState.AppParams, simState.Cdc, am.accountKeeper, am.supplyKeeper, am.keeper)
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ func TestDecodeDistributionStore(t *testing.T) {
|
||||
|
||||
// Set up RewardPeriod, ClaimPeriod, Claim, and previous block time
|
||||
rewardPeriod := types.NewRewardPeriod("btc", time.Now().UTC(), time.Now().Add(time.Hour*1).UTC(),
|
||||
sdk.NewCoin("ukava", sdk.NewInt(10000000000)), time.Now().Add(time.Hour*2).UTC(), time.Duration(time.Hour*2))
|
||||
claimPeriod := types.NewClaimPeriod("btc", 1, time.Now().Add(time.Hour*24).UTC(), time.Duration(time.Hour*24))
|
||||
sdk.NewCoin("ukava", sdk.NewInt(10000000000)), time.Now().Add(time.Hour*2).UTC(), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))})
|
||||
claimPeriod := types.NewClaimPeriod("btc", 1, time.Now().Add(time.Hour*24).UTC(), types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33"))})
|
||||
addr, _ := sdk.AccAddressFromBech32("kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw")
|
||||
claim := types.NewClaim(addr, sdk.NewCoin("ukava", sdk.NewInt(1000000)), "bnb", 1)
|
||||
prevBlockTime := time.Now().Add(time.Hour * -1).UTC()
|
||||
|
@ -67,12 +67,15 @@ func genRewards(r *rand.Rand) types.Rewards {
|
||||
// total reward is in range (half max total reward, max total reward)
|
||||
amount := simulation.RandIntBetween(r, int(MaxTotalAssetReward.Int64()/2), int(MaxTotalAssetReward.Int64()))
|
||||
totalRewards := sdk.NewInt64Coin(RewardDenom, int64(amount))
|
||||
// generate a random number of hours between 6-48 to use for reward's times
|
||||
numbHours := simulation.RandIntBetween(r, 6, 48)
|
||||
duration := time.Duration(time.Hour * time.Duration(numbHours))
|
||||
timeLock := time.Duration(time.Hour * time.Duration(numbHours/2)) // half as long as duration
|
||||
claimDuration := time.Hour * time.Duration(numbHours*2) // twice as long as duration
|
||||
rewards[i] = types.NewReward(active, denom, totalRewards, duration, timeLock, claimDuration)
|
||||
// generate a random number of months for lockups
|
||||
numMonthsSmall := simulation.RandIntBetween(r, 0, 6)
|
||||
numMonthsLarge := simulation.RandIntBetween(r, 7, 12)
|
||||
multiplierSmall := types.NewMultiplier(types.Small, int64(numMonthsSmall), sdk.MustNewDecFromStr("0.33"))
|
||||
multiplierLarge := types.NewMultiplier(types.Large, int64(numMonthsLarge), sdk.MustNewDecFromStr("1.0"))
|
||||
|
||||
duration := time.Duration(time.Hour * time.Duration(simulation.RandIntBetween(r, 1, 48)))
|
||||
claimDuration := time.Hour * time.Duration(simulation.RandIntBetween(r, 1, 48)) // twice as long as duration
|
||||
rewards[i] = types.NewReward(active, denom, totalRewards, duration, types.Multipliers{multiplierSmall, multiplierLarge}, claimDuration)
|
||||
}
|
||||
return rewards
|
||||
}
|
||||
@ -90,9 +93,9 @@ func genRewardPeriods(r *rand.Rand, timestamp time.Time, rewards types.Rewards)
|
||||
// Earlier periods have larger rewards
|
||||
amount := sdk.NewCoin("ukava", baseRewardAmount.Mul(sdk.NewInt(int64(i))))
|
||||
claimEnd := end.Add(reward.ClaimDuration)
|
||||
claimTimeLock := reward.TimeLock
|
||||
claimMultipliers := reward.ClaimMultipliers
|
||||
// Create reward period and append to array
|
||||
rewardPeriods[i] = types.NewRewardPeriod(reward.CollateralType, start, end, amount, claimEnd, claimTimeLock)
|
||||
rewardPeriods[i] = types.NewRewardPeriod(reward.CollateralType, start, end, amount, claimEnd, claimMultipliers)
|
||||
// Update start time of next reward period
|
||||
rewardPeriodStart = end
|
||||
}
|
||||
@ -110,9 +113,9 @@ func genClaimPeriods(rewardPeriods types.RewardPeriods) types.ClaimPeriods {
|
||||
denomRewardPeriodsCount[denom] = numbRewardPeriods
|
||||
// Set end and timelock from the associated reward period
|
||||
end := rewardPeriod.ClaimEnd
|
||||
claimTimeLock := rewardPeriod.ClaimTimeLock
|
||||
claimMultipliers := rewardPeriod.ClaimMultipliers
|
||||
// Create the new claim period for this reward period
|
||||
claimPeriods[i] = types.NewClaimPeriod(denom, numbRewardPeriods, end, claimTimeLock)
|
||||
claimPeriods[i] = types.NewClaimPeriod(denom, numbRewardPeriods, end, claimMultipliers)
|
||||
}
|
||||
return claimPeriods
|
||||
}
|
||||
|
@ -105,7 +105,13 @@ func SimulateMsgClaimReward(ak auth.AccountKeeper, sk types.SupplyKeeper, k keep
|
||||
return simulation.NoOpMsg(types.ModuleName), nil, fmt.Errorf("couldn't find account %s", claimer.Address)
|
||||
}
|
||||
|
||||
msg := types.NewMsgClaimReward(claimer.Address, claim.CollateralType)
|
||||
multiplierName := types.Small
|
||||
|
||||
if simulation.RandIntBetween(r, 0, 1) == 0 {
|
||||
multiplierName = types.Large
|
||||
}
|
||||
|
||||
msg := types.NewMsgClaimReward(claimer.Address, claim.CollateralType, string(multiplierName))
|
||||
|
||||
tx := helpers.GenTx(
|
||||
[]sdk.Msg{msg},
|
||||
|
@ -6,4 +6,4 @@ order: 1
|
||||
|
||||
This module presents an implementation of user incentives that are controlled by governance. When users take a certain action, in this case opening a CDP, they become eligible for rewards. Rewards are __opt in__ meaning that users must submit a message before the claim deadline to claim their rewards. The goals and background of this module were subject of a previous Kava governance proposal, which can be found [here](https://ipfs.io/ipfs/QmSYedssC3nyQacDJmNcREtgmTPyaMx2JX7RNkMdAVkdkr/user-growth-fund-proposal.pdf).
|
||||
|
||||
When governance adds a collateral type to be eligible for rewards, they set the rate (coins/time) at which rewards are given to users, the length of each reward period, the length of each claim period, and the amount of time reward coins must vest before users who claim them can transfer them. For the duration of a reward period, any user that has minted USDX using an eligible collateral type will ratably accumulate rewards in a `Claim` object. For example, if a user has minted 10% of all USDX for the duration of the reward period, they will earn 10% of all rewards for that period. When the reward period ends, the claim period begins immediately, at which point users can submit a message to claim their rewards. Rewards are time-locked, meaning that when a user claims rewards they will receive them as a vesting balance on their account. Vesting balances can be used to stake coins, but cannot be transferred until the vesting period ends.
|
||||
When governance adds a collateral type to be eligible for rewards, they set the rate (coins/time) at which rewards are given to users, the length of each reward period, the length of each claim period, and the amount of time reward coins must vest before users who claim them can transfer them. For the duration of a reward period, any user that has minted USDX using an eligible collateral type will ratably accumulate rewards in a `Claim` object. For example, if a user has minted 10% of all USDX for the duration of the reward period, they will earn 10% of all rewards for that period. When the reward period ends, the claim period begins immediately, at which point users can submit a message to claim their rewards. Rewards are time-locked, meaning that when a user claims rewards they will receive them as a vesting balance on their account. Vesting balances can be used to stake coins, but cannot be transferred until the vesting period ends. In addition to vesting, rewards can have multipliers that vary the number of tokens received. For example, a reward with a vesting period of 1 month may have a multiplier of 0.25, meaning that the user will receive 25% of the reward balance if they choose that vesting schedule.
|
||||
|
@ -15,13 +15,14 @@ type Params struct {
|
||||
Rewards Rewards `json:"rewards" yaml:"rewards"`
|
||||
}
|
||||
|
||||
// Reward stores the specified state for a single reward period.
|
||||
// Reward stores the specified state for a single reward period.
|
||||
type Reward struct {
|
||||
Active bool `json:"active" yaml:"active"` // governance switch to disable a period
|
||||
Denom string `json:"denom" yaml:"denom"` // the collateral denom rewards apply to, must be found in the cdp collaterals
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"` // the collateral type rewards apply to, must be found in the cdp collaterals
|
||||
AvailableRewards sdk.Coin `json:"available_rewards" yaml:"available_rewards"` // the total amount of coins distributed per period
|
||||
Duration time.Duration `json:"duration" yaml:"duration"` // the duration of the period
|
||||
TimeLock time.Duration `json:"time_lock" yaml:"time_lock"` // how long rewards for this period are timelocked
|
||||
ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"` // the reward multiplier and timelock schedule - applied at the time users claim rewards
|
||||
ClaimDuration time.Duration `json:"claim_duration" yaml:"claim_duration"` // how long users have after the period ends to claim their rewards
|
||||
}
|
||||
```
|
||||
|
@ -10,11 +10,13 @@ Users claim rewards using a `MsgClaimReward`.
|
||||
// MsgClaimReward message type used to claim rewards
|
||||
type MsgClaimReward struct {
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
Denom string `json:"denom" yaml:"denom"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"`
|
||||
}
|
||||
```
|
||||
|
||||
## State Modifications
|
||||
|
||||
* Accumulated rewards for active claims are transferred from the `kavadist` module account to the users account as vesting coins
|
||||
* The number of coins transferred is determined by the multiplier in the message. For example, the multiplier equals 1.0, 100% of the claim's reward value is transferred. If the multiplier equals 0.5, 50% of the claim's reward value is transferred.
|
||||
* The corresponding claim object(s) are deleted from the store
|
||||
|
@ -14,10 +14,18 @@ The incentive module contains the following parameters:
|
||||
Each `Reward` has the following parameters
|
||||
|
||||
| Key | Type | Example | Description |
|
||||
|------------------|--------------------|------------------------------------|----------------------------------------------------------------|
|
||||
|------------------|--------------------|------------------------------------|-------------------------------------------------------------------------------------------------------------------|
|
||||
| Active | bool | "true | boolean for if rewards for this collateral are active |
|
||||
| Denom | string | "bnb" | the collateral for which rewards are eligible |
|
||||
| AvailableRewards | object (coin) | `{"denom":"kava","amount":"1000"}` | the rewards available per reward period |
|
||||
| Duration | string (time ns) | "172800000000000" | the duration of each reward period |
|
||||
| TimeLock | string (time ns) | "172800000000000" | the duration for which claimed rewards will be vesting |
|
||||
| ClaimMultipliers | array (Multiplier) | [{see below}] | the number of months for which claimed rewards will be vesting and the multiplier applied when rewards are claimed|
|
||||
| ClaimDuration | string (time ns) | "172800000000000" | how long users have to claim rewards before they expire |
|
||||
|
||||
Each `Multiplier` has the following parameters:
|
||||
|
||||
| Key | Type | Example | Description |
|
||||
|-----------------------|--------------------|--------------------------|-----------------------------------------------------------------|
|
||||
| Name | string | "large" | the unique name of the reward multiplier |
|
||||
| MonthsLockup | int | "6" | number of months HARD tokens with this multiplier are locked |
|
||||
| Factor | Dec | "0.5" | the scaling factor for HARD tokens claimed with this multiplier |
|
||||
|
@ -6,11 +6,14 @@ import (
|
||||
|
||||
// DONTCOVER
|
||||
|
||||
// Incentive module errors
|
||||
var (
|
||||
ErrClaimNotFound = sdkerrors.Register(ModuleName, 1, "no claim with input id found for owner and collateral type")
|
||||
ErrClaimPeriodNotFound = sdkerrors.Register(ModuleName, 2, "no claim period found for id and collateral type")
|
||||
ErrInvalidAccountType = sdkerrors.Register(ModuleName, 3, "account type not supported")
|
||||
ErrNoClaimsFound = sdkerrors.Register(ModuleName, 4, "no claims with collateral type found for address")
|
||||
ErrInsufficientModAccountBalance = sdkerrors.Register(ModuleName, 5, "module account has insufficient balance to pay claim")
|
||||
ErrAccountNotFound = sdkerrors.Register(ModuleName, 6, "account not found")
|
||||
ErrClaimNotFound = sdkerrors.Register(ModuleName, 2, "no claim with input id found for owner and collateral type")
|
||||
ErrClaimPeriodNotFound = sdkerrors.Register(ModuleName, 3, "no claim period found for id and collateral type")
|
||||
ErrInvalidAccountType = sdkerrors.Register(ModuleName, 4, "account type not supported")
|
||||
ErrNoClaimsFound = sdkerrors.Register(ModuleName, 5, "no claims with collateral type found for address")
|
||||
ErrInsufficientModAccountBalance = sdkerrors.Register(ModuleName, 6, "module account has insufficient balance to pay claim")
|
||||
ErrAccountNotFound = sdkerrors.Register(ModuleName, 7, "account not found")
|
||||
ErrInvalidMultiplier = sdkerrors.Register(ModuleName, 8, "invalid rewards multiplier")
|
||||
ErrZeroClaim = sdkerrors.Register(ModuleName, 9, "cannot claim - claim amount rounds to zero")
|
||||
)
|
||||
|
@ -68,11 +68,11 @@ func TestGenesisStateValidate(t *testing.T) {
|
||||
rewards := Rewards{
|
||||
NewReward(
|
||||
true, "bnb", sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
time.Hour*24*7, time.Hour*8766, time.Hour*24*14,
|
||||
time.Hour*24*7, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}, time.Hour*24*14,
|
||||
),
|
||||
}
|
||||
rewardPeriods := RewardPeriods{NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, 10)}
|
||||
claimPeriods := ClaimPeriods{NewClaimPeriod("bnb", 10, now, 100)}
|
||||
rewardPeriods := RewardPeriods{NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))})}
|
||||
claimPeriods := ClaimPeriods{NewClaimPeriod("bnb", 10, now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))})}
|
||||
claims := Claims{NewClaim(owner, sdk.NewCoin("bnb", sdk.OneInt()), "bnb", 10)}
|
||||
gcps := GenesisClaimPeriodIDs{{CollateralType: "bnb", ID: 1}}
|
||||
|
||||
|
@ -15,13 +15,15 @@ var _ sdk.Msg = &MsgClaimReward{}
|
||||
type MsgClaimReward struct {
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"`
|
||||
}
|
||||
|
||||
// NewMsgClaimReward returns a new MsgClaimReward.
|
||||
func NewMsgClaimReward(sender sdk.AccAddress, collateralType string) MsgClaimReward {
|
||||
func NewMsgClaimReward(sender sdk.AccAddress, collateralType, multiplierName string) MsgClaimReward {
|
||||
return MsgClaimReward{
|
||||
Sender: sender,
|
||||
CollateralType: collateralType,
|
||||
MultiplierName: multiplierName,
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +41,7 @@ func (msg MsgClaimReward) ValidateBasic() error {
|
||||
if strings.TrimSpace(msg.CollateralType) == "" {
|
||||
return fmt.Errorf("collateral type cannot be blank")
|
||||
}
|
||||
return nil
|
||||
return MultiplierName(strings.ToLower(msg.MultiplierName)).IsValid()
|
||||
}
|
||||
|
||||
// GetSignBytes gets the canonical byte representation of the Msg.
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
type msgTest struct {
|
||||
from sdk.AccAddress
|
||||
collateralType string
|
||||
multiplierName string
|
||||
expectPass bool
|
||||
}
|
||||
|
||||
@ -29,16 +30,25 @@ func (suite *MsgTestSuite) SetupTest() {
|
||||
{
|
||||
from: sdk.AccAddress(crypto.AddressHash([]byte("KavaTest1"))),
|
||||
collateralType: "bnb",
|
||||
multiplierName: "large",
|
||||
expectPass: true,
|
||||
},
|
||||
{
|
||||
from: sdk.AccAddress(crypto.AddressHash([]byte("KavaTest1"))),
|
||||
collateralType: "",
|
||||
multiplierName: "small",
|
||||
expectPass: false,
|
||||
},
|
||||
{
|
||||
from: sdk.AccAddress{},
|
||||
collateralType: "bnb",
|
||||
multiplierName: "medium",
|
||||
expectPass: false,
|
||||
},
|
||||
{
|
||||
from: sdk.AccAddress(crypto.AddressHash([]byte("KavaTest1"))),
|
||||
collateralType: "bnb",
|
||||
multiplierName: "huge",
|
||||
expectPass: false,
|
||||
},
|
||||
}
|
||||
@ -47,7 +57,7 @@ func (suite *MsgTestSuite) SetupTest() {
|
||||
|
||||
func (suite *MsgTestSuite) TestMsgValidation() {
|
||||
for _, t := range suite.tests {
|
||||
msg := types.NewMsgClaimReward(t.from, t.collateralType)
|
||||
msg := types.NewMsgClaimReward(t.from, t.collateralType, t.multiplierName)
|
||||
err := msg.ValidateBasic()
|
||||
if t.expectPass {
|
||||
suite.Require().NoError(err)
|
||||
|
@ -14,6 +14,13 @@ import (
|
||||
kavadistTypes "github.com/kava-labs/kava/x/kavadist/types"
|
||||
)
|
||||
|
||||
// Valid reward multipliers
|
||||
const (
|
||||
Small MultiplierName = "small"
|
||||
Medium MultiplierName = "medium"
|
||||
Large MultiplierName = "large"
|
||||
)
|
||||
|
||||
// Parameter keys and default values
|
||||
var (
|
||||
KeyActive = []byte("Active")
|
||||
@ -40,7 +47,7 @@ func NewParams(active bool, rewards Rewards) Params {
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultParams returns default params for kavadist module
|
||||
// DefaultParams returns default params for incentive module
|
||||
func DefaultParams() Params {
|
||||
return NewParams(DefaultActive, DefaultRewards)
|
||||
}
|
||||
@ -97,18 +104,18 @@ type Reward struct {
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"` // the collateral type rewards apply to, must be found in the cdp collaterals
|
||||
AvailableRewards sdk.Coin `json:"available_rewards" yaml:"available_rewards"` // the total amount of coins distributed per period
|
||||
Duration time.Duration `json:"duration" yaml:"duration"` // the duration of the period
|
||||
TimeLock time.Duration `json:"time_lock" yaml:"time_lock"` // how long rewards for this period are timelocked
|
||||
ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"` // the reward multiplier and timelock schedule - applied at the time users claim rewards
|
||||
ClaimDuration time.Duration `json:"claim_duration" yaml:"claim_duration"` // how long users have after the period ends to claim their rewards
|
||||
}
|
||||
|
||||
// NewReward returns a new Reward
|
||||
func NewReward(active bool, collateralType string, reward sdk.Coin, duration time.Duration, timelock time.Duration, claimDuration time.Duration) Reward {
|
||||
func NewReward(active bool, collateralType string, reward sdk.Coin, duration time.Duration, multiplier Multipliers, claimDuration time.Duration) Reward {
|
||||
return Reward{
|
||||
Active: active,
|
||||
CollateralType: collateralType,
|
||||
AvailableRewards: reward,
|
||||
Duration: duration,
|
||||
TimeLock: timelock,
|
||||
ClaimMultipliers: multiplier,
|
||||
ClaimDuration: claimDuration,
|
||||
}
|
||||
}
|
||||
@ -120,9 +127,9 @@ func (r Reward) String() string {
|
||||
CollateralType: %s,
|
||||
Available Rewards: %s,
|
||||
Duration: %s,
|
||||
Time Lock: %s,
|
||||
%s,
|
||||
Claim Duration: %s`,
|
||||
r.Active, r.CollateralType, r.AvailableRewards, r.Duration, r.TimeLock, r.ClaimDuration)
|
||||
r.Active, r.CollateralType, r.AvailableRewards, r.Duration, r.ClaimMultipliers, r.ClaimDuration)
|
||||
}
|
||||
|
||||
// Validate performs a basic check of a reward fields.
|
||||
@ -136,8 +143,8 @@ func (r Reward) Validate() error {
|
||||
if r.Duration <= 0 {
|
||||
return fmt.Errorf("reward duration must be positive, is %s for %s", r.Duration, r.CollateralType)
|
||||
}
|
||||
if r.TimeLock < 0 {
|
||||
return fmt.Errorf("reward timelock must be non-negative, is %s for %s", r.TimeLock, r.CollateralType)
|
||||
if err := r.ClaimMultipliers.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if r.ClaimDuration <= 0 {
|
||||
return fmt.Errorf("claim duration must be positive, is %s for %s", r.ClaimDuration, r.CollateralType)
|
||||
@ -177,3 +184,77 @@ func (rs Rewards) String() string {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))},
|
||||
ClaimDuration: time.Hour * 24 * 14,
|
||||
},
|
||||
},
|
||||
@ -61,7 +61,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))},
|
||||
ClaimDuration: time.Hour * 24 * 14,
|
||||
},
|
||||
},
|
||||
@ -81,7 +81,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))},
|
||||
ClaimDuration: time.Hour * 24 * 14,
|
||||
},
|
||||
types.Reward{
|
||||
@ -89,7 +89,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))},
|
||||
ClaimDuration: time.Hour * 24 * 14,
|
||||
},
|
||||
},
|
||||
@ -109,7 +109,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * -24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))},
|
||||
ClaimDuration: time.Hour * 24 * 14,
|
||||
},
|
||||
},
|
||||
@ -129,14 +129,14 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * -8766,
|
||||
ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, -1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))},
|
||||
ClaimDuration: time.Hour * 24 * 14,
|
||||
},
|
||||
},
|
||||
},
|
||||
errResult: errResult{
|
||||
expectPass: false,
|
||||
contains: "reward timelock must be non-negative",
|
||||
contains: "expected non-negative lockup",
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -149,7 +149,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(10000000000)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))},
|
||||
ClaimDuration: time.Hour * 0,
|
||||
},
|
||||
},
|
||||
@ -169,7 +169,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
CollateralType: "bnb-a",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(0)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))},
|
||||
ClaimDuration: time.Hour * 24 * 14,
|
||||
},
|
||||
},
|
||||
@ -189,7 +189,7 @@ func (suite *ParamTestSuite) SetupTest() {
|
||||
CollateralType: "",
|
||||
AvailableRewards: sdk.NewCoin("ukava", sdk.NewInt(1)),
|
||||
Duration: time.Hour * 24 * 7,
|
||||
TimeLock: time.Hour * 8766,
|
||||
ClaimMultipliers: types.Multipliers{types.NewMultiplier(types.Small, 1, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Large, 12, sdk.MustNewDecFromStr("1.0"))},
|
||||
ClaimDuration: time.Hour * 24 * 14,
|
||||
},
|
||||
},
|
||||
|
@ -34,4 +34,5 @@ type PostClaimReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"`
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ type RewardPeriod struct {
|
||||
End time.Time `json:"end" yaml:"end"`
|
||||
Reward sdk.Coin `json:"reward" yaml:"reward"` // per second reward payouts
|
||||
ClaimEnd time.Time `json:"claim_end" yaml:"claim_end"`
|
||||
ClaimTimeLock time.Duration `json:"claim_time_lock" yaml:"claim_time_lock"` // the amount of time rewards are timelocked once they are sent to users
|
||||
ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"` // the reward multiplier and timelock schedule - applied at the time users claim rewards
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer
|
||||
@ -27,19 +27,19 @@ func (rp RewardPeriod) String() string {
|
||||
End: %s,
|
||||
Reward: %s,
|
||||
Claim End: %s,
|
||||
Claim Time Lock: %s
|
||||
`, rp.CollateralType, rp.Start, rp.End, rp.Reward, rp.ClaimEnd, rp.ClaimTimeLock)
|
||||
%s
|
||||
`, rp.CollateralType, rp.Start, rp.End, rp.Reward, rp.ClaimEnd, rp.ClaimMultipliers)
|
||||
}
|
||||
|
||||
// NewRewardPeriod returns a new RewardPeriod
|
||||
func NewRewardPeriod(collateralType string, start time.Time, end time.Time, reward sdk.Coin, claimEnd time.Time, claimTimeLock time.Duration) RewardPeriod {
|
||||
func NewRewardPeriod(collateralType string, start time.Time, end time.Time, reward sdk.Coin, claimEnd time.Time, claimMultipliers Multipliers) RewardPeriod {
|
||||
return RewardPeriod{
|
||||
CollateralType: collateralType,
|
||||
Start: start,
|
||||
End: end,
|
||||
Reward: reward,
|
||||
ClaimEnd: claimEnd,
|
||||
ClaimTimeLock: claimTimeLock,
|
||||
ClaimMultipliers: claimMultipliers,
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,8 +60,8 @@ func (rp RewardPeriod) Validate() error {
|
||||
if rp.ClaimEnd.IsZero() {
|
||||
return errors.New("reward period claim end time cannot be 0")
|
||||
}
|
||||
if rp.ClaimTimeLock == 0 {
|
||||
return errors.New("reward claim time lock cannot be 0")
|
||||
if err := rp.ClaimMultipliers.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.TrimSpace(rp.CollateralType) == "" {
|
||||
return fmt.Errorf("reward period collateral type cannot be blank: %s", rp)
|
||||
@ -95,16 +95,16 @@ type ClaimPeriod struct {
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
ID uint64 `json:"id" yaml:"id"`
|
||||
End time.Time `json:"end" yaml:"end"`
|
||||
TimeLock time.Duration `json:"time_lock" yaml:"time_lock"`
|
||||
ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"`
|
||||
}
|
||||
|
||||
// NewClaimPeriod returns a new ClaimPeriod
|
||||
func NewClaimPeriod(collateralType string, id uint64, end time.Time, timeLock time.Duration) ClaimPeriod {
|
||||
func NewClaimPeriod(collateralType string, id uint64, end time.Time, multipliers Multipliers) ClaimPeriod {
|
||||
return ClaimPeriod{
|
||||
CollateralType: collateralType,
|
||||
ID: id,
|
||||
End: end,
|
||||
TimeLock: timeLock,
|
||||
ClaimMultipliers: multipliers,
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,8 +116,8 @@ func (cp ClaimPeriod) Validate() error {
|
||||
if cp.End.IsZero() {
|
||||
return errors.New("claim period end time cannot be 0")
|
||||
}
|
||||
if cp.TimeLock == 0 {
|
||||
return errors.New("claim period time lock cannot be 0")
|
||||
if err := cp.ClaimMultipliers.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.TrimSpace(cp.CollateralType) == "" {
|
||||
return fmt.Errorf("claim period collateral type cannot be blank: %s", cp)
|
||||
@ -131,8 +131,18 @@ func (cp ClaimPeriod) String() string {
|
||||
Collateral Type: %s,
|
||||
ID: %d,
|
||||
End: %s,
|
||||
Claim Time Lock: %s
|
||||
`, cp.CollateralType, cp.ID, cp.End, cp.TimeLock)
|
||||
%s
|
||||
`, cp.CollateralType, cp.ID, cp.End, cp.ClaimMultipliers)
|
||||
}
|
||||
|
||||
// GetMultiplier returns the named multiplier from the input claim period
|
||||
func (cp ClaimPeriod) GetMultiplier(name MultiplierName) (Multiplier, bool) {
|
||||
for _, multiplier := range cp.ClaimMultipliers {
|
||||
if multiplier.Name == name {
|
||||
return multiplier, true
|
||||
}
|
||||
}
|
||||
return Multiplier{}, false
|
||||
}
|
||||
|
||||
// ClaimPeriods array of ClaimPeriod
|
||||
@ -266,6 +276,6 @@ func NewRewardPeriodFromReward(reward Reward, blockTime time.Time) RewardPeriod
|
||||
End: blockTime.Add(reward.Duration),
|
||||
Reward: rewardCoinPerSecond,
|
||||
ClaimEnd: blockTime.Add(reward.Duration).Add(reward.ClaimDuration),
|
||||
ClaimTimeLock: reward.TimeLock,
|
||||
ClaimMultipliers: reward.ClaimMultipliers,
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ func TestRewardPeriodsValidate(t *testing.T) {
|
||||
{
|
||||
"valid",
|
||||
RewardPeriods{
|
||||
NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, 10),
|
||||
NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}),
|
||||
},
|
||||
true,
|
||||
},
|
||||
@ -80,14 +80,14 @@ func TestRewardPeriodsValidate(t *testing.T) {
|
||||
false,
|
||||
},
|
||||
{
|
||||
"zero claim time lock",
|
||||
"negative time lock",
|
||||
RewardPeriods{
|
||||
{
|
||||
Start: now,
|
||||
End: now.Add(time.Hour),
|
||||
Reward: sdk.NewCoin("bnb", sdk.OneInt()),
|
||||
ClaimEnd: now,
|
||||
ClaimTimeLock: 0,
|
||||
ClaimMultipliers: Multipliers{NewMultiplier(Small, -1, sdk.MustNewDecFromStr("0.33"))},
|
||||
},
|
||||
},
|
||||
false,
|
||||
@ -100,7 +100,7 @@ func TestRewardPeriodsValidate(t *testing.T) {
|
||||
End: now.Add(time.Hour),
|
||||
Reward: sdk.NewCoin("bnb", sdk.OneInt()),
|
||||
ClaimEnd: now,
|
||||
ClaimTimeLock: 10,
|
||||
ClaimMultipliers: Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))},
|
||||
CollateralType: "",
|
||||
},
|
||||
},
|
||||
@ -109,8 +109,8 @@ func TestRewardPeriodsValidate(t *testing.T) {
|
||||
{
|
||||
"duplicate reward period",
|
||||
RewardPeriods{
|
||||
NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, 10),
|
||||
NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, 10),
|
||||
NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}),
|
||||
NewRewardPeriod("bnb", now, now.Add(time.Hour), sdk.NewCoin("bnb", sdk.OneInt()), now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}),
|
||||
},
|
||||
false,
|
||||
},
|
||||
@ -137,7 +137,7 @@ func TestClaimPeriodsValidate(t *testing.T) {
|
||||
{
|
||||
"valid",
|
||||
ClaimPeriods{
|
||||
NewClaimPeriod("bnb", 10, now, 100),
|
||||
NewClaimPeriod("bnb", 10, now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}),
|
||||
},
|
||||
true,
|
||||
},
|
||||
@ -156,31 +156,38 @@ func TestClaimPeriodsValidate(t *testing.T) {
|
||||
false,
|
||||
},
|
||||
{
|
||||
"zero time lock",
|
||||
"negative time lock",
|
||||
ClaimPeriods{
|
||||
{ID: 10, End: now, TimeLock: 0},
|
||||
{ID: 10, End: now, ClaimMultipliers: Multipliers{NewMultiplier(Small, -1, sdk.MustNewDecFromStr("0.33"))}},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"negative multiplier",
|
||||
ClaimPeriods{
|
||||
NewClaimPeriod("bnb", 10, now, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("-0.33"))}),
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"start time > end time",
|
||||
ClaimPeriods{
|
||||
{ID: 10, End: now, TimeLock: 0},
|
||||
{ID: 10, End: now, ClaimMultipliers: Multipliers{NewMultiplier(Small, -1, sdk.MustNewDecFromStr("0.33"))}},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid collateral type",
|
||||
ClaimPeriods{
|
||||
{ID: 10, End: now, TimeLock: 100, CollateralType: ""},
|
||||
{ID: 10, End: now, ClaimMultipliers: Multipliers{NewMultiplier(Small, -1, sdk.MustNewDecFromStr("0.33"))}, CollateralType: ""},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"duplicate reward period",
|
||||
ClaimPeriods{
|
||||
NewClaimPeriod("bnb", 10, now, 100),
|
||||
NewClaimPeriod("bnb", 10, now, 100),
|
||||
NewClaimPeriod("bnb", 10, now, Multipliers{NewMultiplier(Small, -1, sdk.MustNewDecFromStr("0.33"))}),
|
||||
NewClaimPeriod("bnb", 10, now, Multipliers{NewMultiplier(Small, -1, sdk.MustNewDecFromStr("0.33"))}),
|
||||
},
|
||||
false,
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user