mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-26 00:05:18 +00:00
Incentive/Hard rebase to master (#773)
* spike: incentive/types * spike: incentive/types tests * spike: incentive/types/expected_keepers.go * spike: incentive/keeper * spike: incentive/keeper tests * spike: incentive/sims and incentive/sims tests * spike: incentive/module * spike: incentive/module tests * spike: hard/types * spike: hard/types hooks * spike: hard/types * spike: hard/keeper basics * spike: hard/keeper hooks * integrate hard/keeper/borrow.go * integrate hard/keeper/deposit.go * integrate hard/keeper/liquidation.go * integrate hard/keeper/withdraw.go * integrate hard/keeper/repay.go * spike: hard/sims * spike: hard/sims tests * spike: hard/client * spike: hard/module * integrate app.go * spike: x/hard/keeper compile tests * incentive/keeper test clean up * validate usdx incentive types in genesis * refactoring & fix deposit test * fix liquidaton tests * fix incentive tests for hard supply rewards * fix hard genesis tests * update incentive genesis state and params * update cdp rewards accumulation * update app init order and begin blocker order Co-authored-by: karzak <kjydavis3@gmail.com>
This commit is contained in:
parent
67b58f555b
commit
4e6f6d1e9c
29
app/app.go
29
app/app.go
@ -358,6 +358,16 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
|
|||||||
bep3Subspace,
|
bep3Subspace,
|
||||||
app.ModuleAccountAddrs(),
|
app.ModuleAccountAddrs(),
|
||||||
)
|
)
|
||||||
|
hardKeeper := hard.NewKeeper(
|
||||||
|
app.cdc,
|
||||||
|
keys[hard.StoreKey],
|
||||||
|
hardSubspace,
|
||||||
|
app.accountKeeper,
|
||||||
|
app.supplyKeeper,
|
||||||
|
&stakingKeeper,
|
||||||
|
app.pricefeedKeeper,
|
||||||
|
app.auctionKeeper,
|
||||||
|
)
|
||||||
app.kavadistKeeper = kavadist.NewKeeper(
|
app.kavadistKeeper = kavadist.NewKeeper(
|
||||||
app.cdc,
|
app.cdc,
|
||||||
keys[kavadist.StoreKey],
|
keys[kavadist.StoreKey],
|
||||||
@ -370,6 +380,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
|
|||||||
incentiveSubspace,
|
incentiveSubspace,
|
||||||
app.supplyKeeper,
|
app.supplyKeeper,
|
||||||
&cdpKeeper,
|
&cdpKeeper,
|
||||||
|
&hardKeeper,
|
||||||
app.accountKeeper,
|
app.accountKeeper,
|
||||||
)
|
)
|
||||||
app.issuanceKeeper = issuance.NewKeeper(
|
app.issuanceKeeper = issuance.NewKeeper(
|
||||||
@ -379,16 +390,6 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
|
|||||||
app.accountKeeper,
|
app.accountKeeper,
|
||||||
app.supplyKeeper,
|
app.supplyKeeper,
|
||||||
)
|
)
|
||||||
app.hardKeeper = hard.NewKeeper(
|
|
||||||
app.cdc,
|
|
||||||
keys[hard.StoreKey],
|
|
||||||
hardSubspace,
|
|
||||||
app.accountKeeper,
|
|
||||||
app.supplyKeeper,
|
|
||||||
&stakingKeeper,
|
|
||||||
app.pricefeedKeeper,
|
|
||||||
app.auctionKeeper,
|
|
||||||
)
|
|
||||||
|
|
||||||
// register the staking hooks
|
// register the staking hooks
|
||||||
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
|
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
|
||||||
@ -397,6 +398,8 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
|
|||||||
|
|
||||||
app.cdpKeeper = *cdpKeeper.SetHooks(cdp.NewMultiCDPHooks(app.incentiveKeeper.Hooks()))
|
app.cdpKeeper = *cdpKeeper.SetHooks(cdp.NewMultiCDPHooks(app.incentiveKeeper.Hooks()))
|
||||||
|
|
||||||
|
app.hardKeeper = *hardKeeper.SetHooks(hard.NewMultiHARDHooks(app.incentiveKeeper.Hooks()))
|
||||||
|
|
||||||
// create the module manager (Note: Any module instantiated in the module manager that is later modified
|
// create the module manager (Note: Any module instantiated in the module manager that is later modified
|
||||||
// must be passed by reference here.)
|
// must be passed by reference here.)
|
||||||
app.mm = module.NewManager(
|
app.mm = module.NewManager(
|
||||||
@ -432,7 +435,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
|
|||||||
app.mm.SetOrderBeginBlockers(
|
app.mm.SetOrderBeginBlockers(
|
||||||
upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName,
|
upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName,
|
||||||
validatorvesting.ModuleName, kavadist.ModuleName, auction.ModuleName, cdp.ModuleName,
|
validatorvesting.ModuleName, kavadist.ModuleName, auction.ModuleName, cdp.ModuleName,
|
||||||
bep3.ModuleName, incentive.ModuleName, committee.ModuleName, issuance.ModuleName, hard.ModuleName,
|
bep3.ModuleName, hard.ModuleName, committee.ModuleName, issuance.ModuleName, incentive.ModuleName,
|
||||||
)
|
)
|
||||||
|
|
||||||
app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName, pricefeed.ModuleName)
|
app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName, pricefeed.ModuleName)
|
||||||
@ -442,8 +445,8 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
|
|||||||
validatorvesting.ModuleName, distr.ModuleName,
|
validatorvesting.ModuleName, distr.ModuleName,
|
||||||
staking.ModuleName, bank.ModuleName, slashing.ModuleName,
|
staking.ModuleName, bank.ModuleName, slashing.ModuleName,
|
||||||
gov.ModuleName, mint.ModuleName, evidence.ModuleName,
|
gov.ModuleName, mint.ModuleName, evidence.ModuleName,
|
||||||
pricefeed.ModuleName, cdp.ModuleName, auction.ModuleName,
|
pricefeed.ModuleName, cdp.ModuleName, hard.ModuleName, auction.ModuleName,
|
||||||
bep3.ModuleName, kavadist.ModuleName, incentive.ModuleName, committee.ModuleName, issuance.ModuleName, hard.ModuleName,
|
bep3.ModuleName, kavadist.ModuleName, incentive.ModuleName, committee.ModuleName, issuance.ModuleName,
|
||||||
supply.ModuleName, // calculates the total supply from account - should run after modules that modify accounts in genesis
|
supply.ModuleName, // calculates the total supply from account - should run after modules that modify accounts in genesis
|
||||||
crisis.ModuleName, // runs the invariants at genesis - should run after other modules
|
crisis.ModuleName, // runs the invariants at genesis - should run after other modules
|
||||||
genutil.ModuleName, // genutils must occur after staking so that pools are properly initialized with tokens from genesis accounts.
|
genutil.ModuleName, // genutils must occur after staking so that pools are properly initialized with tokens from genesis accounts.
|
||||||
|
@ -4,13 +4,8 @@ import (
|
|||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BeginBlocker applies rewards to liquidity providers and delegators according to params
|
// BeginBlocker updates interest rates and attempts liquidations
|
||||||
func BeginBlocker(ctx sdk.Context, k Keeper) {
|
func BeginBlocker(ctx sdk.Context, k Keeper) {
|
||||||
k.ApplyDepositRewards(ctx)
|
|
||||||
if k.ShouldDistributeValidatorRewards(ctx, k.BondDenom(ctx)) {
|
|
||||||
k.ApplyDelegationRewards(ctx, k.BondDenom(ctx))
|
|
||||||
k.SetPreviousDelegationDistribution(ctx, ctx.BlockTime(), k.BondDenom(ctx))
|
|
||||||
}
|
|
||||||
k.ApplyInterestRateUpdates(ctx)
|
k.ApplyInterestRateUpdates(ctx)
|
||||||
k.AttemptIndexLiquidations(ctx)
|
k.AttemptIndexLiquidations(ctx)
|
||||||
k.SetPreviousBlockTime(ctx, ctx.BlockTime())
|
k.SetPreviousBlockTime(ctx, ctx.BlockTime())
|
||||||
|
@ -8,9 +8,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BeginningOfMonth = keeper.BeginningOfMonth
|
|
||||||
MidMonth = keeper.MidMonth
|
|
||||||
PaymentHour = keeper.PaymentHour
|
|
||||||
AttributeKeyBlockHeight = types.AttributeKeyBlockHeight
|
AttributeKeyBlockHeight = types.AttributeKeyBlockHeight
|
||||||
AttributeKeyClaimAmount = types.AttributeKeyClaimAmount
|
AttributeKeyClaimAmount = types.AttributeKeyClaimAmount
|
||||||
AttributeKeyClaimHolder = types.AttributeKeyClaimHolder
|
AttributeKeyClaimHolder = types.AttributeKeyClaimHolder
|
||||||
@ -56,22 +53,22 @@ var (
|
|||||||
CalculateBorrowInterestFactor = keeper.CalculateBorrowInterestFactor
|
CalculateBorrowInterestFactor = keeper.CalculateBorrowInterestFactor
|
||||||
CalculateSupplyInterestFactor = keeper.CalculateSupplyInterestFactor
|
CalculateSupplyInterestFactor = keeper.CalculateSupplyInterestFactor
|
||||||
APYToSPY = keeper.APYToSPY
|
APYToSPY = keeper.APYToSPY
|
||||||
ClaimKey = types.ClaimKey
|
|
||||||
DefaultGenesisState = types.DefaultGenesisState
|
DefaultGenesisState = types.DefaultGenesisState
|
||||||
DefaultParams = types.DefaultParams
|
DefaultParams = types.DefaultParams
|
||||||
DepositTypeIteratorKey = types.DepositTypeIteratorKey
|
DepositTypeIteratorKey = types.DepositTypeIteratorKey
|
||||||
GetTotalVestingPeriodLength = types.GetTotalVestingPeriodLength
|
GetTotalVestingPeriodLength = types.GetTotalVestingPeriodLength
|
||||||
NewClaim = types.NewClaim
|
NewBorrowLimit = types.NewBorrowLimit
|
||||||
NewDelegatorDistributionSchedule = types.NewDelegatorDistributionSchedule
|
NewInterestRateModel = types.NewInterestRateModel
|
||||||
NewDeposit = types.NewDeposit
|
NewDeposit = types.NewDeposit
|
||||||
NewDistributionSchedule = types.NewDistributionSchedule
|
|
||||||
NewGenesisState = types.NewGenesisState
|
NewGenesisState = types.NewGenesisState
|
||||||
NewMsgClaimReward = types.NewMsgClaimReward
|
NewMsgClaimReward = types.NewMsgClaimReward
|
||||||
NewMsgDeposit = types.NewMsgDeposit
|
NewMsgDeposit = types.NewMsgDeposit
|
||||||
NewMsgWithdraw = types.NewMsgWithdraw
|
NewMsgWithdraw = types.NewMsgWithdraw
|
||||||
|
NewMultiHARDHooks = types.NewMultiHARDHooks
|
||||||
NewMultiplier = types.NewMultiplier
|
NewMultiplier = types.NewMultiplier
|
||||||
NewParams = types.NewParams
|
NewParams = types.NewParams
|
||||||
NewPeriod = types.NewPeriod
|
NewPeriod = types.NewPeriod
|
||||||
|
NewMoneyMarket = types.NewMoneyMarket
|
||||||
NewQueryAccountParams = types.NewQueryAccountParams
|
NewQueryAccountParams = types.NewQueryAccountParams
|
||||||
NewQueryClaimParams = types.NewQueryClaimParams
|
NewQueryClaimParams = types.NewQueryClaimParams
|
||||||
ParamKeyTable = types.ParamKeyTable
|
ParamKeyTable = types.ParamKeyTable
|
||||||
@ -79,12 +76,7 @@ var (
|
|||||||
|
|
||||||
// variable aliases
|
// variable aliases
|
||||||
BorrowsKeyPrefix = types.BorrowsKeyPrefix
|
BorrowsKeyPrefix = types.BorrowsKeyPrefix
|
||||||
ClaimsKeyPrefix = types.ClaimsKeyPrefix
|
|
||||||
DefaultActive = types.DefaultActive
|
DefaultActive = types.DefaultActive
|
||||||
DefaultDelegatorSchedules = types.DefaultDelegatorSchedules
|
|
||||||
DefaultDistributionTimes = types.DefaultDistributionTimes
|
|
||||||
DefaultGovSchedules = types.DefaultGovSchedules
|
|
||||||
DefaultLPSchedules = types.DefaultLPSchedules
|
|
||||||
DefaultPreviousBlockTime = types.DefaultPreviousBlockTime
|
DefaultPreviousBlockTime = types.DefaultPreviousBlockTime
|
||||||
ClaimTypesClaimQuery = types.ClaimTypesClaimQuery
|
ClaimTypesClaimQuery = types.ClaimTypesClaimQuery
|
||||||
DepositsKeyPrefix = types.DepositsKeyPrefix
|
DepositsKeyPrefix = types.DepositsKeyPrefix
|
||||||
@ -103,11 +95,8 @@ var (
|
|||||||
ErrZeroClaim = types.ErrZeroClaim
|
ErrZeroClaim = types.ErrZeroClaim
|
||||||
GovDenom = types.GovDenom
|
GovDenom = types.GovDenom
|
||||||
KeyActive = types.KeyActive
|
KeyActive = types.KeyActive
|
||||||
KeyDelegatorSchedule = types.KeyDelegatorSchedule
|
|
||||||
KeyLPSchedules = types.KeyLPSchedules
|
|
||||||
ModuleCdc = types.ModuleCdc
|
ModuleCdc = types.ModuleCdc
|
||||||
PreviousBlockTimeKey = types.PreviousBlockTimeKey
|
PreviousBlockTimeKey = types.PreviousBlockTimeKey
|
||||||
PreviousDelegationDistributionKey = types.PreviousDelegationDistributionKey
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -116,14 +105,8 @@ type (
|
|||||||
Borrow = types.Borrow
|
Borrow = types.Borrow
|
||||||
MoneyMarket = types.MoneyMarket
|
MoneyMarket = types.MoneyMarket
|
||||||
MoneyMarkets = types.MoneyMarkets
|
MoneyMarkets = types.MoneyMarkets
|
||||||
DelegatorDistributionSchedule = types.DelegatorDistributionSchedule
|
|
||||||
DelegatorDistributionSchedules = types.DelegatorDistributionSchedules
|
|
||||||
Deposit = types.Deposit
|
Deposit = types.Deposit
|
||||||
ClaimType = types.ClaimType
|
ClaimType = types.ClaimType
|
||||||
DistributionSchedule = types.DistributionSchedule
|
|
||||||
DistributionSchedules = types.DistributionSchedules
|
|
||||||
GenesisDistributionTime = types.GenesisDistributionTime
|
|
||||||
GenesisDistributionTimes = types.GenesisDistributionTimes
|
|
||||||
GenesisState = types.GenesisState
|
GenesisState = types.GenesisState
|
||||||
MsgClaimReward = types.MsgClaimReward
|
MsgClaimReward = types.MsgClaimReward
|
||||||
MsgDeposit = types.MsgDeposit
|
MsgDeposit = types.MsgDeposit
|
||||||
|
@ -22,7 +22,6 @@ const (
|
|||||||
flagName = "name"
|
flagName = "name"
|
||||||
flagDenom = "denom"
|
flagDenom = "denom"
|
||||||
flagOwner = "owner"
|
flagOwner = "owner"
|
||||||
flagClaimType = "claim-type"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetQueryCmd returns the cli query commands for the module
|
// GetQueryCmd returns the cli query commands for the module
|
||||||
@ -40,7 +39,6 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||||||
queryModAccountsCmd(queryRoute, cdc),
|
queryModAccountsCmd(queryRoute, cdc),
|
||||||
queryDepositsCmd(queryRoute, cdc),
|
queryDepositsCmd(queryRoute, cdc),
|
||||||
queryTotalDepositedCmd(queryRoute, cdc),
|
queryTotalDepositedCmd(queryRoute, cdc),
|
||||||
queryClaimsCmd(queryRoute, cdc),
|
|
||||||
queryBorrowsCmd(queryRoute, cdc),
|
queryBorrowsCmd(queryRoute, cdc),
|
||||||
queryTotalBorrowedCmd(queryRoute, cdc),
|
queryTotalBorrowedCmd(queryRoute, cdc),
|
||||||
)...)
|
)...)
|
||||||
@ -177,76 +175,6 @@ func queryDepositsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryClaimsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "claims",
|
|
||||||
Short: "query hard module claims with optional filters",
|
|
||||||
Long: strings.TrimSpace(`query for all hard module claims or a specific claim using flags:
|
|
||||||
|
|
||||||
Example:
|
|
||||||
$ kvcli q hard claims
|
|
||||||
$ kvcli q hard claims --owner kava1l0xsq2z7gqd7yly0g40y5836g0appumark77ny --claim-type lp --denom bnb
|
|
||||||
$ kvcli q hard claims --claim-type stake --denom ukava
|
|
||||||
$ kvcli q hard claims --denom btcb`,
|
|
||||||
),
|
|
||||||
Args: cobra.NoArgs,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
|
||||||
|
|
||||||
var owner sdk.AccAddress
|
|
||||||
var claimType types.ClaimType
|
|
||||||
|
|
||||||
ownerBech := viper.GetString(flagOwner)
|
|
||||||
denom := viper.GetString(flagDenom)
|
|
||||||
claimTypeStr := viper.GetString(flagClaimType)
|
|
||||||
|
|
||||||
if len(ownerBech) != 0 {
|
|
||||||
claimOwner, err := sdk.AccAddressFromBech32(ownerBech)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
owner = claimOwner
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(claimTypeStr) != 0 {
|
|
||||||
if err := types.ClaimType(claimTypeStr).IsValid(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
claimType = types.ClaimType(claimTypeStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
page := viper.GetInt(flags.FlagPage)
|
|
||||||
limit := viper.GetInt(flags.FlagLimit)
|
|
||||||
|
|
||||||
params := types.NewQueryClaimParams(page, limit, denom, owner, claimType)
|
|
||||||
bz, err := cdc.MarshalJSON(params)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetClaims)
|
|
||||||
res, height, err := cliCtx.QueryWithData(route, bz)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cliCtx = cliCtx.WithHeight(height)
|
|
||||||
|
|
||||||
var claims []types.Claim
|
|
||||||
if err := cdc.UnmarshalJSON(res, &claims); err != nil {
|
|
||||||
return fmt.Errorf("failed to unmarshal claims: %w", err)
|
|
||||||
}
|
|
||||||
return cliCtx.PrintOutput(claims)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.Flags().Int(flags.FlagPage, 1, "pagination page to query for")
|
|
||||||
cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit (max 100)")
|
|
||||||
cmd.Flags().String(flagOwner, "", "(optional) filter for claims by owner address")
|
|
||||||
cmd.Flags().String(flagDenom, "", "(optional) filter for claims by denom")
|
|
||||||
cmd.Flags().String(flagClaimType, "", "(optional) filter for claims by type (lp or staking)")
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func queryBorrowsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
func queryBorrowsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "borrows",
|
Use: "borrows",
|
||||||
|
@ -32,7 +32,6 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
|
|||||||
hardTxCmd.AddCommand(flags.PostCommands(
|
hardTxCmd.AddCommand(flags.PostCommands(
|
||||||
getCmdDeposit(cdc),
|
getCmdDeposit(cdc),
|
||||||
getCmdWithdraw(cdc),
|
getCmdWithdraw(cdc),
|
||||||
getCmdClaimReward(cdc),
|
|
||||||
getCmdBorrow(cdc),
|
getCmdBorrow(cdc),
|
||||||
getCmdLiquidate(cdc),
|
getCmdLiquidate(cdc),
|
||||||
getCmdRepay(cdc),
|
getCmdRepay(cdc),
|
||||||
@ -90,35 +89,6 @@ func getCmdWithdraw(cdc *codec.Codec) *cobra.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCmdClaimReward(cdc *codec.Codec) *cobra.Command {
|
|
||||||
return &cobra.Command{
|
|
||||||
Use: "claim [receiver-addr] [deposit-denom] [deposit-type] [multiplier]",
|
|
||||||
Short: "claim HARD tokens to receiver address",
|
|
||||||
Long: strings.TrimSpace(
|
|
||||||
`sends accumulated HARD tokens from the hard module account to the receiver address.
|
|
||||||
Note that receiver address should match the sender address,
|
|
||||||
unless the sender is a validator-vesting account`),
|
|
||||||
Args: cobra.ExactArgs(4),
|
|
||||||
Example: fmt.Sprintf(
|
|
||||||
`%s tx %s claim kava1hgcfsuwc889wtdmt8pjy7qffua9dd2tralu64j bnb lp large --from <key>`, version.ClientName, types.ModuleName,
|
|
||||||
),
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
|
||||||
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
|
|
||||||
receiver, err := sdk.AccAddressFromBech32(args[0])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
msg := types.NewMsgClaimReward(cliCtx.GetFromAddress(), receiver, args[1], args[2], args[3])
|
|
||||||
if err := msg.ValidateBasic(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCmdBorrow(cdc *codec.Codec) *cobra.Command {
|
func getCmdBorrow(cdc *codec.Codec) *cobra.Command {
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "borrow [1000000000ukava]",
|
Use: "borrow [1000000000ukava]",
|
||||||
|
@ -21,12 +21,6 @@ func InitGenesis(ctx sdk.Context, k Keeper, supplyKeeper types.SupplyKeeper, gs
|
|||||||
k.SetPreviousBlockTime(ctx, gs.PreviousBlockTime)
|
k.SetPreviousBlockTime(ctx, gs.PreviousBlockTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pdt := range gs.PreviousDistributionTimes {
|
|
||||||
if !pdt.PreviousDistributionTime.Equal(DefaultPreviousBlockTime) {
|
|
||||||
k.SetPreviousDelegationDistribution(ctx, pdt.PreviousDistributionTime, pdt.Denom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, mm := range gs.Params.MoneyMarkets {
|
for _, mm := range gs.Params.MoneyMarkets {
|
||||||
k.SetMoneyMarket(ctx, mm.Denom, mm)
|
k.SetMoneyMarket(ctx, mm.Denom, mm)
|
||||||
}
|
}
|
||||||
@ -64,12 +58,5 @@ func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState {
|
|||||||
if !found {
|
if !found {
|
||||||
previousBlockTime = DefaultPreviousBlockTime
|
previousBlockTime = DefaultPreviousBlockTime
|
||||||
}
|
}
|
||||||
previousDistTimes := GenesisDistributionTimes{}
|
return NewGenesisState(params, previousBlockTime)
|
||||||
for _, dds := range params.DelegatorDistributionSchedules {
|
|
||||||
previousDistTime, found := k.GetPreviousDelegatorDistribution(ctx, dds.DistributionSchedule.DepositDenom)
|
|
||||||
if found {
|
|
||||||
previousDistTimes = append(previousDistTimes, GenesisDistributionTime{PreviousDistributionTime: previousDistTime, Denom: dds.DistributionSchedule.DepositDenom})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NewGenesisState(params, previousBlockTime, previousDistTimes)
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package hard
|
package hard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
|
|
||||||
@ -15,8 +13,6 @@ func NewHandler(k Keeper) sdk.Handler {
|
|||||||
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
|
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
|
||||||
ctx = ctx.WithEventManager(sdk.NewEventManager())
|
ctx = ctx.WithEventManager(sdk.NewEventManager())
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case types.MsgClaimReward:
|
|
||||||
return handleMsgClaimReward(ctx, k, msg)
|
|
||||||
case types.MsgDeposit:
|
case types.MsgDeposit:
|
||||||
return handleMsgDeposit(ctx, k, msg)
|
return handleMsgDeposit(ctx, k, msg)
|
||||||
case types.MsgWithdraw:
|
case types.MsgWithdraw:
|
||||||
@ -33,24 +29,6 @@ func NewHandler(k Keeper) sdk.Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgClaimReward(ctx sdk.Context, k keeper.Keeper, msg types.MsgClaimReward) (*sdk.Result, error) {
|
|
||||||
err := k.ClaimReward(ctx, msg.Sender, msg.Receiver, msg.DepositDenom, types.ClaimType(strings.ToLower(msg.ClaimType)), types.MultiplierName(strings.ToLower(msg.MultiplierName)))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.EventManager().EmitEvent(
|
|
||||||
sdk.NewEvent(
|
|
||||||
sdk.EventTypeMessage,
|
|
||||||
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
|
|
||||||
sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return &sdk.Result{
|
|
||||||
Events: ctx.EventManager().Events(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMsgDeposit(ctx sdk.Context, k keeper.Keeper, msg types.MsgDeposit) (*sdk.Result, error) {
|
func handleMsgDeposit(ctx sdk.Context, k keeper.Keeper, msg types.MsgDeposit) (*sdk.Result, error) {
|
||||||
err := k.Deposit(ctx, msg.Depositor, msg.Amount)
|
err := k.Deposit(ctx, msg.Depositor, msg.Amount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -28,7 +28,12 @@ func (k Keeper) Borrow(ctx sdk.Context, borrower sdk.AccAddress, coins sdk.Coins
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync any outstanding interest
|
// Call incentive hook
|
||||||
|
existingBorrow, hasExistingBorrow := k.GetBorrow(ctx, borrower)
|
||||||
|
if hasExistingBorrow {
|
||||||
|
k.BeforeBorrowModified(ctx, existingBorrow)
|
||||||
|
}
|
||||||
|
|
||||||
k.SyncBorrowInterest(ctx, borrower)
|
k.SyncBorrowInterest(ctx, borrower)
|
||||||
|
|
||||||
// Validate borrow amount within user and protocol limits
|
// Validate borrow amount within user and protocol limits
|
||||||
@ -84,7 +89,6 @@ func (k Keeper) Borrow(ctx sdk.Context, borrower sdk.AccAddress, coins sdk.Coins
|
|||||||
} else {
|
} else {
|
||||||
amount = coins
|
amount = coins
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct the user's new/updated borrow with amount and interest factors
|
// Construct the user's new/updated borrow with amount and interest factors
|
||||||
borrow := types.NewBorrow(borrower, amount, borrowInterestFactors)
|
borrow := types.NewBorrow(borrower, amount, borrowInterestFactors)
|
||||||
|
|
||||||
@ -104,6 +108,12 @@ func (k Keeper) Borrow(ctx sdk.Context, borrower sdk.AccAddress, coins sdk.Coins
|
|||||||
// it has already been included in the total borrowed coins by the BeginBlocker.
|
// it has already been included in the total borrowed coins by the BeginBlocker.
|
||||||
k.IncrementBorrowedCoins(ctx, coins)
|
k.IncrementBorrowedCoins(ctx, coins)
|
||||||
|
|
||||||
|
if !hasExistingBorrow {
|
||||||
|
k.AfterBorrowCreated(ctx, borrow)
|
||||||
|
} else {
|
||||||
|
k.AfterBorrowModified(ctx, borrow)
|
||||||
|
}
|
||||||
|
|
||||||
ctx.EventManager().EmitEvent(
|
ctx.EventManager().EmitEvent(
|
||||||
sdk.NewEvent(
|
sdk.NewEvent(
|
||||||
types.EventTypeHardBorrow,
|
types.EventTypeHardBorrow,
|
||||||
|
@ -262,19 +262,6 @@ func (suite *KeeperTestSuite) TestBorrow() {
|
|||||||
// hard module genesis state
|
// hard module genesis state
|
||||||
hardGS := types.NewGenesisState(types.NewParams(
|
hardGS := types.NewGenesisState(types.NewParams(
|
||||||
true,
|
true,
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "ukava", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "btcb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "busd", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "xyz", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
types.MoneyMarkets{
|
||||||
types.NewMoneyMarket("usdx", types.NewBorrowLimit(true, tc.args.usdxBorrowLimit, sdk.MustNewDecFromStr("1")), "usdx:usd", sdk.NewInt(USDX_CF), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("usdx", types.NewBorrowLimit(true, tc.args.usdxBorrowLimit, sdk.MustNewDecFromStr("1")), "usdx:usd", sdk.NewInt(USDX_CF), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
types.NewMoneyMarket("busd", types.NewBorrowLimit(false, sdk.NewDec(100000000*BUSD_CF), sdk.MustNewDecFromStr("1")), "busd:usd", sdk.NewInt(BUSD_CF), sdk.NewInt(BUSD_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("busd", types.NewBorrowLimit(false, sdk.NewDec(100000000*BUSD_CF), sdk.MustNewDecFromStr("1")), "busd:usd", sdk.NewInt(BUSD_CF), sdk.NewInt(BUSD_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
@ -284,7 +271,7 @@ func (suite *KeeperTestSuite) TestBorrow() {
|
|||||||
types.NewMoneyMarket("xyz", types.NewBorrowLimit(false, sdk.NewDec(1), tc.args.loanToValueBNB), "xyz:usd", sdk.NewInt(1), sdk.NewInt(1), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("xyz", types.NewBorrowLimit(false, sdk.NewDec(1), tc.args.loanToValueBNB), "xyz:usd", sdk.NewInt(1), sdk.NewInt(1), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
},
|
},
|
||||||
0, // LTV counter
|
0, // LTV counter
|
||||||
), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes)
|
), types.DefaultPreviousBlockTime)
|
||||||
|
|
||||||
// Pricefeed module genesis state
|
// Pricefeed module genesis state
|
||||||
pricefeedGS := pricefeed.GenesisState{
|
pricefeedGS := pricefeed.GenesisState{
|
||||||
|
@ -1,149 +0,0 @@
|
|||||||
package keeper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
||||||
|
|
||||||
"github.com/kava-labs/kava/x/hard/types"
|
|
||||||
validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// BeginningOfMonth hard rewards that are claimed after the 15th at 14:00UTC of the month always vest on the first of the month
|
|
||||||
BeginningOfMonth = 1
|
|
||||||
// MidMonth hard rewards that are claimed before the 15th at 14:00UTC of the month always vest on the 15 of the month
|
|
||||||
MidMonth = 15
|
|
||||||
// PaymentHour hard rewards always vest at 14:00UTC
|
|
||||||
PaymentHour = 14
|
|
||||||
)
|
|
||||||
|
|
||||||
// ClaimReward sends the reward amount to the reward owner and deletes the claim from the store
|
|
||||||
func (k Keeper) ClaimReward(ctx sdk.Context, claimHolder sdk.AccAddress, receiver sdk.AccAddress, depositDenom string, claimType types.ClaimType, multiplier types.MultiplierName) error {
|
|
||||||
|
|
||||||
claim, found := k.GetClaim(ctx, claimHolder, depositDenom, claimType)
|
|
||||||
if !found {
|
|
||||||
return sdkerrors.Wrapf(types.ErrClaimNotFound, "no %s %s claim found for %s", depositDenom, claimType, claimHolder)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := k.validateSenderReceiver(ctx, claimHolder, receiver)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch claimType {
|
|
||||||
case types.LP:
|
|
||||||
err = k.claimLPReward(ctx, claim, receiver, multiplier)
|
|
||||||
case types.Stake:
|
|
||||||
err = k.claimDelegatorReward(ctx, claim, receiver, multiplier)
|
|
||||||
default:
|
|
||||||
return sdkerrors.Wrap(types.ErrInvalidClaimType, string(claimType))
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ctx.EventManager().EmitEvent(
|
|
||||||
sdk.NewEvent(
|
|
||||||
types.EventTypeClaimHardReward,
|
|
||||||
sdk.NewAttribute(sdk.AttributeKeyAmount, claim.Amount.String()),
|
|
||||||
sdk.NewAttribute(types.AttributeKeyClaimHolder, claimHolder.String()),
|
|
||||||
sdk.NewAttribute(types.AttributeKeyDepositDenom, depositDenom),
|
|
||||||
sdk.NewAttribute(types.AttributeKeyClaimType, string(claimType)),
|
|
||||||
sdk.NewAttribute(types.AttributeKeyClaimMultiplier, string(multiplier)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
k.DeleteClaim(ctx, claim)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPeriodLength returns the length of the period based on the input blocktime and multiplier
|
|
||||||
// note that pay dates are always the 1st or 15th of the month at 14:00UTC.
|
|
||||||
func (k Keeper) GetPeriodLength(ctx sdk.Context, multiplier types.Multiplier) (int64, error) {
|
|
||||||
|
|
||||||
if multiplier.MonthsLockup == 0 {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
switch multiplier.Name {
|
|
||||||
case types.Small, types.Medium, types.Large:
|
|
||||||
currentDay := ctx.BlockTime().Day()
|
|
||||||
payDay := BeginningOfMonth
|
|
||||||
monthOffset := int64(1)
|
|
||||||
if currentDay < MidMonth || (currentDay == MidMonth && ctx.BlockTime().Hour() < PaymentHour) {
|
|
||||||
payDay = MidMonth
|
|
||||||
monthOffset = int64(0)
|
|
||||||
}
|
|
||||||
periodEndDate := time.Date(ctx.BlockTime().Year(), ctx.BlockTime().Month(), payDay, PaymentHour, 0, 0, 0, time.UTC).AddDate(0, int(multiplier.MonthsLockup+monthOffset), 0)
|
|
||||||
return periodEndDate.Unix() - ctx.BlockTime().Unix(), nil
|
|
||||||
}
|
|
||||||
return 0, types.ErrInvalidMultiplier
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k Keeper) claimLPReward(ctx sdk.Context, claim types.Claim, receiver sdk.AccAddress, multiplierName types.MultiplierName) error {
|
|
||||||
lps, found := k.GetLPSchedule(ctx, claim.DepositDenom)
|
|
||||||
if !found {
|
|
||||||
return sdkerrors.Wrapf(types.ErrLPScheduleNotFound, claim.DepositDenom)
|
|
||||||
}
|
|
||||||
multiplier, found := lps.GetMultiplier(multiplierName)
|
|
||||||
if !found {
|
|
||||||
return sdkerrors.Wrapf(types.ErrInvalidMultiplier, string(multiplierName))
|
|
||||||
}
|
|
||||||
if ctx.BlockTime().After(lps.ClaimEnd) {
|
|
||||||
return sdkerrors.Wrapf(types.ErrClaimExpired, "block time %s > claim end time %s", ctx.BlockTime(), lps.ClaimEnd)
|
|
||||||
}
|
|
||||||
rewardAmount := sdk.NewDecFromInt(claim.Amount.Amount).Mul(multiplier.Factor).RoundInt()
|
|
||||||
if rewardAmount.IsZero() {
|
|
||||||
return types.ErrZeroClaim
|
|
||||||
}
|
|
||||||
rewardCoin := sdk.NewCoin(claim.Amount.Denom, rewardAmount)
|
|
||||||
length, err := k.GetPeriodLength(ctx, multiplier)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return k.SendTimeLockedCoinsToAccount(ctx, types.LPAccount, receiver, sdk.NewCoins(rewardCoin), length)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k Keeper) claimDelegatorReward(ctx sdk.Context, claim types.Claim, receiver sdk.AccAddress, multiplierName types.MultiplierName) error {
|
|
||||||
dss, found := k.GetDelegatorSchedule(ctx, claim.DepositDenom)
|
|
||||||
if !found {
|
|
||||||
return sdkerrors.Wrapf(types.ErrLPScheduleNotFound, claim.DepositDenom)
|
|
||||||
}
|
|
||||||
multiplier, found := dss.DistributionSchedule.GetMultiplier(multiplierName)
|
|
||||||
if !found {
|
|
||||||
return sdkerrors.Wrapf(types.ErrInvalidMultiplier, string(multiplierName))
|
|
||||||
}
|
|
||||||
if ctx.BlockTime().After(dss.DistributionSchedule.ClaimEnd) {
|
|
||||||
return sdkerrors.Wrapf(types.ErrClaimExpired, "block time %s > claim end time %s", ctx.BlockTime(), dss.DistributionSchedule.ClaimEnd)
|
|
||||||
}
|
|
||||||
rewardAmount := sdk.NewDecFromInt(claim.Amount.Amount).Mul(multiplier.Factor).RoundInt()
|
|
||||||
if rewardAmount.IsZero() {
|
|
||||||
return types.ErrZeroClaim
|
|
||||||
}
|
|
||||||
rewardCoin := sdk.NewCoin(claim.Amount.Denom, rewardAmount)
|
|
||||||
|
|
||||||
length, err := k.GetPeriodLength(ctx, multiplier)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return k.SendTimeLockedCoinsToAccount(ctx, types.DelegatorAccount, receiver, sdk.NewCoins(rewardCoin), length)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k Keeper) validateSenderReceiver(ctx sdk.Context, sender, receiver sdk.AccAddress) error {
|
|
||||||
senderAcc := k.accountKeeper.GetAccount(ctx, sender)
|
|
||||||
if senderAcc == nil {
|
|
||||||
return sdkerrors.Wrapf(types.ErrAccountNotFound, sender.String())
|
|
||||||
}
|
|
||||||
switch senderAcc.(type) {
|
|
||||||
case *validatorvesting.ValidatorVestingAccount:
|
|
||||||
if sender.Equals(receiver) {
|
|
||||||
return sdkerrors.Wrapf(types.ErrInvalidAccountType, "%T", senderAcc)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if !sender.Equals(receiver) {
|
|
||||||
return sdkerrors.Wrapf(types.ErrInvalidReceiver, "%s", sender)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,475 +0,0 @@
|
|||||||
package keeper_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
|
||||||
|
|
||||||
"github.com/kava-labs/kava/app"
|
|
||||||
"github.com/kava-labs/kava/x/hard/types"
|
|
||||||
validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestClaim() {
|
|
||||||
type args struct {
|
|
||||||
claimOwner sdk.AccAddress
|
|
||||||
receiver sdk.AccAddress
|
|
||||||
denom string
|
|
||||||
claimType types.ClaimType
|
|
||||||
multiplier types.MultiplierName
|
|
||||||
blockTime time.Time
|
|
||||||
createClaim bool
|
|
||||||
claimAmount sdk.Coin
|
|
||||||
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 liquid claim",
|
|
||||||
args{
|
|
||||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
receiver: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
denom: "bnb",
|
|
||||||
claimType: types.LP,
|
|
||||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
|
||||||
createClaim: true,
|
|
||||||
claimAmount: sdk.NewCoin("hard", sdk.NewInt(100)),
|
|
||||||
validatorVesting: false,
|
|
||||||
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(33)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
|
||||||
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(967))),
|
|
||||||
expectedVestingAccount: false,
|
|
||||||
expectedVestingLength: 0,
|
|
||||||
multiplier: types.Small,
|
|
||||||
},
|
|
||||||
errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"valid liquid delegator claim",
|
|
||||||
args{
|
|
||||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
receiver: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
denom: "bnb",
|
|
||||||
claimType: types.Stake,
|
|
||||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
|
||||||
createClaim: true,
|
|
||||||
claimAmount: sdk.NewCoin("hard", sdk.NewInt(100)),
|
|
||||||
validatorVesting: false,
|
|
||||||
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(33)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
|
||||||
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(967))),
|
|
||||||
expectedVestingAccount: false,
|
|
||||||
expectedVestingLength: 0,
|
|
||||||
multiplier: types.Small,
|
|
||||||
},
|
|
||||||
errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"valid medium vesting claim",
|
|
||||||
args{
|
|
||||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
receiver: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
denom: "bnb",
|
|
||||||
claimType: types.LP,
|
|
||||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
|
||||||
createClaim: true,
|
|
||||||
claimAmount: sdk.NewCoin("hard", sdk.NewInt(100)),
|
|
||||||
validatorVesting: false,
|
|
||||||
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(50)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
|
||||||
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(950))),
|
|
||||||
expectedVestingAccount: true,
|
|
||||||
expectedVestingLength: 16848000,
|
|
||||||
multiplier: types.Medium,
|
|
||||||
},
|
|
||||||
errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"valid large vesting claim",
|
|
||||||
args{
|
|
||||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
receiver: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
denom: "bnb",
|
|
||||||
claimType: types.LP,
|
|
||||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
|
||||||
createClaim: true,
|
|
||||||
claimAmount: sdk.NewCoin("hard", sdk.NewInt(100)),
|
|
||||||
validatorVesting: false,
|
|
||||||
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(100)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
|
||||||
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(900))),
|
|
||||||
expectedVestingAccount: true,
|
|
||||||
expectedVestingLength: 64281600,
|
|
||||||
multiplier: types.Large,
|
|
||||||
},
|
|
||||||
errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"valid validator vesting",
|
|
||||||
args{
|
|
||||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
receiver: sdk.AccAddress(crypto.AddressHash([]byte("test2"))),
|
|
||||||
denom: "bnb",
|
|
||||||
claimType: types.LP,
|
|
||||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
|
||||||
createClaim: true,
|
|
||||||
claimAmount: sdk.NewCoin("hard", sdk.NewInt(100)),
|
|
||||||
validatorVesting: true,
|
|
||||||
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(100)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
|
||||||
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(900))),
|
|
||||||
expectedVestingAccount: true,
|
|
||||||
expectedVestingLength: 64281600,
|
|
||||||
multiplier: types.Large,
|
|
||||||
},
|
|
||||||
errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"invalid validator vesting",
|
|
||||||
args{
|
|
||||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
receiver: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
denom: "bnb",
|
|
||||||
claimType: types.LP,
|
|
||||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
|
||||||
createClaim: true,
|
|
||||||
claimAmount: sdk.NewCoin("hard", sdk.NewInt(100)),
|
|
||||||
validatorVesting: true,
|
|
||||||
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(100)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
|
||||||
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(900))),
|
|
||||||
expectedVestingAccount: true,
|
|
||||||
expectedVestingLength: 64281600,
|
|
||||||
multiplier: types.Large,
|
|
||||||
},
|
|
||||||
errArgs{
|
|
||||||
expectPass: false,
|
|
||||||
contains: "receiver account type not supported",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"claim not found",
|
|
||||||
args{
|
|
||||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
receiver: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
denom: "bnb",
|
|
||||||
claimType: types.LP,
|
|
||||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
|
||||||
createClaim: false,
|
|
||||||
claimAmount: sdk.NewCoin("hard", sdk.NewInt(100)),
|
|
||||||
validatorVesting: false,
|
|
||||||
expectedAccountBalance: sdk.Coins{},
|
|
||||||
expectedModAccountBalance: sdk.Coins{},
|
|
||||||
expectedVestingAccount: false,
|
|
||||||
expectedVestingLength: 0,
|
|
||||||
multiplier: types.Small,
|
|
||||||
},
|
|
||||||
errArgs{
|
|
||||||
expectPass: false,
|
|
||||||
contains: "claim not found",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"claim expired",
|
|
||||||
args{
|
|
||||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
receiver: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
denom: "bnb",
|
|
||||||
claimType: types.LP,
|
|
||||||
blockTime: time.Date(2022, 11, 1, 14, 0, 0, 0, time.UTC),
|
|
||||||
createClaim: true,
|
|
||||||
claimAmount: sdk.NewCoin("hard", sdk.NewInt(100)),
|
|
||||||
validatorVesting: false,
|
|
||||||
expectedAccountBalance: sdk.Coins{},
|
|
||||||
expectedModAccountBalance: sdk.Coins{},
|
|
||||||
expectedVestingAccount: false,
|
|
||||||
expectedVestingLength: 0,
|
|
||||||
multiplier: types.Small,
|
|
||||||
},
|
|
||||||
errArgs{
|
|
||||||
expectPass: false,
|
|
||||||
contains: "claim period expired",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"different receiver address",
|
|
||||||
args{
|
|
||||||
claimOwner: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
receiver: sdk.AccAddress(crypto.AddressHash([]byte("test2"))),
|
|
||||||
denom: "bnb",
|
|
||||||
claimType: types.LP,
|
|
||||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
|
||||||
createClaim: true,
|
|
||||||
claimAmount: sdk.NewCoin("hard", sdk.NewInt(100)),
|
|
||||||
validatorVesting: false,
|
|
||||||
expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(100)), sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
|
||||||
expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(900))),
|
|
||||||
expectedVestingAccount: true,
|
|
||||||
expectedVestingLength: 64281600,
|
|
||||||
multiplier: types.Large,
|
|
||||||
},
|
|
||||||
errArgs{
|
|
||||||
expectPass: false,
|
|
||||||
contains: "receiver account must match sender account",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
suite.Run(tc.name, func() {
|
|
||||||
// create new app with one funded account
|
|
||||||
|
|
||||||
// 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, tc.args.receiver},
|
|
||||||
[]sdk.Coins{
|
|
||||||
sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
|
||||||
sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(1000)), sdk.NewCoin("btcb", sdk.NewInt(1000))),
|
|
||||||
})
|
|
||||||
loanToValue := sdk.MustNewDecFromStr("0.6")
|
|
||||||
hardGS := types.NewGenesisState(types.NewParams(
|
|
||||||
true,
|
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
|
||||||
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
|
||||||
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
|
||||||
},
|
|
||||||
0, // LTV counter
|
|
||||||
), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes)
|
|
||||||
tApp.InitializeFromGenesisStates(authGS, app.GenesisState{types.ModuleName: types.ModuleCdc.MustMarshalJSON(hardGS)})
|
|
||||||
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.LPAccount, sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(1000))))
|
|
||||||
supplyKeeper.MintCoins(ctx, types.DelegatorAccount, sdk.NewCoins(sdk.NewCoin("hard", sdk.NewInt(1000))))
|
|
||||||
keeper := tApp.GetHardKeeper()
|
|
||||||
suite.app = tApp
|
|
||||||
suite.ctx = ctx
|
|
||||||
suite.keeper = keeper
|
|
||||||
|
|
||||||
if tc.args.createClaim {
|
|
||||||
claim := types.NewClaim(tc.args.claimOwner, tc.args.denom, tc.args.claimAmount, tc.args.claimType)
|
|
||||||
suite.Require().NotPanics(func() { suite.keeper.SetClaim(suite.ctx, claim) })
|
|
||||||
}
|
|
||||||
|
|
||||||
err := suite.keeper.ClaimReward(suite.ctx, tc.args.claimOwner, tc.args.receiver, tc.args.denom, tc.args.claimType, tc.args.multiplier)
|
|
||||||
if tc.errArgs.expectPass {
|
|
||||||
suite.Require().NoError(err)
|
|
||||||
acc := suite.getAccount(tc.args.receiver)
|
|
||||||
suite.Require().Equal(tc.args.expectedAccountBalance, acc.GetCoins())
|
|
||||||
mAcc := suite.getModuleAccount(types.LPAccount)
|
|
||||||
if tc.args.claimType == types.Stake {
|
|
||||||
mAcc = suite.getModuleAccount(types.DelegatorAccount)
|
|
||||||
}
|
|
||||||
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.denom, tc.args.claimType)
|
|
||||||
suite.Require().False(f)
|
|
||||||
} else {
|
|
||||||
suite.Require().Error(err)
|
|
||||||
suite.Require().True(strings.Contains(err.Error(), tc.errArgs.contains))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestGetPeriodLength() {
|
|
||||||
type args struct {
|
|
||||||
blockTime time.Time
|
|
||||||
multiplier types.Multiplier
|
|
||||||
expectedLength int64
|
|
||||||
}
|
|
||||||
type errArgs struct {
|
|
||||||
expectPass bool
|
|
||||||
contains string
|
|
||||||
}
|
|
||||||
type periodTest struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
errArgs errArgs
|
|
||||||
}
|
|
||||||
testCases := []periodTest{
|
|
||||||
{
|
|
||||||
name: "first half of month",
|
|
||||||
args: args{
|
|
||||||
blockTime: time.Date(2020, 11, 2, 15, 0, 0, 0, time.UTC),
|
|
||||||
multiplier: types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.333333")),
|
|
||||||
expectedLength: time.Date(2021, 5, 15, 14, 0, 0, 0, time.UTC).Unix() - time.Date(2020, 11, 2, 15, 0, 0, 0, time.UTC).Unix(),
|
|
||||||
},
|
|
||||||
errArgs: errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "first half of month long lockup",
|
|
||||||
args: args{
|
|
||||||
blockTime: time.Date(2020, 11, 2, 15, 0, 0, 0, time.UTC),
|
|
||||||
multiplier: types.NewMultiplier(types.Medium, 24, sdk.MustNewDecFromStr("0.333333")),
|
|
||||||
expectedLength: time.Date(2022, 11, 15, 14, 0, 0, 0, time.UTC).Unix() - time.Date(2020, 11, 2, 15, 0, 0, 0, time.UTC).Unix(),
|
|
||||||
},
|
|
||||||
errArgs: errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "second half of month",
|
|
||||||
args: args{
|
|
||||||
blockTime: time.Date(2020, 12, 31, 15, 0, 0, 0, time.UTC),
|
|
||||||
multiplier: types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.333333")),
|
|
||||||
expectedLength: time.Date(2021, 7, 1, 14, 0, 0, 0, time.UTC).Unix() - time.Date(2020, 12, 31, 15, 0, 0, 0, time.UTC).Unix(),
|
|
||||||
},
|
|
||||||
errArgs: errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "second half of month long lockup",
|
|
||||||
args: args{
|
|
||||||
blockTime: time.Date(2020, 12, 31, 15, 0, 0, 0, time.UTC),
|
|
||||||
multiplier: types.NewMultiplier(types.Large, 24, sdk.MustNewDecFromStr("0.333333")),
|
|
||||||
expectedLength: time.Date(2023, 1, 1, 14, 0, 0, 0, time.UTC).Unix() - time.Date(2020, 12, 31, 15, 0, 0, 0, time.UTC).Unix(),
|
|
||||||
},
|
|
||||||
errArgs: errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "end of feb",
|
|
||||||
args: args{
|
|
||||||
blockTime: time.Date(2021, 2, 28, 15, 0, 0, 0, time.UTC),
|
|
||||||
multiplier: types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.333333")),
|
|
||||||
expectedLength: time.Date(2021, 9, 1, 14, 0, 0, 0, time.UTC).Unix() - time.Date(2021, 2, 28, 15, 0, 0, 0, time.UTC).Unix(),
|
|
||||||
},
|
|
||||||
errArgs: errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "leap year",
|
|
||||||
args: args{
|
|
||||||
blockTime: time.Date(2020, 2, 29, 15, 0, 0, 0, time.UTC),
|
|
||||||
multiplier: types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.333333")),
|
|
||||||
expectedLength: time.Date(2020, 9, 1, 14, 0, 0, 0, time.UTC).Unix() - time.Date(2020, 2, 29, 15, 0, 0, 0, time.UTC).Unix(),
|
|
||||||
},
|
|
||||||
errArgs: errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "leap year long lockup",
|
|
||||||
args: args{
|
|
||||||
blockTime: time.Date(2020, 2, 29, 15, 0, 0, 0, time.UTC),
|
|
||||||
multiplier: types.NewMultiplier(types.Large, 24, sdk.MustNewDecFromStr("1")),
|
|
||||||
expectedLength: time.Date(2022, 3, 1, 14, 0, 0, 0, time.UTC).Unix() - time.Date(2020, 2, 29, 15, 0, 0, 0, time.UTC).Unix(),
|
|
||||||
},
|
|
||||||
errArgs: errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "exactly half of month",
|
|
||||||
args: args{
|
|
||||||
blockTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
|
||||||
multiplier: types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.333333")),
|
|
||||||
expectedLength: time.Date(2021, 7, 1, 14, 0, 0, 0, time.UTC).Unix() - time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC).Unix(),
|
|
||||||
},
|
|
||||||
errArgs: errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "just before half of month",
|
|
||||||
args: args{
|
|
||||||
blockTime: time.Date(2020, 12, 15, 13, 59, 59, 0, time.UTC),
|
|
||||||
multiplier: types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.333333")),
|
|
||||||
expectedLength: time.Date(2021, 6, 15, 14, 0, 0, 0, time.UTC).Unix() - time.Date(2020, 12, 15, 13, 59, 59, 0, time.UTC).Unix(),
|
|
||||||
},
|
|
||||||
errArgs: errArgs{
|
|
||||||
expectPass: true,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
suite.Run(tc.name, func() {
|
|
||||||
ctx := suite.ctx.WithBlockTime(tc.args.blockTime)
|
|
||||||
length, err := suite.keeper.GetPeriodLength(ctx, tc.args.multiplier)
|
|
||||||
if tc.errArgs.expectPass {
|
|
||||||
suite.Require().NoError(err)
|
|
||||||
suite.Require().Equal(tc.args.expectedLength, length)
|
|
||||||
} else {
|
|
||||||
suite.Require().Error(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -29,6 +29,12 @@ func (k Keeper) Deposit(ctx sdk.Context, depositor sdk.AccAddress, coins sdk.Coi
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call incentive hook
|
||||||
|
existingDeposit, hasExistingDeposit := k.GetDeposit(ctx, depositor)
|
||||||
|
if hasExistingDeposit {
|
||||||
|
k.BeforeDepositModified(ctx, existingDeposit)
|
||||||
|
}
|
||||||
|
|
||||||
// Sync any outstanding interest
|
// Sync any outstanding interest
|
||||||
k.SyncBorrowInterest(ctx, depositor)
|
k.SyncBorrowInterest(ctx, depositor)
|
||||||
k.SyncSupplyInterest(ctx, depositor)
|
k.SyncSupplyInterest(ctx, depositor)
|
||||||
@ -98,10 +104,12 @@ func (k Keeper) Deposit(ctx sdk.Context, depositor sdk.AccAddress, coins sdk.Coi
|
|||||||
}
|
}
|
||||||
|
|
||||||
k.UpdateDepositAndLtvIndex(ctx, deposit, newLtv, prevLtv)
|
k.UpdateDepositAndLtvIndex(ctx, deposit, newLtv, prevLtv)
|
||||||
|
|
||||||
// Update total supplied amount by newly supplied coins. Don't add user's pending interest as
|
|
||||||
// it has already been included in the total supplied coins by the BeginBlocker.
|
|
||||||
k.IncrementSuppliedCoins(ctx, coins)
|
k.IncrementSuppliedCoins(ctx, coins)
|
||||||
|
if !foundDeposit { // User's first deposit
|
||||||
|
k.AfterDepositCreated(ctx, deposit)
|
||||||
|
} else {
|
||||||
|
k.AfterDepositModified(ctx, deposit)
|
||||||
|
}
|
||||||
|
|
||||||
ctx.EventManager().EmitEvent(
|
ctx.EventManager().EmitEvent(
|
||||||
sdk.NewEvent(
|
sdk.NewEvent(
|
||||||
@ -116,16 +124,10 @@ func (k Keeper) Deposit(ctx sdk.Context, depositor sdk.AccAddress, coins sdk.Coi
|
|||||||
|
|
||||||
// ValidateDeposit validates a deposit
|
// ValidateDeposit validates a deposit
|
||||||
func (k Keeper) ValidateDeposit(ctx sdk.Context, coins sdk.Coins) error {
|
func (k Keeper) ValidateDeposit(ctx sdk.Context, coins sdk.Coins) error {
|
||||||
params := k.GetParams(ctx)
|
|
||||||
for _, depCoin := range coins {
|
for _, depCoin := range coins {
|
||||||
found := false
|
_, foundMm := k.GetMoneyMarket(ctx, depCoin.Denom)
|
||||||
for _, lps := range params.LiquidityProviderSchedules {
|
if !foundMm {
|
||||||
if lps.DepositDenom == depCoin.Denom {
|
return sdkerrors.Wrapf(types.ErrInvalidDepositDenom, "money market denom %s not found", depCoin.Denom)
|
||||||
found = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return sdkerrors.Wrapf(types.ErrInvalidDepositDenom, "liquidity provider denom %s not found", depCoin.Denom)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ func (suite *KeeperTestSuite) TestDeposit() {
|
|||||||
"invalid deposit denom",
|
"invalid deposit denom",
|
||||||
args{
|
args{
|
||||||
depositor: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
depositor: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
||||||
amount: sdk.NewCoins(sdk.NewCoin("btcb", sdk.NewInt(100))),
|
amount: sdk.NewCoins(sdk.NewCoin("fake", sdk.NewInt(100))),
|
||||||
numberDeposits: 1,
|
numberDeposits: 1,
|
||||||
expectedAccountBalance: sdk.Coins{},
|
expectedAccountBalance: sdk.Coins{},
|
||||||
expectedModAccountBalance: sdk.Coins{},
|
expectedModAccountBalance: sdk.Coins{},
|
||||||
@ -106,14 +106,6 @@ func (suite *KeeperTestSuite) TestDeposit() {
|
|||||||
loanToValue, _ := sdk.NewDecFromStr("0.6")
|
loanToValue, _ := sdk.NewDecFromStr("0.6")
|
||||||
hardGS := types.NewGenesisState(types.NewParams(
|
hardGS := types.NewGenesisState(types.NewParams(
|
||||||
true,
|
true,
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
types.MoneyMarkets{
|
||||||
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
@ -121,7 +113,7 @@ func (suite *KeeperTestSuite) TestDeposit() {
|
|||||||
types.NewMoneyMarket("btcb", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "btcb:usd", sdk.NewInt(1000000), sdk.NewInt(BTCB_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("btcb", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "btcb:usd", sdk.NewInt(1000000), sdk.NewInt(BTCB_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
},
|
},
|
||||||
0, // LTV counter
|
0, // LTV counter
|
||||||
), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes)
|
), types.DefaultPreviousBlockTime)
|
||||||
|
|
||||||
// Pricefeed module genesis state
|
// Pricefeed module genesis state
|
||||||
pricefeedGS := pricefeed.GenesisState{
|
pricefeedGS := pricefeed.GenesisState{
|
||||||
|
52
x/hard/keeper/hooks.go
Normal file
52
x/hard/keeper/hooks.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package keeper
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
|
"github.com/kava-labs/kava/x/hard/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Implements StakingHooks interface
|
||||||
|
var _ types.HARDHooks = Keeper{}
|
||||||
|
|
||||||
|
// AfterDepositCreated - call hook if registered
|
||||||
|
func (k Keeper) AfterDepositCreated(ctx sdk.Context, deposit types.Deposit) {
|
||||||
|
if k.hooks != nil {
|
||||||
|
k.hooks.AfterDepositCreated(ctx, deposit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeforeDepositModified - call hook if registered
|
||||||
|
func (k Keeper) BeforeDepositModified(ctx sdk.Context, deposit types.Deposit) {
|
||||||
|
if k.hooks != nil {
|
||||||
|
k.hooks.BeforeDepositModified(ctx, deposit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterDepositModified - call hook if registered
|
||||||
|
func (k Keeper) AfterDepositModified(ctx sdk.Context, deposit types.Deposit) {
|
||||||
|
if k.hooks != nil {
|
||||||
|
k.hooks.AfterDepositModified(ctx, deposit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterBorrowCreated - call hook if registered
|
||||||
|
func (k Keeper) AfterBorrowCreated(ctx sdk.Context, borrow types.Borrow) {
|
||||||
|
if k.hooks != nil {
|
||||||
|
k.hooks.AfterBorrowCreated(ctx, borrow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeforeBorrowModified - call hook if registered
|
||||||
|
func (k Keeper) BeforeBorrowModified(ctx sdk.Context, borrow types.Borrow) {
|
||||||
|
if k.hooks != nil {
|
||||||
|
k.hooks.BeforeBorrowModified(ctx, borrow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterBorrowModified - call hook if registered
|
||||||
|
func (k Keeper) AfterBorrowModified(ctx sdk.Context, borrow types.Borrow) {
|
||||||
|
if k.hooks != nil {
|
||||||
|
k.hooks.AfterBorrowModified(ctx, borrow)
|
||||||
|
}
|
||||||
|
}
|
@ -135,7 +135,6 @@ func (k Keeper) AccrueInterest(ctx sdk.Context, denom string) error {
|
|||||||
k.IncrementBorrowedCoins(ctx, totalBorrowInterestAccumulated)
|
k.IncrementBorrowedCoins(ctx, totalBorrowInterestAccumulated)
|
||||||
k.IncrementSuppliedCoins(ctx, sdk.NewCoins(sdk.NewCoin(denom, supplyInterestNew)))
|
k.IncrementSuppliedCoins(ctx, sdk.NewCoins(sdk.NewCoin(denom, supplyInterestNew)))
|
||||||
k.SetTotalReserves(ctx, denom, reservesPrior.Add(sdk.NewCoin(mm.Denom, reservesNew)))
|
k.SetTotalReserves(ctx, denom, reservesPrior.Add(sdk.NewCoin(mm.Denom, reservesNew)))
|
||||||
k.SetSupplyInterestFactor(ctx, denom, supplyInterestFactorNew)
|
|
||||||
k.SetPreviousAccrualTime(ctx, denom, ctx.BlockTime())
|
k.SetPreviousAccrualTime(ctx, denom, ctx.BlockTime())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -712,14 +712,6 @@ func (suite *KeeperTestSuite) TestBorrowInterest() {
|
|||||||
// Hard module genesis state
|
// Hard module genesis state
|
||||||
hardGS := types.NewGenesisState(types.NewParams(
|
hardGS := types.NewGenesisState(types.NewParams(
|
||||||
true,
|
true,
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "ukava", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
types.MoneyMarkets{
|
||||||
types.NewMoneyMarket("ukava",
|
types.NewMoneyMarket("ukava",
|
||||||
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.8")), // Borrow Limit
|
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.8")), // Borrow Limit
|
||||||
@ -731,7 +723,7 @@ func (suite *KeeperTestSuite) TestBorrowInterest() {
|
|||||||
sdk.ZeroDec()), // Keeper Reward Percentage
|
sdk.ZeroDec()), // Keeper Reward Percentage
|
||||||
},
|
},
|
||||||
0, // LTV counter
|
0, // LTV counter
|
||||||
), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes)
|
), types.DefaultPreviousBlockTime)
|
||||||
|
|
||||||
// Pricefeed module genesis state
|
// Pricefeed module genesis state
|
||||||
pricefeedGS := pricefeed.GenesisState{
|
pricefeedGS := pricefeed.GenesisState{
|
||||||
@ -1127,15 +1119,6 @@ func (suite *KeeperTestSuite) TestSupplyInterest() {
|
|||||||
// Hard module genesis state
|
// Hard module genesis state
|
||||||
hardGS := types.NewGenesisState(types.NewParams(
|
hardGS := types.NewGenesisState(types.NewParams(
|
||||||
true,
|
true,
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "ukava", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
types.MoneyMarkets{
|
||||||
types.NewMoneyMarket("ukava",
|
types.NewMoneyMarket("ukava",
|
||||||
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.8")), // Borrow Limit
|
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.8")), // Borrow Limit
|
||||||
@ -1155,7 +1138,7 @@ func (suite *KeeperTestSuite) TestSupplyInterest() {
|
|||||||
sdk.ZeroDec()), // Keeper Reward Percentage
|
sdk.ZeroDec()), // Keeper Reward Percentage
|
||||||
},
|
},
|
||||||
0, // LTV counter
|
0, // LTV counter
|
||||||
), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes)
|
), types.DefaultPreviousBlockTime)
|
||||||
|
|
||||||
// Pricefeed module genesis state
|
// Pricefeed module genesis state
|
||||||
pricefeedGS := pricefeed.GenesisState{
|
pricefeedGS := pricefeed.GenesisState{
|
||||||
|
@ -21,6 +21,7 @@ type Keeper struct {
|
|||||||
stakingKeeper types.StakingKeeper
|
stakingKeeper types.StakingKeeper
|
||||||
pricefeedKeeper types.PricefeedKeeper
|
pricefeedKeeper types.PricefeedKeeper
|
||||||
auctionKeeper types.AuctionKeeper
|
auctionKeeper types.AuctionKeeper
|
||||||
|
hooks types.HARDHooks
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewKeeper creates a new keeper
|
// NewKeeper creates a new keeper
|
||||||
@ -40,9 +41,19 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramstore subspace.Subspace,
|
|||||||
stakingKeeper: stk,
|
stakingKeeper: stk,
|
||||||
pricefeedKeeper: pfk,
|
pricefeedKeeper: pfk,
|
||||||
auctionKeeper: auk,
|
auctionKeeper: auk,
|
||||||
|
hooks: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetHooks sets the cdp keeper hooks
|
||||||
|
func (k *Keeper) SetHooks(hooks types.HARDHooks) *Keeper {
|
||||||
|
if k.hooks != nil {
|
||||||
|
panic("cannot set validator hooks twice")
|
||||||
|
}
|
||||||
|
k.hooks = hooks
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
// GetPreviousBlockTime get the blocktime for the previous block
|
// GetPreviousBlockTime get the blocktime for the previous block
|
||||||
func (k Keeper) GetPreviousBlockTime(ctx sdk.Context) (blockTime time.Time, found bool) {
|
func (k Keeper) GetPreviousBlockTime(ctx sdk.Context) (blockTime time.Time, found bool) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousBlockTimeKey)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousBlockTimeKey)
|
||||||
@ -60,23 +71,6 @@ func (k Keeper) SetPreviousBlockTime(ctx sdk.Context, blockTime time.Time) {
|
|||||||
store.Set([]byte{}, k.cdc.MustMarshalBinaryBare(blockTime))
|
store.Set([]byte{}, k.cdc.MustMarshalBinaryBare(blockTime))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPreviousDelegatorDistribution get the time of the previous delegator distribution
|
|
||||||
func (k Keeper) GetPreviousDelegatorDistribution(ctx sdk.Context, denom string) (distTime time.Time, found bool) {
|
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousDelegationDistributionKey)
|
|
||||||
bz := store.Get([]byte(denom))
|
|
||||||
if bz == nil {
|
|
||||||
return time.Time{}, false
|
|
||||||
}
|
|
||||||
k.cdc.MustUnmarshalBinaryBare(bz, &distTime)
|
|
||||||
return distTime, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPreviousDelegationDistribution set the time of the previous delegator distribution
|
|
||||||
func (k Keeper) SetPreviousDelegationDistribution(ctx sdk.Context, distTime time.Time, denom string) {
|
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousDelegationDistributionKey)
|
|
||||||
store.Set([]byte(denom), k.cdc.MustMarshalBinaryBare(distTime))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDeposit returns a deposit from the store for a particular depositor address, deposit denom
|
// GetDeposit returns a deposit from the store for a particular depositor address, deposit denom
|
||||||
func (k Keeper) GetDeposit(ctx sdk.Context, depositor sdk.AccAddress) (types.Deposit, bool) {
|
func (k Keeper) GetDeposit(ctx sdk.Context, depositor sdk.AccAddress) (types.Deposit, bool) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.DepositsKeyPrefix)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.DepositsKeyPrefix)
|
||||||
@ -116,59 +110,6 @@ func (k Keeper) IterateDeposits(ctx sdk.Context, cb func(deposit types.Deposit)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClaim returns a claim from the store for a particular claim owner, deposit denom, and claim type
|
|
||||||
func (k Keeper) GetClaim(ctx sdk.Context, owner sdk.AccAddress, depositDenom string, claimType types.ClaimType) (types.Claim, bool) {
|
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimsKeyPrefix)
|
|
||||||
bz := store.Get(types.ClaimKey(claimType, depositDenom, owner))
|
|
||||||
if bz == nil {
|
|
||||||
return types.Claim{}, false
|
|
||||||
}
|
|
||||||
var claim types.Claim
|
|
||||||
k.cdc.MustUnmarshalBinaryBare(bz, &claim)
|
|
||||||
return claim, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetClaim stores the input claim in the store, prefixed by the deposit type, deposit denom, and owner address, in that order
|
|
||||||
func (k Keeper) SetClaim(ctx sdk.Context, claim types.Claim) {
|
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimsKeyPrefix)
|
|
||||||
bz := k.cdc.MustMarshalBinaryBare(claim)
|
|
||||||
store.Set(types.ClaimKey(claim.Type, claim.DepositDenom, claim.Owner), bz)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteClaim deletes a claim from the store
|
|
||||||
func (k Keeper) DeleteClaim(ctx sdk.Context, claim types.Claim) {
|
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimsKeyPrefix)
|
|
||||||
store.Delete(types.ClaimKey(claim.Type, claim.DepositDenom, claim.Owner))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IterateClaims iterates over all claim objects in the store and performs a callback function
|
|
||||||
func (k Keeper) IterateClaims(ctx sdk.Context, cb func(claim types.Claim) (stop bool)) {
|
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimsKeyPrefix)
|
|
||||||
iterator := sdk.KVStorePrefixIterator(store, []byte{})
|
|
||||||
defer iterator.Close()
|
|
||||||
for ; iterator.Valid(); iterator.Next() {
|
|
||||||
var claim types.Claim
|
|
||||||
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &claim)
|
|
||||||
if cb(claim) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IterateClaimsByTypeAndDenom iterates over all claim objects in the store with the matching claim type and deposit denom and performs a callback function
|
|
||||||
func (k Keeper) IterateClaimsByTypeAndDenom(ctx sdk.Context, claimType types.ClaimType, depositDenom string, cb func(claim types.Claim) (stop bool)) {
|
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimsKeyPrefix)
|
|
||||||
iterator := sdk.KVStorePrefixIterator(store, types.ClaimTypeIteratorKey(claimType, depositDenom))
|
|
||||||
defer iterator.Close()
|
|
||||||
for ; iterator.Valid(); iterator.Next() {
|
|
||||||
var claim types.Claim
|
|
||||||
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &claim)
|
|
||||||
if cb(claim) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDepositsByUser gets all deposits for an individual user
|
// GetDepositsByUser gets all deposits for an individual user
|
||||||
func (k Keeper) GetDepositsByUser(ctx sdk.Context, user sdk.AccAddress) []types.Deposit {
|
func (k Keeper) GetDepositsByUser(ctx sdk.Context, user sdk.AccAddress) []types.Deposit {
|
||||||
var deposits []types.Deposit
|
var deposits []types.Deposit
|
||||||
|
@ -60,21 +60,6 @@ func (suite *KeeperTestSuite) TestGetSetPreviousBlockTime() {
|
|||||||
suite.Equal(now, pbt)
|
suite.Equal(now, pbt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestGetSetPreviousDelegatorDistribution() {
|
|
||||||
now := tmtime.Now()
|
|
||||||
|
|
||||||
_, f := suite.keeper.GetPreviousDelegatorDistribution(suite.ctx, suite.keeper.BondDenom(suite.ctx))
|
|
||||||
suite.Require().False(f)
|
|
||||||
|
|
||||||
suite.NotPanics(func() {
|
|
||||||
suite.keeper.SetPreviousDelegationDistribution(suite.ctx, now, suite.keeper.BondDenom(suite.ctx))
|
|
||||||
})
|
|
||||||
|
|
||||||
pdt, f := suite.keeper.GetPreviousDelegatorDistribution(suite.ctx, suite.keeper.BondDenom(suite.ctx))
|
|
||||||
suite.True(f)
|
|
||||||
suite.Equal(now, pdt)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestGetSetDeleteDeposit() {
|
func (suite *KeeperTestSuite) TestGetSetDeleteDeposit() {
|
||||||
dep := types.NewDeposit(sdk.AccAddress("test"), sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(100))),
|
dep := types.NewDeposit(sdk.AccAddress("test"), sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(100))),
|
||||||
types.SupplyInterestFactors{types.NewSupplyInterestFactor("", sdk.MustNewDecFromStr("0"))})
|
types.SupplyInterestFactors{types.NewSupplyInterestFactor("", sdk.MustNewDecFromStr("0"))})
|
||||||
@ -108,21 +93,6 @@ func (suite *KeeperTestSuite) TestIterateDeposits() {
|
|||||||
suite.Require().Equal(5, len(deposits))
|
suite.Require().Equal(5, len(deposits))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestGetSetDeleteClaim() {
|
|
||||||
claim := types.NewClaim(sdk.AccAddress("test"), "bnb", sdk.NewCoin("hard", sdk.NewInt(100)), "lp")
|
|
||||||
_, f := suite.keeper.GetClaim(suite.ctx, sdk.AccAddress("test"), "bnb", "lp")
|
|
||||||
suite.Require().False(f)
|
|
||||||
|
|
||||||
suite.Require().NotPanics(func() { suite.keeper.SetClaim(suite.ctx, claim) })
|
|
||||||
testClaim, f := suite.keeper.GetClaim(suite.ctx, sdk.AccAddress("test"), "bnb", "lp")
|
|
||||||
suite.Require().True(f)
|
|
||||||
suite.Require().Equal(claim, testClaim)
|
|
||||||
|
|
||||||
suite.Require().NotPanics(func() { suite.keeper.DeleteClaim(suite.ctx, claim) })
|
|
||||||
_, f = suite.keeper.GetClaim(suite.ctx, sdk.AccAddress("test"), "bnb", "lp")
|
|
||||||
suite.Require().False(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestGetSetDeleteInterestRateModel() {
|
func (suite *KeeperTestSuite) TestGetSetDeleteInterestRateModel() {
|
||||||
denom := "test"
|
denom := "test"
|
||||||
model := types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10"))
|
model := types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10"))
|
||||||
|
@ -39,9 +39,6 @@ func (k Keeper) AttemptKeeperLiquidation(ctx sdk.Context, keeper sdk.AccAddress,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
k.SyncBorrowInterest(ctx, borrower)
|
|
||||||
k.SyncSupplyInterest(ctx, borrower)
|
|
||||||
|
|
||||||
deposit, found := k.GetDeposit(ctx, borrower)
|
deposit, found := k.GetDeposit(ctx, borrower)
|
||||||
if !found {
|
if !found {
|
||||||
return types.ErrDepositNotFound
|
return types.ErrDepositNotFound
|
||||||
@ -52,6 +49,23 @@ func (k Keeper) AttemptKeeperLiquidation(ctx sdk.Context, keeper sdk.AccAddress,
|
|||||||
return types.ErrBorrowNotFound
|
return types.ErrBorrowNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call incentive hooks
|
||||||
|
k.BeforeDepositModified(ctx, deposit)
|
||||||
|
k.BeforeBorrowModified(ctx, borrow)
|
||||||
|
|
||||||
|
k.SyncBorrowInterest(ctx, borrower)
|
||||||
|
k.SyncSupplyInterest(ctx, borrower)
|
||||||
|
|
||||||
|
deposit, found = k.GetDeposit(ctx, borrower)
|
||||||
|
if !found {
|
||||||
|
return types.ErrDepositNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
borrow, found = k.GetBorrow(ctx, borrower)
|
||||||
|
if !found {
|
||||||
|
return types.ErrBorrowNotFound
|
||||||
|
}
|
||||||
|
|
||||||
isWithinRange, err := k.IsWithinValidLtvRange(ctx, deposit, borrow)
|
isWithinRange, err := k.IsWithinValidLtvRange(ctx, deposit, borrow)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -123,20 +123,6 @@ func (suite *KeeperTestSuite) TestIndexLiquidation() {
|
|||||||
// Hard module genesis state
|
// Hard module genesis state
|
||||||
hardGS := types.NewGenesisState(types.NewParams(
|
hardGS := types.NewGenesisState(types.NewParams(
|
||||||
true,
|
true,
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "usdc", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "usdt", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "dai", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "ukava", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "btc", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
types.MoneyMarkets{
|
||||||
types.NewMoneyMarket("usdx",
|
types.NewMoneyMarket("usdx",
|
||||||
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.9")), // Borrow Limit
|
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.9")), // Borrow Limit
|
||||||
@ -196,7 +182,7 @@ func (suite *KeeperTestSuite) TestIndexLiquidation() {
|
|||||||
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
|
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
|
||||||
},
|
},
|
||||||
tc.args.ltvIndexCount, // LTV counter
|
tc.args.ltvIndexCount, // LTV counter
|
||||||
), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes)
|
), types.DefaultPreviousBlockTime)
|
||||||
|
|
||||||
// Pricefeed module genesis state
|
// Pricefeed module genesis state
|
||||||
pricefeedGS := pricefeed.GenesisState{
|
pricefeedGS := pricefeed.GenesisState{
|
||||||
@ -549,15 +535,6 @@ func (suite *KeeperTestSuite) TestFullIndexLiquidation() {
|
|||||||
// Hard module genesis state
|
// Hard module genesis state
|
||||||
hardGS := types.NewGenesisState(types.NewParams(
|
hardGS := types.NewGenesisState(types.NewParams(
|
||||||
true,
|
true,
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "ukava", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
types.MoneyMarkets{
|
||||||
types.NewMoneyMarket("usdx",
|
types.NewMoneyMarket("usdx",
|
||||||
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.9")), // Borrow Limit
|
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.9")), // Borrow Limit
|
||||||
@ -577,7 +554,7 @@ func (suite *KeeperTestSuite) TestFullIndexLiquidation() {
|
|||||||
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
|
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
|
||||||
},
|
},
|
||||||
tc.args.ltvIndexCount, // LTV counter
|
tc.args.ltvIndexCount, // LTV counter
|
||||||
), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes)
|
), types.DefaultPreviousBlockTime)
|
||||||
|
|
||||||
// Pricefeed module genesis state
|
// Pricefeed module genesis state
|
||||||
pricefeedGS := pricefeed.GenesisState{
|
pricefeedGS := pricefeed.GenesisState{
|
||||||
@ -1181,20 +1158,6 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() {
|
|||||||
// Hard module genesis state
|
// Hard module genesis state
|
||||||
hardGS := types.NewGenesisState(types.NewParams(
|
hardGS := types.NewGenesisState(types.NewParams(
|
||||||
true,
|
true,
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "usdc", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "usdt", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "dai", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "ukava", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "btc", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
types.MoneyMarkets{
|
||||||
types.NewMoneyMarket("usdx",
|
types.NewMoneyMarket("usdx",
|
||||||
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.9")), // Borrow Limit
|
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.9")), // Borrow Limit
|
||||||
@ -1254,7 +1217,7 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() {
|
|||||||
tc.args.keeperRewardPercent), // Keeper Reward Percent
|
tc.args.keeperRewardPercent), // Keeper Reward Percent
|
||||||
},
|
},
|
||||||
0, // LTV counter
|
0, // LTV counter
|
||||||
), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes)
|
), types.DefaultPreviousBlockTime)
|
||||||
|
|
||||||
// Pricefeed module genesis state
|
// Pricefeed module genesis state
|
||||||
pricefeedGS := pricefeed.GenesisState{
|
pricefeedGS := pricefeed.GenesisState{
|
||||||
|
@ -18,28 +18,6 @@ func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
|
|||||||
k.paramSubspace.SetParamSet(ctx, ¶ms)
|
k.paramSubspace.SetParamSet(ctx, ¶ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLPSchedule gets the LP's schedule
|
|
||||||
func (k Keeper) GetLPSchedule(ctx sdk.Context, denom string) (types.DistributionSchedule, bool) {
|
|
||||||
params := k.GetParams(ctx)
|
|
||||||
for _, lps := range params.LiquidityProviderSchedules {
|
|
||||||
if lps.DepositDenom == denom {
|
|
||||||
return lps, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return types.DistributionSchedule{}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDelegatorSchedule gets the Delgator's schedule
|
|
||||||
func (k Keeper) GetDelegatorSchedule(ctx sdk.Context, denom string) (types.DelegatorDistributionSchedule, bool) {
|
|
||||||
params := k.GetParams(ctx)
|
|
||||||
for _, dds := range params.DelegatorDistributionSchedules {
|
|
||||||
if dds.DistributionSchedule.DepositDenom == denom {
|
|
||||||
return dds, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return types.DelegatorDistributionSchedule{}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMoneyMarketParam returns the corresponding Money Market param for a specific denom
|
// GetMoneyMarketParam returns the corresponding Money Market param for a specific denom
|
||||||
func (k Keeper) GetMoneyMarketParam(ctx sdk.Context, denom string) (types.MoneyMarket, bool) {
|
func (k Keeper) GetMoneyMarketParam(ctx sdk.Context, denom string) (types.MoneyMarket, bool) {
|
||||||
params := k.GetParams(ctx)
|
params := k.GetParams(ctx)
|
||||||
|
@ -24,8 +24,6 @@ func NewQuerier(k Keeper) sdk.Querier {
|
|||||||
return queryGetDeposits(ctx, req, k)
|
return queryGetDeposits(ctx, req, k)
|
||||||
case types.QueryGetTotalDeposited:
|
case types.QueryGetTotalDeposited:
|
||||||
return queryGetTotalDeposited(ctx, req, k)
|
return queryGetTotalDeposited(ctx, req, k)
|
||||||
case types.QueryGetClaims:
|
|
||||||
return queryGetClaims(ctx, req, k)
|
|
||||||
case types.QueryGetBorrows:
|
case types.QueryGetBorrows:
|
||||||
return queryGetBorrows(ctx, req, k)
|
return queryGetBorrows(ctx, req, k)
|
||||||
case types.QueryGetTotalBorrowed:
|
case types.QueryGetTotalBorrowed:
|
||||||
@ -149,111 +147,6 @@ func queryGetDeposits(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte,
|
|||||||
return bz, nil
|
return bz, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryGetClaims(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
|
|
||||||
|
|
||||||
var params types.QueryClaimParams
|
|
||||||
err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms)
|
|
||||||
if err != nil {
|
|
||||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
|
|
||||||
}
|
|
||||||
depositDenom := len(params.Denom) > 0
|
|
||||||
owner := len(params.Owner) > 0
|
|
||||||
claimType := len(params.ClaimType) > 0
|
|
||||||
|
|
||||||
var claims []types.Claim
|
|
||||||
switch {
|
|
||||||
case depositDenom && owner && claimType:
|
|
||||||
claim, found := k.GetClaim(ctx, params.Owner, params.Denom, params.ClaimType)
|
|
||||||
if found {
|
|
||||||
claims = append(claims, claim)
|
|
||||||
}
|
|
||||||
case depositDenom && owner:
|
|
||||||
for _, dt := range types.ClaimTypesClaimQuery {
|
|
||||||
claim, found := k.GetClaim(ctx, params.Owner, params.Denom, dt)
|
|
||||||
if found {
|
|
||||||
claims = append(claims, claim)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case depositDenom && claimType:
|
|
||||||
k.IterateClaimsByTypeAndDenom(ctx, params.ClaimType, params.Denom, func(claim types.Claim) (stop bool) {
|
|
||||||
claims = append(claims, claim)
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
case owner && claimType:
|
|
||||||
hardParams := k.GetParams(ctx)
|
|
||||||
switch {
|
|
||||||
case params.ClaimType == types.LP:
|
|
||||||
for _, lps := range hardParams.LiquidityProviderSchedules {
|
|
||||||
claim, found := k.GetClaim(ctx, params.Owner, lps.DepositDenom, params.ClaimType)
|
|
||||||
if found {
|
|
||||||
claims = append(claims, claim)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case params.ClaimType == types.Stake:
|
|
||||||
for _, dss := range hardParams.DelegatorDistributionSchedules {
|
|
||||||
claim, found := k.GetClaim(ctx, params.Owner, dss.DistributionSchedule.DepositDenom, params.ClaimType)
|
|
||||||
if found {
|
|
||||||
claims = append(claims, claim)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case depositDenom:
|
|
||||||
for _, dt := range types.ClaimTypesClaimQuery {
|
|
||||||
k.IterateClaimsByTypeAndDenom(ctx, dt, params.Denom, func(claim types.Claim) (stop bool) {
|
|
||||||
claims = append(claims, claim)
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
case owner:
|
|
||||||
hardParams := k.GetParams(ctx)
|
|
||||||
for _, lps := range hardParams.LiquidityProviderSchedules {
|
|
||||||
claim, found := k.GetClaim(ctx, params.Owner, lps.DepositDenom, types.LP)
|
|
||||||
if found {
|
|
||||||
claims = append(claims, claim)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, dds := range hardParams.DelegatorDistributionSchedules {
|
|
||||||
claim, found := k.GetClaim(ctx, params.Owner, dds.DistributionSchedule.DepositDenom, types.Stake)
|
|
||||||
if found {
|
|
||||||
claims = append(claims, claim)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case claimType:
|
|
||||||
hardParams := k.GetParams(ctx)
|
|
||||||
for _, lps := range hardParams.LiquidityProviderSchedules {
|
|
||||||
k.IterateClaimsByTypeAndDenom(ctx, params.ClaimType, lps.DepositDenom, func(claim types.Claim) (stop bool) {
|
|
||||||
claims = append(claims, claim)
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
for _, dds := range hardParams.DelegatorDistributionSchedules {
|
|
||||||
k.IterateClaimsByTypeAndDenom(ctx, params.ClaimType, dds.DistributionSchedule.DepositDenom, func(claim types.Claim) (stop bool) {
|
|
||||||
claims = append(claims, claim)
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
k.IterateClaims(ctx, func(claim types.Claim) (stop bool) {
|
|
||||||
claims = append(claims, claim)
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
start, end := client.Paginate(len(claims), params.Page, params.Limit, 100)
|
|
||||||
if start < 0 || end < 0 {
|
|
||||||
claims = []types.Claim{}
|
|
||||||
} else {
|
|
||||||
claims = claims[start:end]
|
|
||||||
}
|
|
||||||
|
|
||||||
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, claims)
|
|
||||||
if err != nil {
|
|
||||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return bz, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func queryGetBorrows(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
|
func queryGetBorrows(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
|
||||||
|
|
||||||
var params types.QueryBorrowsParams
|
var params types.QueryBorrowsParams
|
||||||
|
@ -15,6 +15,14 @@ func (k Keeper) Repay(ctx sdk.Context, sender sdk.AccAddress, coins sdk.Coins) e
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check borrow exists here to avoid duplicating store read in ValidateRepay
|
||||||
|
borrow, found := k.GetBorrow(ctx, sender)
|
||||||
|
if !found {
|
||||||
|
return types.ErrBorrowNotFound
|
||||||
|
}
|
||||||
|
// Call incentive hook
|
||||||
|
k.BeforeBorrowModified(ctx, borrow)
|
||||||
|
|
||||||
// Sync borrow interest so loan is up-to-date
|
// Sync borrow interest so loan is up-to-date
|
||||||
k.SyncBorrowInterest(ctx, sender)
|
k.SyncBorrowInterest(ctx, sender)
|
||||||
|
|
||||||
@ -24,12 +32,6 @@ func (k Keeper) Repay(ctx sdk.Context, sender sdk.AccAddress, coins sdk.Coins) e
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check borrow exists here to avoid duplicating store read in ValidateRepay
|
|
||||||
borrow, found := k.GetBorrow(ctx, sender)
|
|
||||||
if !found {
|
|
||||||
return types.ErrBorrowNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
payment, err := k.CalculatePaymentAmount(borrow.Amount, coins)
|
payment, err := k.CalculatePaymentAmount(borrow.Amount, coins)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -59,6 +61,11 @@ func (k Keeper) Repay(ctx sdk.Context, sender sdk.AccAddress, coins sdk.Coins) e
|
|||||||
// Update total borrowed amount
|
// Update total borrowed amount
|
||||||
k.DecrementBorrowedCoins(ctx, payment)
|
k.DecrementBorrowedCoins(ctx, payment)
|
||||||
|
|
||||||
|
// Call incentive hook
|
||||||
|
if !borrow.Amount.Empty() {
|
||||||
|
k.AfterBorrowModified(ctx, borrow)
|
||||||
|
}
|
||||||
|
|
||||||
ctx.EventManager().EmitEvent(
|
ctx.EventManager().EmitEvent(
|
||||||
sdk.NewEvent(
|
sdk.NewEvent(
|
||||||
types.EventTypeHardRepay,
|
types.EventTypeHardRepay,
|
||||||
|
@ -138,15 +138,6 @@ func (suite *KeeperTestSuite) TestRepay() {
|
|||||||
// Hard module genesis state
|
// Hard module genesis state
|
||||||
hardGS := types.NewGenesisState(types.NewParams(
|
hardGS := types.NewGenesisState(types.NewParams(
|
||||||
true,
|
true,
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "ukava", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
types.MoneyMarkets{
|
||||||
types.NewMoneyMarket("usdx",
|
types.NewMoneyMarket("usdx",
|
||||||
types.NewBorrowLimit(false, sdk.NewDec(100000000*USDX_CF), sdk.MustNewDecFromStr("1")), // Borrow Limit
|
types.NewBorrowLimit(false, sdk.NewDec(100000000*USDX_CF), sdk.MustNewDecFromStr("1")), // Borrow Limit
|
||||||
@ -166,7 +157,7 @@ func (suite *KeeperTestSuite) TestRepay() {
|
|||||||
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
|
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
|
||||||
},
|
},
|
||||||
0, // LTV counter
|
0, // LTV counter
|
||||||
), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes)
|
), types.DefaultPreviousBlockTime)
|
||||||
|
|
||||||
// Pricefeed module genesis state
|
// Pricefeed module genesis state
|
||||||
pricefeedGS := pricefeed.GenesisState{
|
pricefeedGS := pricefeed.GenesisState{
|
||||||
|
@ -1,175 +0,0 @@
|
|||||||
package keeper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
stakingexported "github.com/cosmos/cosmos-sdk/x/staking/exported"
|
|
||||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
|
||||||
|
|
||||||
"github.com/kava-labs/kava/x/hard/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ApplyDepositRewards iterates over lp and gov deposits and updates the amount of rewards for each depositor
|
|
||||||
func (k Keeper) ApplyDepositRewards(ctx sdk.Context) {
|
|
||||||
previousBlockTime, found := k.GetPreviousBlockTime(ctx)
|
|
||||||
if !found {
|
|
||||||
previousBlockTime = ctx.BlockTime()
|
|
||||||
k.SetPreviousBlockTime(ctx, previousBlockTime)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
params := k.GetParams(ctx)
|
|
||||||
if !params.Active {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
timeElapsed := sdk.NewInt(ctx.BlockTime().Unix() - previousBlockTime.Unix())
|
|
||||||
|
|
||||||
for _, lps := range params.LiquidityProviderSchedules {
|
|
||||||
if !lps.Active {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if lps.End.Before(ctx.BlockTime()) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if lps.Start.After(ctx.BlockTime()) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
totalDeposited := k.GetTotalDeposited(ctx, lps.DepositDenom)
|
|
||||||
if totalDeposited.IsZero() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rewardsToDistribute := lps.RewardsPerSecond.Amount.Mul(timeElapsed)
|
|
||||||
if rewardsToDistribute.IsZero() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rewardsDistributed := sdk.ZeroInt()
|
|
||||||
k.IterateDeposits(ctx, func(dep types.Deposit) (stop bool) {
|
|
||||||
rewardsShare := sdk.NewDecFromInt(dep.Amount.AmountOf(lps.DepositDenom)).Quo(sdk.NewDecFromInt(totalDeposited))
|
|
||||||
if rewardsShare.IsZero() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
rewardsEarned := rewardsShare.Mul(sdk.NewDecFromInt(rewardsToDistribute)).RoundInt()
|
|
||||||
if rewardsEarned.IsZero() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
k.AddToClaim(ctx, dep.Depositor, lps.DepositDenom, types.LP, sdk.NewCoin(lps.RewardsPerSecond.Denom, rewardsEarned))
|
|
||||||
rewardsDistributed = rewardsDistributed.Add(rewardsEarned)
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
ctx.EventManager().EmitEvent(
|
|
||||||
sdk.NewEvent(
|
|
||||||
types.EventTypeHardLPDistribution,
|
|
||||||
sdk.NewAttribute(types.AttributeKeyBlockHeight, fmt.Sprintf("%d", ctx.BlockHeight())),
|
|
||||||
sdk.NewAttribute(types.AttributeKeyRewardsDistribution, rewardsDistributed.String()),
|
|
||||||
sdk.NewAttribute(types.AttributeKeyDepositDenom, lps.DepositDenom),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
k.SetPreviousBlockTime(ctx, ctx.BlockTime())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShouldDistributeValidatorRewards returns true if enough time has elapsed such that rewards should be distributed to delegators
|
|
||||||
func (k Keeper) ShouldDistributeValidatorRewards(ctx sdk.Context, denom string) bool {
|
|
||||||
previousDistributionTime, found := k.GetPreviousDelegatorDistribution(ctx, denom)
|
|
||||||
if !found {
|
|
||||||
k.SetPreviousDelegationDistribution(ctx, ctx.BlockTime(), denom)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
params := k.GetParams(ctx)
|
|
||||||
if !params.Active {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, dds := range params.DelegatorDistributionSchedules {
|
|
||||||
if denom != dds.DistributionSchedule.DepositDenom {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if dds.DistributionSchedule.End.Before(ctx.BlockTime()) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
timeElapsed := sdk.NewInt(ctx.BlockTime().Unix() - previousDistributionTime.Unix())
|
|
||||||
if timeElapsed.GTE(sdk.NewInt(int64(dds.DistributionFrequency.Seconds()))) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyDelegationRewards iterates over each delegation object in the staking store and applies rewards according to the input delegation distribution schedule
|
|
||||||
func (k Keeper) ApplyDelegationRewards(ctx sdk.Context, denom string) {
|
|
||||||
dds, found := k.GetDelegatorSchedule(ctx, denom)
|
|
||||||
if !found {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !dds.DistributionSchedule.Active {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if dds.DistributionSchedule.Start.After(ctx.BlockTime()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
bondMacc := k.stakingKeeper.GetBondedPool(ctx)
|
|
||||||
bondedCoinAmount := bondMacc.GetCoins().AmountOf(dds.DistributionSchedule.DepositDenom)
|
|
||||||
if bondedCoinAmount.IsZero() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
previousDistributionTime, found := k.GetPreviousDelegatorDistribution(ctx, dds.DistributionSchedule.DepositDenom)
|
|
||||||
if !found {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
timeElapsed := sdk.NewInt(ctx.BlockTime().Unix() - previousDistributionTime.Unix())
|
|
||||||
rewardsToDistribute := dds.DistributionSchedule.RewardsPerSecond.Amount.Mul(timeElapsed)
|
|
||||||
|
|
||||||
// create a map that has each validator address (sdk.ValAddress) as a key and the coversion factor for going from delegator shares to tokens for delegations to that validator.
|
|
||||||
// If a validator has never been slashed, the conversion factor will be 1.0, if they have been, it will be < 1.0
|
|
||||||
sharesToTokens := make(map[string]sdk.Dec)
|
|
||||||
k.stakingKeeper.IterateValidators(ctx, func(index int64, validator stakingexported.ValidatorI) (stop bool) {
|
|
||||||
if validator.GetTokens().IsZero() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// don't include a validator if it's unbonded or unbonding- ie delegators don't accumulate rewards when delegated to an unbonded/slashed validator
|
|
||||||
if validator.GetStatus() != sdk.Bonded {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
sharesToTokens[validator.GetOperator().String()] = sdk.NewDecFromInt(validator.GetTokens()).Quo(validator.GetDelegatorShares())
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
rewardsDistributed := sdk.ZeroInt()
|
|
||||||
|
|
||||||
k.stakingKeeper.IterateAllDelegations(ctx, func(delegation stakingtypes.Delegation) (stop bool) {
|
|
||||||
conversionFactor, ok := sharesToTokens[delegation.ValidatorAddress.String()]
|
|
||||||
if ok {
|
|
||||||
delegationTokens := conversionFactor.Mul(delegation.Shares)
|
|
||||||
delegationShare := delegationTokens.Quo(sdk.NewDecFromInt(bondedCoinAmount))
|
|
||||||
rewardsEarned := delegationShare.Mul(sdk.NewDecFromInt(rewardsToDistribute)).RoundInt()
|
|
||||||
if rewardsEarned.IsZero() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
k.AddToClaim(
|
|
||||||
ctx, delegation.DelegatorAddress, dds.DistributionSchedule.DepositDenom,
|
|
||||||
types.Stake, sdk.NewCoin(dds.DistributionSchedule.RewardsPerSecond.Denom, rewardsEarned))
|
|
||||||
rewardsDistributed = rewardsDistributed.Add(rewardsEarned)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
ctx.EventManager().EmitEvent(
|
|
||||||
sdk.NewEvent(
|
|
||||||
types.EventTypeHardDelegatorDistribution,
|
|
||||||
sdk.NewAttribute(types.AttributeKeyBlockHeight, fmt.Sprintf("%d", ctx.BlockHeight())),
|
|
||||||
sdk.NewAttribute(types.AttributeKeyRewardsDistribution, rewardsDistributed.String()),
|
|
||||||
sdk.NewAttribute(types.AttributeKeyDepositDenom, denom),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddToClaim adds the input amount to an existing claim or creates a new one
|
|
||||||
func (k Keeper) AddToClaim(ctx sdk.Context, owner sdk.AccAddress, depositDenom string, claimType types.ClaimType, amountToAdd sdk.Coin) {
|
|
||||||
claim, found := k.GetClaim(ctx, owner, depositDenom, claimType)
|
|
||||||
if !found {
|
|
||||||
claim = types.NewClaim(owner, depositDenom, amountToAdd, claimType)
|
|
||||||
} else {
|
|
||||||
claim.Amount = claim.Amount.Add(amountToAdd)
|
|
||||||
}
|
|
||||||
k.SetClaim(ctx, claim)
|
|
||||||
}
|
|
@ -1,476 +0,0 @@
|
|||||||
package keeper_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
|
||||||
"github.com/stretchr/testify/suite"
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
|
||||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
|
||||||
|
|
||||||
"github.com/kava-labs/kava/app"
|
|
||||||
"github.com/kava-labs/kava/x/hard/keeper"
|
|
||||||
"github.com/kava-labs/kava/x/hard/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestApplyDepositRewards() {
|
|
||||||
type args struct {
|
|
||||||
depositor sdk.AccAddress
|
|
||||||
denom string
|
|
||||||
depositAmount sdk.Coins
|
|
||||||
totalDeposits sdk.Coin
|
|
||||||
rewardRate sdk.Coin
|
|
||||||
claimType types.ClaimType
|
|
||||||
previousBlockTime time.Time
|
|
||||||
blockTime time.Time
|
|
||||||
expectedClaimBalance sdk.Coin
|
|
||||||
}
|
|
||||||
type errArgs struct {
|
|
||||||
expectPanic bool
|
|
||||||
contains string
|
|
||||||
}
|
|
||||||
type testCase struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
errArgs errArgs
|
|
||||||
}
|
|
||||||
testCases := []testCase{
|
|
||||||
{
|
|
||||||
name: "distribute rewards",
|
|
||||||
args: args{
|
|
||||||
depositor: sdk.AccAddress(crypto.AddressHash([]byte("test"))),
|
|
||||||
denom: "bnb",
|
|
||||||
rewardRate: c("hard", 500),
|
|
||||||
depositAmount: cs(c("bnb", 100)),
|
|
||||||
totalDeposits: c("bnb", 1000),
|
|
||||||
claimType: types.LP,
|
|
||||||
previousBlockTime: time.Date(2020, 11, 1, 13, 59, 50, 0, time.UTC),
|
|
||||||
blockTime: time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC),
|
|
||||||
expectedClaimBalance: c("hard", 500),
|
|
||||||
},
|
|
||||||
errArgs: errArgs{
|
|
||||||
expectPanic: false,
|
|
||||||
contains: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
suite.Run(tc.name, func() {
|
|
||||||
// Initialize test app and set context
|
|
||||||
tApp := app.NewTestApp()
|
|
||||||
ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tc.args.blockTime})
|
|
||||||
loanToValue, _ := sdk.NewDecFromStr("0.6")
|
|
||||||
hardGS := types.NewGenesisState(types.NewParams(
|
|
||||||
true,
|
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), tc.args.rewardRate, time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), tc.args.rewardRate, time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
|
||||||
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
|
||||||
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
|
||||||
},
|
|
||||||
0, // LTV counter
|
|
||||||
), tc.args.previousBlockTime, types.DefaultDistributionTimes)
|
|
||||||
tApp.InitializeFromGenesisStates(app.GenesisState{types.ModuleName: types.ModuleCdc.MustMarshalJSON(hardGS)})
|
|
||||||
supplyKeeper := tApp.GetSupplyKeeper()
|
|
||||||
supplyKeeper.MintCoins(ctx, types.ModuleAccountName, cs(tc.args.totalDeposits))
|
|
||||||
keeper := tApp.GetHardKeeper()
|
|
||||||
deposit := types.NewDeposit(tc.args.depositor, tc.args.depositAmount, types.SupplyInterestFactors{})
|
|
||||||
keeper.SetDeposit(ctx, deposit)
|
|
||||||
suite.app = tApp
|
|
||||||
suite.ctx = ctx
|
|
||||||
suite.keeper = keeper
|
|
||||||
|
|
||||||
if tc.errArgs.expectPanic {
|
|
||||||
suite.Require().Panics(func() { suite.keeper.ApplyDepositRewards(suite.ctx) })
|
|
||||||
} else {
|
|
||||||
suite.Require().NotPanics(func() { suite.keeper.ApplyDepositRewards(suite.ctx) })
|
|
||||||
claim, f := suite.keeper.GetClaim(suite.ctx, tc.args.depositor, tc.args.denom, tc.args.claimType)
|
|
||||||
suite.Require().True(f)
|
|
||||||
suite.Require().Equal(tc.args.expectedClaimBalance, claim.Amount)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestApplyDelegatorRewardsTestSuite(t *testing.T) {
|
|
||||||
suite.Run(t, new(DelegatorRewardsTestSuite))
|
|
||||||
}
|
|
||||||
|
|
||||||
type DelegatorRewardsTestSuite struct {
|
|
||||||
suite.Suite
|
|
||||||
|
|
||||||
validatorAddrs []sdk.ValAddress
|
|
||||||
delegatorAddrs []sdk.AccAddress
|
|
||||||
|
|
||||||
keeper keeper.Keeper
|
|
||||||
stakingKeeper staking.Keeper
|
|
||||||
app app.TestApp
|
|
||||||
rewardRate int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// The default state used by each test
|
|
||||||
func (suite *DelegatorRewardsTestSuite) SetupTest() {
|
|
||||||
config := sdk.GetConfig()
|
|
||||||
app.SetBech32AddressPrefixes(config)
|
|
||||||
|
|
||||||
_, allAddrs := app.GeneratePrivKeyAddressPairs(10)
|
|
||||||
suite.delegatorAddrs = allAddrs[:5]
|
|
||||||
for _, a := range allAddrs[5:] {
|
|
||||||
suite.validatorAddrs = append(suite.validatorAddrs, sdk.ValAddress(a))
|
|
||||||
}
|
|
||||||
|
|
||||||
suite.app = app.NewTestApp()
|
|
||||||
|
|
||||||
suite.rewardRate = 500
|
|
||||||
|
|
||||||
suite.app.InitializeFromGenesisStates(
|
|
||||||
equalCoinsAuthGenState(allAddrs, cs(c("ukava", 5_000_000))),
|
|
||||||
stakingGenesisState(),
|
|
||||||
hardGenesisState(c("hard", suite.rewardRate)),
|
|
||||||
)
|
|
||||||
|
|
||||||
suite.keeper = suite.app.GetHardKeeper()
|
|
||||||
suite.stakingKeeper = suite.app.GetStakingKeeper()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *DelegatorRewardsTestSuite) TestSlash() {
|
|
||||||
|
|
||||||
blockTime := time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC)
|
|
||||||
ctx := suite.app.NewContext(true, abci.Header{Height: 1, Time: blockTime})
|
|
||||||
const rewardDuration = 5
|
|
||||||
suite.keeper.SetPreviousDelegationDistribution(ctx, blockTime.Add(-1*rewardDuration*time.Second), "ukava")
|
|
||||||
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgCreateValidator(ctx, suite.validatorAddrs[0], c("ukava", 5_000_000)),
|
|
||||||
)
|
|
||||||
staking.EndBlocker(ctx, suite.stakingKeeper)
|
|
||||||
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.slashValidator(ctx, suite.validatorAddrs[0], "0.05"),
|
|
||||||
)
|
|
||||||
staking.EndBlocker(ctx, suite.stakingKeeper)
|
|
||||||
|
|
||||||
// Run function under test
|
|
||||||
suite.keeper.ApplyDelegationRewards(ctx, "ukava")
|
|
||||||
|
|
||||||
// Check claim amounts
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.verifyKavaClaimAmount(ctx, sdk.AccAddress(suite.validatorAddrs[0]), c("hard", suite.rewardRate*rewardDuration)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *DelegatorRewardsTestSuite) TestUndelegation() {
|
|
||||||
|
|
||||||
blockTime := time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC)
|
|
||||||
ctx := suite.app.NewContext(true, abci.Header{Height: 1, Time: blockTime})
|
|
||||||
const rewardDuration = 5
|
|
||||||
suite.keeper.SetPreviousDelegationDistribution(ctx, blockTime.Add(-1*rewardDuration*time.Second), "ukava")
|
|
||||||
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgCreateValidator(ctx, suite.validatorAddrs[0], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgDelegate(ctx, suite.delegatorAddrs[0], suite.validatorAddrs[0], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
staking.EndBlocker(ctx, suite.stakingKeeper)
|
|
||||||
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgUndelegate(ctx, suite.delegatorAddrs[0], suite.validatorAddrs[0], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
staking.EndBlocker(ctx, suite.stakingKeeper)
|
|
||||||
|
|
||||||
// Run function under test
|
|
||||||
suite.keeper.ApplyDelegationRewards(ctx, "ukava")
|
|
||||||
|
|
||||||
// Check claim amounts
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.verifyKavaClaimAmount(ctx, sdk.AccAddress(suite.validatorAddrs[0]), c("hard", suite.rewardRate*rewardDuration)),
|
|
||||||
)
|
|
||||||
suite.Require().False(
|
|
||||||
suite.kavaClaimExists(ctx, suite.delegatorAddrs[0]),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *DelegatorRewardsTestSuite) TestUnevenNumberDelegations() {
|
|
||||||
|
|
||||||
// Setup a context
|
|
||||||
blockTime := time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC)
|
|
||||||
ctx := suite.app.NewContext(true, abci.Header{Height: 1, Time: blockTime})
|
|
||||||
const rewardDuration = 5
|
|
||||||
suite.keeper.SetPreviousDelegationDistribution(ctx, blockTime.Add(-1*rewardDuration*time.Second), "ukava")
|
|
||||||
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgCreateValidator(ctx, suite.validatorAddrs[0], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgDelegate(ctx, suite.delegatorAddrs[0], suite.validatorAddrs[0], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgDelegate(ctx, suite.delegatorAddrs[1], suite.validatorAddrs[0], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
staking.EndBlocker(ctx, suite.stakingKeeper)
|
|
||||||
|
|
||||||
// Run function under test
|
|
||||||
suite.keeper.ApplyDelegationRewards(ctx, "ukava")
|
|
||||||
|
|
||||||
// Check claim amounts
|
|
||||||
expectedReward := suite.rewardRate * rewardDuration / 3 // floor division
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.verifyKavaClaimAmount(ctx, sdk.AccAddress(suite.validatorAddrs[0]), c("hard", expectedReward)),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.verifyKavaClaimAmount(ctx, suite.delegatorAddrs[0], c("hard", expectedReward)),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.verifyKavaClaimAmount(ctx, suite.delegatorAddrs[1], c("hard", expectedReward)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *DelegatorRewardsTestSuite) TestSlashWithUndelegated() {
|
|
||||||
|
|
||||||
// Setup a context
|
|
||||||
blockTime := time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC)
|
|
||||||
ctx := suite.app.NewContext(true, abci.Header{Height: 1, Time: blockTime})
|
|
||||||
const rewardDuration = 5
|
|
||||||
suite.keeper.SetPreviousDelegationDistribution(ctx, blockTime.Add(-1*rewardDuration*time.Second), "ukava")
|
|
||||||
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgCreateValidator(ctx, suite.validatorAddrs[0], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgDelegate(ctx, suite.delegatorAddrs[0], suite.validatorAddrs[0], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgDelegate(ctx, suite.delegatorAddrs[1], suite.validatorAddrs[0], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
staking.EndBlocker(ctx, suite.stakingKeeper)
|
|
||||||
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgUndelegate(ctx, suite.delegatorAddrs[0], suite.validatorAddrs[0], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
staking.EndBlocker(ctx, suite.stakingKeeper)
|
|
||||||
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.slashValidator(ctx, suite.validatorAddrs[0], "0.05"),
|
|
||||||
)
|
|
||||||
staking.EndBlocker(ctx, suite.stakingKeeper)
|
|
||||||
|
|
||||||
// Run function under test
|
|
||||||
suite.keeper.ApplyDelegationRewards(ctx, "ukava")
|
|
||||||
|
|
||||||
// Check claim amounts
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.verifyKavaClaimAmount(ctx, sdk.AccAddress(suite.validatorAddrs[0]), c("hard", suite.rewardRate*rewardDuration/2)),
|
|
||||||
)
|
|
||||||
suite.Require().False(
|
|
||||||
suite.kavaClaimExists(ctx, suite.delegatorAddrs[0]),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.verifyKavaClaimAmount(ctx, suite.delegatorAddrs[1], c("hard", suite.rewardRate*rewardDuration/2)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
func (suite *DelegatorRewardsTestSuite) TestUnbondingValidator() {
|
|
||||||
|
|
||||||
// Setup a context
|
|
||||||
blockTime := time.Date(2020, 11, 1, 14, 0, 0, 0, time.UTC)
|
|
||||||
ctx := suite.app.NewContext(true, abci.Header{Height: 1, Time: blockTime})
|
|
||||||
const rewardDuration = 5
|
|
||||||
suite.keeper.SetPreviousDelegationDistribution(ctx, blockTime.Add(-1*rewardDuration*time.Second), "ukava")
|
|
||||||
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgCreateValidator(ctx, suite.validatorAddrs[0], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgCreateValidator(ctx, suite.validatorAddrs[1], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgDelegate(ctx, suite.delegatorAddrs[0], suite.validatorAddrs[0], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.deliverMsgDelegate(ctx, suite.delegatorAddrs[1], suite.validatorAddrs[1], c("ukava", 1_000_000)),
|
|
||||||
)
|
|
||||||
staking.EndBlocker(ctx, suite.stakingKeeper)
|
|
||||||
|
|
||||||
suite.Require().NoError(
|
|
||||||
// jail the validator to put it into an unbonding state
|
|
||||||
suite.jailValidator(ctx, suite.validatorAddrs[0]),
|
|
||||||
)
|
|
||||||
staking.EndBlocker(ctx, suite.stakingKeeper)
|
|
||||||
|
|
||||||
// Run function under test
|
|
||||||
suite.keeper.ApplyDelegationRewards(ctx, "ukava")
|
|
||||||
|
|
||||||
// Check claim amounts
|
|
||||||
suite.Require().False(
|
|
||||||
// validator 0 will be unbonding and should not receive rewards
|
|
||||||
suite.kavaClaimExists(ctx, sdk.AccAddress(suite.validatorAddrs[0])),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.verifyKavaClaimAmount(ctx, sdk.AccAddress(suite.validatorAddrs[1]), c("hard", suite.rewardRate*rewardDuration/2)),
|
|
||||||
)
|
|
||||||
suite.Require().False(
|
|
||||||
// delegations to unbonding validators and should not receive rewards
|
|
||||||
suite.kavaClaimExists(ctx, suite.delegatorAddrs[0]),
|
|
||||||
)
|
|
||||||
suite.Require().NoError(
|
|
||||||
suite.verifyKavaClaimAmount(ctx, suite.delegatorAddrs[1], c("hard", suite.rewardRate*rewardDuration/2)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *DelegatorRewardsTestSuite) deliverMsgCreateValidator(ctx sdk.Context, address sdk.ValAddress, selfDelegation sdk.Coin) error {
|
|
||||||
msg := staking.NewMsgCreateValidator(
|
|
||||||
address,
|
|
||||||
ed25519.GenPrivKey().PubKey(),
|
|
||||||
selfDelegation,
|
|
||||||
staking.Description{},
|
|
||||||
staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
|
||||||
sdk.NewInt(1_000_000),
|
|
||||||
)
|
|
||||||
handleStakingMsg := staking.NewHandler(suite.stakingKeeper)
|
|
||||||
_, err := handleStakingMsg(ctx, msg)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
func (suite *DelegatorRewardsTestSuite) deliverMsgDelegate(ctx sdk.Context, delegator sdk.AccAddress, validator sdk.ValAddress, amount sdk.Coin) error {
|
|
||||||
msg := staking.NewMsgDelegate(
|
|
||||||
delegator,
|
|
||||||
validator,
|
|
||||||
amount,
|
|
||||||
)
|
|
||||||
handleStakingMsg := staking.NewHandler(suite.stakingKeeper)
|
|
||||||
_, err := handleStakingMsg(ctx, msg)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
func (suite *DelegatorRewardsTestSuite) deliverMsgUndelegate(ctx sdk.Context, delegator sdk.AccAddress, validator sdk.ValAddress, amount sdk.Coin) error {
|
|
||||||
msg := staking.NewMsgUndelegate(
|
|
||||||
delegator,
|
|
||||||
validator,
|
|
||||||
amount,
|
|
||||||
)
|
|
||||||
handleStakingMsg := staking.NewHandler(suite.stakingKeeper)
|
|
||||||
_, err := handleStakingMsg(ctx, msg)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *DelegatorRewardsTestSuite) slashValidator(ctx sdk.Context, validator sdk.ValAddress, slashPercent string) error {
|
|
||||||
// Assume slashable offence occurred at block 1. Note this might cause problems if tests are running at a block height higher than the unbonding period (default 3 weeks)
|
|
||||||
const infractionHeight int64 = 1
|
|
||||||
|
|
||||||
val, found := suite.stakingKeeper.GetValidator(ctx, validator)
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("can't find validator in state")
|
|
||||||
}
|
|
||||||
suite.stakingKeeper.Slash(
|
|
||||||
ctx,
|
|
||||||
sdk.GetConsAddress(val.ConsPubKey),
|
|
||||||
infractionHeight,
|
|
||||||
val.GetConsensusPower(),
|
|
||||||
sdk.MustNewDecFromStr(slashPercent),
|
|
||||||
)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (suite *DelegatorRewardsTestSuite) jailValidator(ctx sdk.Context, validator sdk.ValAddress) error {
|
|
||||||
val, found := suite.stakingKeeper.GetValidator(ctx, validator)
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("can't find validator in state")
|
|
||||||
}
|
|
||||||
suite.stakingKeeper.Jail(ctx, sdk.GetConsAddress(val.ConsPubKey))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// verifyKavaClaimAmount looks up a ukava claim and checks the claim amount is equal to an expected value
|
|
||||||
func (suite *DelegatorRewardsTestSuite) verifyKavaClaimAmount(ctx sdk.Context, owner sdk.AccAddress, expectedAmount sdk.Coin) error {
|
|
||||||
claim, found := suite.keeper.GetClaim(ctx, owner, "ukava", types.Stake)
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("could not find claim")
|
|
||||||
}
|
|
||||||
if !expectedAmount.IsEqual(claim.Amount) {
|
|
||||||
return fmt.Errorf("expected claim amount (%s) != actual claim amount (%s)", expectedAmount, claim.Amount)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// kavaClaimExists checks the store for a ukava claim
|
|
||||||
func (suite *DelegatorRewardsTestSuite) kavaClaimExists(ctx sdk.Context, owner sdk.AccAddress) bool {
|
|
||||||
_, found := suite.keeper.GetClaim(ctx, owner, "ukava", types.Stake)
|
|
||||||
return found
|
|
||||||
}
|
|
||||||
|
|
||||||
func hardGenesisState(rewardRate sdk.Coin) app.GenesisState {
|
|
||||||
loanToValue := sdk.MustNewDecFromStr("0.6")
|
|
||||||
genState := types.NewGenesisState(
|
|
||||||
types.NewParams(
|
|
||||||
true,
|
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(
|
|
||||||
true,
|
|
||||||
"bnb",
|
|
||||||
time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC),
|
|
||||||
time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC),
|
|
||||||
rewardRate,
|
|
||||||
time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC),
|
|
||||||
types.Multipliers{
|
|
||||||
types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")),
|
|
||||||
types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")),
|
|
||||||
types.NewMultiplier(types.Large, 24, sdk.OneDec()),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{
|
|
||||||
types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(
|
|
||||||
true,
|
|
||||||
"ukava",
|
|
||||||
time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC),
|
|
||||||
time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC),
|
|
||||||
rewardRate,
|
|
||||||
time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC),
|
|
||||||
types.Multipliers{
|
|
||||||
types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")),
|
|
||||||
types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")),
|
|
||||||
types.NewMultiplier(types.Large, 24, sdk.OneDec()),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
|
||||||
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
|
||||||
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
|
||||||
},
|
|
||||||
0, // LTV counter
|
|
||||||
),
|
|
||||||
types.DefaultPreviousBlockTime,
|
|
||||||
types.DefaultDistributionTimes,
|
|
||||||
)
|
|
||||||
return app.GenesisState{
|
|
||||||
types.ModuleName: types.ModuleCdc.MustMarshalJSON(genState),
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func stakingGenesisState() app.GenesisState {
|
|
||||||
genState := staking.DefaultGenesisState()
|
|
||||||
genState.Params.BondDenom = "ukava"
|
|
||||||
return app.GenesisState{
|
|
||||||
staking.ModuleName: staking.ModuleCdc.MustMarshalJSON(genState),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// equalCoinsAuthGenState returns an auth genesis state with the same coins for each account
|
|
||||||
func equalCoinsAuthGenState(addresses []sdk.AccAddress, coins sdk.Coins) app.GenesisState {
|
|
||||||
coinsList := []sdk.Coins{}
|
|
||||||
for range addresses {
|
|
||||||
coinsList = append(coinsList, coins)
|
|
||||||
}
|
|
||||||
return app.NewAuthGenState(addresses, coinsList)
|
|
||||||
}
|
|
@ -282,20 +282,12 @@ func (suite *KeeperTestSuite) TestSendTimeLockedCoinsToAccount() {
|
|||||||
loanToValue := sdk.MustNewDecFromStr("0.6")
|
loanToValue := sdk.MustNewDecFromStr("0.6")
|
||||||
hardGS := types.NewGenesisState(types.NewParams(
|
hardGS := types.NewGenesisState(types.NewParams(
|
||||||
true,
|
true,
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Large, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
types.MoneyMarkets{
|
||||||
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
},
|
},
|
||||||
0, // LTV counter
|
0, // LTV counter
|
||||||
), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes)
|
), types.DefaultPreviousBlockTime)
|
||||||
tApp.InitializeFromGenesisStates(authGS, app.GenesisState{types.ModuleName: types.ModuleCdc.MustMarshalJSON(hardGS)})
|
tApp.InitializeFromGenesisStates(authGS, app.GenesisState{types.ModuleName: types.ModuleCdc.MustMarshalJSON(hardGS)})
|
||||||
if tc.args.accArgs.vestingAccountBefore {
|
if tc.args.accArgs.vestingAccountBefore {
|
||||||
ak := tApp.GetAccountKeeper()
|
ak := tApp.GetAccountKeeper()
|
||||||
|
@ -15,13 +15,15 @@ func (k Keeper) Withdraw(ctx sdk.Context, depositor sdk.AccAddress, coins sdk.Co
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
k.SyncBorrowInterest(ctx, depositor)
|
|
||||||
k.SyncSupplyInterest(ctx, depositor)
|
|
||||||
|
|
||||||
deposit, found := k.GetDeposit(ctx, depositor)
|
deposit, found := k.GetDeposit(ctx, depositor)
|
||||||
if !found {
|
if !found {
|
||||||
return sdkerrors.Wrapf(types.ErrDepositNotFound, "no deposit found for %s", depositor)
|
return sdkerrors.Wrapf(types.ErrDepositNotFound, "no deposit found for %s", depositor)
|
||||||
}
|
}
|
||||||
|
// Call incentive hook
|
||||||
|
k.BeforeDepositModified(ctx, deposit)
|
||||||
|
|
||||||
|
k.SyncBorrowInterest(ctx, depositor)
|
||||||
|
k.SyncSupplyInterest(ctx, depositor)
|
||||||
|
|
||||||
amount, err := k.CalculateWithdrawAmount(deposit.Amount, coins)
|
amount, err := k.CalculateWithdrawAmount(deposit.Amount, coins)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -47,19 +49,7 @@ func (k Keeper) Withdraw(ctx sdk.Context, depositor sdk.AccAddress, coins sdk.Co
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if deposit.Amount.IsEqual(amount) {
|
|
||||||
ctx.EventManager().EmitEvent(
|
|
||||||
sdk.NewEvent(
|
|
||||||
types.EventTypeDeleteHardDeposit,
|
|
||||||
sdk.NewAttribute(types.AttributeKeyDepositor, depositor.String()),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
k.DeleteDeposit(ctx, deposit)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
deposit.Amount = deposit.Amount.Sub(amount)
|
deposit.Amount = deposit.Amount.Sub(amount)
|
||||||
|
|
||||||
newLtv, err := k.CalculateLtv(ctx, deposit, borrow)
|
newLtv, err := k.CalculateLtv(ctx, deposit, borrow)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -69,6 +59,9 @@ func (k Keeper) Withdraw(ctx sdk.Context, depositor sdk.AccAddress, coins sdk.Co
|
|||||||
// Update total supplied amount
|
// Update total supplied amount
|
||||||
k.DecrementBorrowedCoins(ctx, amount)
|
k.DecrementBorrowedCoins(ctx, amount)
|
||||||
|
|
||||||
|
// Call incentive hook
|
||||||
|
k.AfterDepositModified(ctx, deposit)
|
||||||
|
|
||||||
ctx.EventManager().EmitEvent(
|
ctx.EventManager().EmitEvent(
|
||||||
sdk.NewEvent(
|
sdk.NewEvent(
|
||||||
types.EventTypeHardWithdrawal,
|
types.EventTypeHardWithdrawal,
|
||||||
@ -76,7 +69,6 @@ func (k Keeper) Withdraw(ctx sdk.Context, depositor sdk.AccAddress, coins sdk.Co
|
|||||||
sdk.NewAttribute(types.AttributeKeyDepositor, depositor.String()),
|
sdk.NewAttribute(types.AttributeKeyDepositor, depositor.String()),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,21 +125,13 @@ func (suite *KeeperTestSuite) TestWithdraw() {
|
|||||||
loanToValue := sdk.MustNewDecFromStr("0.6")
|
loanToValue := sdk.MustNewDecFromStr("0.6")
|
||||||
hardGS := types.NewGenesisState(types.NewParams(
|
hardGS := types.NewGenesisState(types.NewParams(
|
||||||
true,
|
true,
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
types.MoneyMarkets{
|
||||||
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("usdx", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("ukava", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
types.NewMoneyMarket("bnb", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "bnb:usd", sdk.NewInt(100000000), sdk.NewInt(BNB_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
types.NewMoneyMarket("bnb", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "bnb:usd", sdk.NewInt(100000000), sdk.NewInt(BNB_CF*1000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
},
|
},
|
||||||
0, // LTV counter
|
0, // LTV counter
|
||||||
), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes)
|
), types.DefaultPreviousBlockTime)
|
||||||
|
|
||||||
// Pricefeed module genesis state
|
// Pricefeed module genesis state
|
||||||
pricefeedGS := pricefeed.GenesisState{
|
pricefeedGS := pricefeed.GenesisState{
|
||||||
@ -273,15 +265,6 @@ func (suite *KeeperTestSuite) TestLtvWithdraw() {
|
|||||||
// Harvest module genesis state
|
// Harvest module genesis state
|
||||||
harvestGS := types.NewGenesisState(types.NewParams(
|
harvestGS := types.NewGenesisState(types.NewParams(
|
||||||
true,
|
true,
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "ukava", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.MoneyMarkets{
|
types.MoneyMarkets{
|
||||||
types.NewMoneyMarket("ukava",
|
types.NewMoneyMarket("ukava",
|
||||||
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.8")), // Borrow Limit
|
types.NewBorrowLimit(false, sdk.NewDec(100000000*KAVA_CF), sdk.MustNewDecFromStr("0.8")), // Borrow Limit
|
||||||
@ -301,7 +284,7 @@ func (suite *KeeperTestSuite) TestLtvWithdraw() {
|
|||||||
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
|
sdk.MustNewDecFromStr("0.05")), // Keeper Reward Percent
|
||||||
},
|
},
|
||||||
0, // LTV counter
|
0, // LTV counter
|
||||||
), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes)
|
), types.DefaultPreviousBlockTime)
|
||||||
|
|
||||||
// Pricefeed module genesis state
|
// Pricefeed module genesis state
|
||||||
pricefeedGS := pricefeed.GenesisState{
|
pricefeedGS := pricefeed.GenesisState{
|
||||||
|
@ -15,21 +15,16 @@ import (
|
|||||||
// DecodeStore unmarshals the KVPair's Value to the corresponding hard type
|
// DecodeStore unmarshals the KVPair's Value to the corresponding hard type
|
||||||
func DecodeStore(cdc *codec.Codec, kvA, kvB kv.Pair) string {
|
func DecodeStore(cdc *codec.Codec, kvA, kvB kv.Pair) string {
|
||||||
switch {
|
switch {
|
||||||
case bytes.Equal(kvA.Key[:1], types.PreviousBlockTimeKey), bytes.Equal(kvA.Key[:1], types.PreviousDelegationDistributionKey):
|
|
||||||
var timeA, timeB time.Time
|
|
||||||
cdc.MustUnmarshalBinaryBare(kvA.Value, &timeA)
|
|
||||||
cdc.MustUnmarshalBinaryBare(kvB.Value, &timeB)
|
|
||||||
return fmt.Sprintf("%s\n%s", timeA, timeB)
|
|
||||||
case bytes.Equal(kvA.Key[:1], types.DepositsKeyPrefix):
|
case bytes.Equal(kvA.Key[:1], types.DepositsKeyPrefix):
|
||||||
var depA, depB types.Deposit
|
var depA, depB types.Deposit
|
||||||
cdc.MustUnmarshalBinaryBare(kvA.Value, &depA)
|
cdc.MustUnmarshalBinaryBare(kvA.Value, &depA)
|
||||||
cdc.MustUnmarshalBinaryBare(kvB.Value, &depB)
|
cdc.MustUnmarshalBinaryBare(kvB.Value, &depB)
|
||||||
return fmt.Sprintf("%s\n%s", depA, depB)
|
return fmt.Sprintf("%s\n%s", depA, depB)
|
||||||
case bytes.Equal(kvA.Key[:1], types.ClaimsKeyPrefix):
|
case bytes.Equal(kvA.Key[:1], types.PreviousBlockTimeKey):
|
||||||
var claimA, claimB types.Claim
|
var timeA, timeB time.Time
|
||||||
cdc.MustUnmarshalBinaryBare(kvA.Value, &claimA)
|
cdc.MustUnmarshalBinaryBare(kvA.Value, &timeA)
|
||||||
cdc.MustUnmarshalBinaryBare(kvB.Value, &claimB)
|
cdc.MustUnmarshalBinaryBare(kvB.Value, &timeB)
|
||||||
return fmt.Sprintf("%s\n%s", claimA, claimB)
|
return fmt.Sprintf("%s\n%s", timeA, timeB)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("invalid %s key prefix %X", types.ModuleName, kvA.Key[:1]))
|
panic(fmt.Sprintf("invalid %s key prefix %X", types.ModuleName, kvA.Key[:1]))
|
||||||
}
|
}
|
||||||
|
@ -27,16 +27,11 @@ func TestDecodeDistributionStore(t *testing.T) {
|
|||||||
cdc := makeTestCodec()
|
cdc := makeTestCodec()
|
||||||
|
|
||||||
prevBlockTime := time.Now().UTC()
|
prevBlockTime := time.Now().UTC()
|
||||||
deposit := types.NewDeposit(sdk.AccAddress("test"),
|
deposit := types.NewDeposit(sdk.AccAddress("test"), sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(1))), types.SupplyInterestFactors{})
|
||||||
sdk.NewCoins(sdk.NewCoin("bnb", sdk.NewInt(1))),
|
|
||||||
types.SupplyInterestFactors{types.NewSupplyInterestFactor("bnb", sdk.OneDec())})
|
|
||||||
claim := types.NewClaim(sdk.AccAddress("test"), "bnb", sdk.NewCoin("hard", sdk.NewInt(100)), "stake")
|
|
||||||
|
|
||||||
kvPairs := kv.Pairs{
|
kvPairs := kv.Pairs{
|
||||||
kv.Pair{Key: []byte(types.PreviousBlockTimeKey), Value: cdc.MustMarshalBinaryBare(prevBlockTime)},
|
kv.Pair{Key: []byte(types.PreviousBlockTimeKey), Value: cdc.MustMarshalBinaryBare(prevBlockTime)},
|
||||||
kv.Pair{Key: []byte(types.PreviousDelegationDistributionKey), Value: cdc.MustMarshalBinaryBare(prevBlockTime)},
|
|
||||||
kv.Pair{Key: []byte(types.DepositsKeyPrefix), Value: cdc.MustMarshalBinaryBare(deposit)},
|
kv.Pair{Key: []byte(types.DepositsKeyPrefix), Value: cdc.MustMarshalBinaryBare(deposit)},
|
||||||
kv.Pair{Key: []byte(types.ClaimsKeyPrefix), Value: cdc.MustMarshalBinaryBare(claim)},
|
|
||||||
kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}},
|
kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,9 +40,7 @@ func TestDecodeDistributionStore(t *testing.T) {
|
|||||||
expectedLog string
|
expectedLog string
|
||||||
}{
|
}{
|
||||||
{"PreviousBlockTime", fmt.Sprintf("%s\n%s", prevBlockTime, prevBlockTime)},
|
{"PreviousBlockTime", fmt.Sprintf("%s\n%s", prevBlockTime, prevBlockTime)},
|
||||||
{"PreviousDistributionTime", fmt.Sprintf("%s\n%s", prevBlockTime, prevBlockTime)},
|
|
||||||
{"Deposit", fmt.Sprintf("%s\n%s", deposit, deposit)},
|
{"Deposit", fmt.Sprintf("%s\n%s", deposit, deposit)},
|
||||||
{"Claim", fmt.Sprintf("%s\n%s", claim, claim)},
|
|
||||||
{"other", ""},
|
{"other", ""},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Claim defines an amount of coins that the owner can claim
|
|
||||||
type Claim struct {
|
|
||||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
|
||||||
DepositDenom string `json:"deposit_denom" yaml:"deposit_denom"`
|
|
||||||
Amount sdk.Coin `json:"amount" yaml:"amount"`
|
|
||||||
Type ClaimType `json:"claim_type" yaml:"claim_type"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClaim returns a new claim
|
|
||||||
func NewClaim(owner sdk.AccAddress, denom string, amount sdk.Coin, claimType ClaimType) Claim {
|
|
||||||
return Claim{
|
|
||||||
Owner: owner,
|
|
||||||
DepositDenom: denom,
|
|
||||||
Amount: amount,
|
|
||||||
Type: claimType,
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,5 +20,4 @@ func RegisterCodec(cdc *codec.Codec) {
|
|||||||
cdc.RegisterConcrete(MsgBorrow{}, "hard/MsgBorrow", nil)
|
cdc.RegisterConcrete(MsgBorrow{}, "hard/MsgBorrow", nil)
|
||||||
cdc.RegisterConcrete(MsgLiquidate{}, "hard/MsgLiquidate", nil)
|
cdc.RegisterConcrete(MsgLiquidate{}, "hard/MsgLiquidate", nil)
|
||||||
cdc.RegisterConcrete(MsgRepay{}, "hard/MsgRepay", nil)
|
cdc.RegisterConcrete(MsgRepay{}, "hard/MsgRepay", nil)
|
||||||
cdc.RegisterConcrete(DistributionSchedule{}, "hard/DistributionSchedule", nil)
|
|
||||||
}
|
}
|
||||||
|
@ -45,3 +45,13 @@ type PricefeedKeeper interface {
|
|||||||
type AuctionKeeper interface {
|
type AuctionKeeper interface {
|
||||||
StartCollateralAuction(ctx sdk.Context, seller string, lot sdk.Coin, maxBid sdk.Coin, lotReturnAddrs []sdk.AccAddress, lotReturnWeights []sdk.Int, debt sdk.Coin) (uint64, error)
|
StartCollateralAuction(ctx sdk.Context, seller string, lot sdk.Coin, maxBid sdk.Coin, lotReturnAddrs []sdk.AccAddress, lotReturnWeights []sdk.Int, debt sdk.Coin) (uint64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HARDHooks event hooks for other keepers to run code in response to HARD modifications
|
||||||
|
type HARDHooks interface {
|
||||||
|
AfterDepositCreated(ctx sdk.Context, deposit Deposit)
|
||||||
|
BeforeDepositModified(ctx sdk.Context, deposit Deposit)
|
||||||
|
AfterDepositModified(ctx sdk.Context, deposit Deposit)
|
||||||
|
AfterBorrowCreated(ctx sdk.Context, borrow Borrow)
|
||||||
|
BeforeBorrowModified(ctx sdk.Context, borrow Borrow)
|
||||||
|
AfterBorrowModified(ctx sdk.Context, borrow Borrow)
|
||||||
|
}
|
||||||
|
@ -5,30 +5,25 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
|
|
||||||
tmtime "github.com/tendermint/tendermint/types/time"
|
tmtime "github.com/tendermint/tendermint/types/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GenesisState default values
|
// GenesisState default values
|
||||||
var (
|
var (
|
||||||
DefaultPreviousBlockTime = tmtime.Canonical(time.Unix(0, 0))
|
DefaultPreviousBlockTime = tmtime.Canonical(time.Unix(0, 0))
|
||||||
DefaultDistributionTimes = GenesisDistributionTimes{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GenesisState is the state that must be provided at genesis.
|
// GenesisState is the state that must be provided at genesis.
|
||||||
type GenesisState struct {
|
type GenesisState struct {
|
||||||
Params Params `json:"params" yaml:"params"`
|
Params Params `json:"params" yaml:"params"`
|
||||||
PreviousBlockTime time.Time `json:"previous_block_time" yaml:"previous_block_time"`
|
PreviousBlockTime time.Time `json:"previous_block_time" yaml:"previous_block_time"`
|
||||||
PreviousDistributionTimes GenesisDistributionTimes `json:"previous_distribution_times" yaml:"previous_distribution_times"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGenesisState returns a new genesis state
|
// NewGenesisState returns a new genesis state
|
||||||
func NewGenesisState(params Params, previousBlockTime time.Time, previousDistTimes GenesisDistributionTimes) GenesisState {
|
func NewGenesisState(params Params, previousBlockTime time.Time) GenesisState {
|
||||||
return GenesisState{
|
return GenesisState{
|
||||||
Params: params,
|
Params: params,
|
||||||
PreviousBlockTime: previousBlockTime,
|
PreviousBlockTime: previousBlockTime,
|
||||||
PreviousDistributionTimes: previousDistTimes,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +32,6 @@ func DefaultGenesisState() GenesisState {
|
|||||||
return GenesisState{
|
return GenesisState{
|
||||||
Params: DefaultParams(),
|
Params: DefaultParams(),
|
||||||
PreviousBlockTime: DefaultPreviousBlockTime,
|
PreviousBlockTime: DefaultPreviousBlockTime,
|
||||||
PreviousDistributionTimes: DefaultDistributionTimes,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,14 +45,6 @@ func (gs GenesisState) Validate() error {
|
|||||||
if gs.PreviousBlockTime.Equal(time.Time{}) {
|
if gs.PreviousBlockTime.Equal(time.Time{}) {
|
||||||
return fmt.Errorf("previous block time not set")
|
return fmt.Errorf("previous block time not set")
|
||||||
}
|
}
|
||||||
for _, gdt := range gs.PreviousDistributionTimes {
|
|
||||||
if gdt.PreviousDistributionTime.Equal(time.Time{}) {
|
|
||||||
return fmt.Errorf("previous distribution time not set for %s", gdt.Denom)
|
|
||||||
}
|
|
||||||
if err := sdk.ValidateDenom(gdt.Denom); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,12 +59,3 @@ func (gs GenesisState) Equal(gs2 GenesisState) bool {
|
|||||||
func (gs GenesisState) IsEmpty() bool {
|
func (gs GenesisState) IsEmpty() bool {
|
||||||
return gs.Equal(GenesisState{})
|
return gs.Equal(GenesisState{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenesisDistributionTime stores the previous distribution time and its corresponding denom
|
|
||||||
type GenesisDistributionTime struct {
|
|
||||||
Denom string `json:"denom" yaml:"denom"`
|
|
||||||
PreviousDistributionTime time.Time `json:"previous_distribution_time" yaml:"previous_distribution_time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenesisDistributionTimes slice of GenesisDistributionTime
|
|
||||||
type GenesisDistributionTimes []GenesisDistributionTime
|
|
||||||
|
@ -5,8 +5,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
"github.com/kava-labs/kava/x/hard/types"
|
"github.com/kava-labs/kava/x/hard/types"
|
||||||
@ -20,7 +18,6 @@ func (suite *GenesisTestSuite) TestGenesisValidation() {
|
|||||||
type args struct {
|
type args struct {
|
||||||
params types.Params
|
params types.Params
|
||||||
pbt time.Time
|
pbt time.Time
|
||||||
pdts types.GenesisDistributionTimes
|
|
||||||
}
|
}
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@ -33,7 +30,6 @@ func (suite *GenesisTestSuite) TestGenesisValidation() {
|
|||||||
args: args{
|
args: args{
|
||||||
params: types.DefaultParams(),
|
params: types.DefaultParams(),
|
||||||
pbt: types.DefaultPreviousBlockTime,
|
pbt: types.DefaultPreviousBlockTime,
|
||||||
pdts: types.DefaultDistributionTimes,
|
|
||||||
},
|
},
|
||||||
expectPass: true,
|
expectPass: true,
|
||||||
expectedErr: "",
|
expectedErr: "",
|
||||||
@ -41,23 +37,8 @@ func (suite *GenesisTestSuite) TestGenesisValidation() {
|
|||||||
{
|
{
|
||||||
name: "valid",
|
name: "valid",
|
||||||
args: args{
|
args: args{
|
||||||
params: types.NewParams(
|
params: types.NewParams(true, types.DefaultMoneyMarkets, types.DefaultCheckLtvIndexCount),
|
||||||
true,
|
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.OneDec()), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("1.5")), types.NewMultiplier(types.Medium, 24, sdk.MustNewDecFromStr("3"))}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.DefaultMoneyMarkets,
|
|
||||||
types.DefaultCheckLtvIndexCount,
|
|
||||||
),
|
|
||||||
pbt: time.Date(2020, 10, 8, 12, 0, 0, 0, time.UTC),
|
pbt: time.Date(2020, 10, 8, 12, 0, 0, 0, time.UTC),
|
||||||
pdts: types.GenesisDistributionTimes{
|
|
||||||
{PreviousDistributionTime: time.Date(2020, 10, 8, 12, 0, 0, 0, time.UTC), Denom: "bnb"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
expectPass: true,
|
expectPass: true,
|
||||||
expectedErr: "",
|
expectedErr: "",
|
||||||
@ -65,55 +46,16 @@ func (suite *GenesisTestSuite) TestGenesisValidation() {
|
|||||||
{
|
{
|
||||||
name: "invalid previous blocktime",
|
name: "invalid previous blocktime",
|
||||||
args: args{
|
args: args{
|
||||||
params: types.NewParams(
|
params: types.NewParams(true, types.DefaultMoneyMarkets, types.DefaultCheckLtvIndexCount),
|
||||||
true,
|
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.OneDec()), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("1.5")), types.NewMultiplier(types.Medium, 24, sdk.MustNewDecFromStr("3"))}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.DefaultMoneyMarkets,
|
|
||||||
types.DefaultCheckLtvIndexCount,
|
|
||||||
),
|
|
||||||
pbt: time.Time{},
|
pbt: time.Time{},
|
||||||
pdts: types.GenesisDistributionTimes{
|
|
||||||
{PreviousDistributionTime: time.Date(2020, 10, 8, 12, 0, 0, 0, time.UTC), Denom: "bnb"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
expectPass: false,
|
expectPass: false,
|
||||||
expectedErr: "previous block time not set",
|
expectedErr: "previous block time not set",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "invalid previous distribution time",
|
|
||||||
args: args{
|
|
||||||
params: types.NewParams(
|
|
||||||
true,
|
|
||||||
types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.OneDec()), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("1.5")), types.NewMultiplier(types.Medium, 24, sdk.MustNewDecFromStr("3"))}),
|
|
||||||
},
|
|
||||||
types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
types.DefaultMoneyMarkets,
|
|
||||||
types.DefaultCheckLtvIndexCount,
|
|
||||||
),
|
|
||||||
pbt: time.Date(2020, 10, 8, 12, 0, 0, 0, time.UTC),
|
|
||||||
pdts: types.GenesisDistributionTimes{
|
|
||||||
{PreviousDistributionTime: time.Time{}, Denom: "bnb"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectPass: false,
|
|
||||||
expectedErr: "previous distribution time not set",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
suite.Run(tc.name, func() {
|
suite.Run(tc.name, func() {
|
||||||
gs := types.NewGenesisState(tc.args.params, tc.args.pbt, tc.args.pdts)
|
gs := types.NewGenesisState(tc.args.params, tc.args.pbt)
|
||||||
err := gs.Validate()
|
err := gs.Validate()
|
||||||
if tc.expectPass {
|
if tc.expectPass {
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
53
x/hard/types/hooks.go
Normal file
53
x/hard/types/hooks.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
|
// MultiHARDHooks combine multiple HARD hooks, all hook functions are run in array sequence
|
||||||
|
type MultiHARDHooks []HARDHooks
|
||||||
|
|
||||||
|
// NewMultiHARDHooks returns a new MultiHARDHooks
|
||||||
|
func NewMultiHARDHooks(hooks ...HARDHooks) MultiHARDHooks {
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterDepositCreated runs after a deposit is created
|
||||||
|
func (h MultiHARDHooks) AfterDepositCreated(ctx sdk.Context, deposit Deposit) {
|
||||||
|
for i := range h {
|
||||||
|
h[i].AfterDepositCreated(ctx, deposit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeforeDepositModified runs before a deposit is modified
|
||||||
|
func (h MultiHARDHooks) BeforeDepositModified(ctx sdk.Context, deposit Deposit) {
|
||||||
|
for i := range h {
|
||||||
|
h[i].BeforeDepositModified(ctx, deposit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterDepositModified runs after a deposit is modified
|
||||||
|
func (h MultiHARDHooks) AfterDepositModified(ctx sdk.Context, deposit Deposit) {
|
||||||
|
for i := range h {
|
||||||
|
h[i].AfterDepositModified(ctx, deposit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterBorrowCreated runs after a borrow is created
|
||||||
|
func (h MultiHARDHooks) AfterBorrowCreated(ctx sdk.Context, borrow Borrow) {
|
||||||
|
for i := range h {
|
||||||
|
h[i].AfterBorrowCreated(ctx, borrow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeforeBorrowModified runs before a borrow is modified
|
||||||
|
func (h MultiHARDHooks) BeforeBorrowModified(ctx sdk.Context, borrow Borrow) {
|
||||||
|
for i := range h {
|
||||||
|
h[i].BeforeBorrowModified(ctx, borrow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterBorrowModified runs after a borrow is modified
|
||||||
|
func (h MultiHARDHooks) AfterBorrowModified(ctx sdk.Context, borrow Borrow) {
|
||||||
|
for i := range h {
|
||||||
|
h[i].AfterBorrowModified(ctx, borrow)
|
||||||
|
}
|
||||||
|
}
|
@ -35,9 +35,7 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
PreviousBlockTimeKey = []byte{0x01}
|
PreviousBlockTimeKey = []byte{0x01}
|
||||||
PreviousDelegationDistributionKey = []byte{0x02}
|
|
||||||
DepositsKeyPrefix = []byte{0x03}
|
DepositsKeyPrefix = []byte{0x03}
|
||||||
ClaimsKeyPrefix = []byte{0x04}
|
|
||||||
BorrowsKeyPrefix = []byte{0x05}
|
BorrowsKeyPrefix = []byte{0x05}
|
||||||
BorrowedCoinsPrefix = []byte{0x06}
|
BorrowedCoinsPrefix = []byte{0x06}
|
||||||
SuppliedCoinsPrefix = []byte{0x07}
|
SuppliedCoinsPrefix = []byte{0x07}
|
||||||
@ -55,16 +53,6 @@ func DepositTypeIteratorKey(denom string) []byte {
|
|||||||
return createKey([]byte(denom))
|
return createKey([]byte(denom))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClaimKey key of a specific deposit in the store
|
|
||||||
func ClaimKey(depositType ClaimType, denom string, owner sdk.AccAddress) []byte {
|
|
||||||
return createKey([]byte(depositType), sep, []byte(denom), sep, owner)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClaimTypeIteratorKey returns an interator prefix for interating over claims by deposit type and denom
|
|
||||||
func ClaimTypeIteratorKey(depositType ClaimType, denom string) []byte {
|
|
||||||
return createKey([]byte(depositType), sep, []byte(denom))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBorrowByLtvKey is used by the LTV index
|
// GetBorrowByLtvKey is used by the LTV index
|
||||||
func GetBorrowByLtvKey(ltv sdk.Dec, borrower sdk.AccAddress) []byte {
|
func GetBorrowByLtvKey(ltv sdk.Dec, borrower sdk.AccAddress) []byte {
|
||||||
return append(ltv.Bytes(), borrower...)
|
return append(ltv.Bytes(), borrower...)
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/params"
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
@ -14,14 +12,9 @@ import (
|
|||||||
// Parameter keys and default values
|
// Parameter keys and default values
|
||||||
var (
|
var (
|
||||||
KeyActive = []byte("Active")
|
KeyActive = []byte("Active")
|
||||||
KeyLPSchedules = []byte("LPSchedules")
|
|
||||||
KeyDelegatorSchedule = []byte("DelegatorSchedule")
|
|
||||||
KeyMoneyMarkets = []byte("MoneyMarkets")
|
KeyMoneyMarkets = []byte("MoneyMarkets")
|
||||||
KeyCheckLtvIndexCount = []byte("CheckLtvIndexCount")
|
KeyCheckLtvIndexCount = []byte("CheckLtvIndexCount")
|
||||||
DefaultActive = true
|
DefaultActive = true
|
||||||
DefaultGovSchedules = DistributionSchedules{}
|
|
||||||
DefaultLPSchedules = DistributionSchedules{}
|
|
||||||
DefaultDelegatorSchedules = DelegatorDistributionSchedules{}
|
|
||||||
DefaultMoneyMarkets = MoneyMarkets{}
|
DefaultMoneyMarkets = MoneyMarkets{}
|
||||||
DefaultCheckLtvIndexCount = 10
|
DefaultCheckLtvIndexCount = 10
|
||||||
GovDenom = cdptypes.DefaultGovDenom
|
GovDenom = cdptypes.DefaultGovDenom
|
||||||
@ -30,156 +23,10 @@ var (
|
|||||||
// Params governance parameters for hard module
|
// Params governance parameters for hard module
|
||||||
type Params struct {
|
type Params struct {
|
||||||
Active bool `json:"active" yaml:"active"`
|
Active bool `json:"active" yaml:"active"`
|
||||||
LiquidityProviderSchedules DistributionSchedules `json:"liquidity_provider_schedules" yaml:"liquidity_provider_schedules"`
|
|
||||||
DelegatorDistributionSchedules DelegatorDistributionSchedules `json:"delegator_distribution_schedules" yaml:"delegator_distribution_schedules"`
|
|
||||||
MoneyMarkets MoneyMarkets `json:"money_markets" yaml:"money_markets"`
|
MoneyMarkets MoneyMarkets `json:"money_markets" yaml:"money_markets"`
|
||||||
CheckLtvIndexCount int `json:"check_ltv_index_count" yaml:"check_ltv_index_count"`
|
CheckLtvIndexCount int `json:"check_ltv_index_count" yaml:"check_ltv_index_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DistributionSchedule distribution schedule for liquidity providers
|
|
||||||
type DistributionSchedule struct {
|
|
||||||
Active bool `json:"active" yaml:"active"`
|
|
||||||
DepositDenom string `json:"deposit_denom" yaml:"deposit_denom"`
|
|
||||||
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"`
|
|
||||||
ClaimEnd time.Time `json:"claim_end" yaml:"claim_end"`
|
|
||||||
ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDistributionSchedule returns a new DistributionSchedule
|
|
||||||
func NewDistributionSchedule(active bool, denom string, start, end time.Time, reward sdk.Coin, claimEnd time.Time, multipliers Multipliers) DistributionSchedule {
|
|
||||||
return DistributionSchedule{
|
|
||||||
Active: active,
|
|
||||||
DepositDenom: denom,
|
|
||||||
Start: start,
|
|
||||||
End: end,
|
|
||||||
RewardsPerSecond: reward,
|
|
||||||
ClaimEnd: claimEnd,
|
|
||||||
ClaimMultipliers: multipliers,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String implements fmt.Stringer
|
|
||||||
func (ds DistributionSchedule) String() string {
|
|
||||||
return fmt.Sprintf(`Liquidity Provider Distribution Schedule:
|
|
||||||
Deposit Denom: %s,
|
|
||||||
Start: %s,
|
|
||||||
End: %s,
|
|
||||||
Rewards Per Second: %s,
|
|
||||||
Claim End: %s,
|
|
||||||
Active: %t
|
|
||||||
`, ds.DepositDenom, ds.Start, ds.End, ds.RewardsPerSecond, ds.ClaimEnd, ds.Active)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate performs a basic check of a distribution schedule.
|
|
||||||
func (ds DistributionSchedule) Validate() error {
|
|
||||||
if !ds.RewardsPerSecond.IsValid() {
|
|
||||||
return fmt.Errorf("invalid reward coins %s for %s", ds.RewardsPerSecond, ds.DepositDenom)
|
|
||||||
}
|
|
||||||
if !ds.RewardsPerSecond.IsPositive() {
|
|
||||||
return fmt.Errorf("reward amount must be positive, is %s for %s", ds.RewardsPerSecond, ds.DepositDenom)
|
|
||||||
}
|
|
||||||
if ds.RewardsPerSecond.Denom != "hard" {
|
|
||||||
return fmt.Errorf("reward denom should be hard, is %s", ds.RewardsPerSecond.Denom)
|
|
||||||
}
|
|
||||||
if ds.Start.IsZero() {
|
|
||||||
return errors.New("reward period start time cannot be 0")
|
|
||||||
}
|
|
||||||
if ds.End.IsZero() {
|
|
||||||
return errors.New("reward period end time cannot be 0")
|
|
||||||
}
|
|
||||||
if ds.Start.After(ds.End) {
|
|
||||||
return fmt.Errorf("end period time %s cannot be before start time %s", ds.End, ds.Start)
|
|
||||||
}
|
|
||||||
if ds.ClaimEnd.Before(ds.End) {
|
|
||||||
return fmt.Errorf("claim end time %s cannot be before end time %s", ds.ClaimEnd, ds.End)
|
|
||||||
}
|
|
||||||
for _, multiplier := range ds.ClaimMultipliers {
|
|
||||||
if err := multiplier.Validate(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DistributionSchedules slice of DistributionSchedule
|
|
||||||
type DistributionSchedules []DistributionSchedule
|
|
||||||
|
|
||||||
// Validate checks if all the LiquidityProviderSchedules are valid and there are no duplicated
|
|
||||||
// entries.
|
|
||||||
func (dss DistributionSchedules) Validate() error {
|
|
||||||
seenPeriods := make(map[string]bool)
|
|
||||||
for _, ds := range dss {
|
|
||||||
if seenPeriods[ds.DepositDenom] {
|
|
||||||
return fmt.Errorf("duplicated distribution provider schedule with deposit denom %s", ds.DepositDenom)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ds.Validate(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
seenPeriods[ds.DepositDenom] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String implements fmt.Stringer
|
|
||||||
func (dss DistributionSchedules) String() string {
|
|
||||||
out := "Distribution Schedules\n"
|
|
||||||
for _, ds := range dss {
|
|
||||||
out += fmt.Sprintf("%s\n", ds)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DelegatorDistributionSchedule distribution schedule for delegators
|
|
||||||
type DelegatorDistributionSchedule struct {
|
|
||||||
DistributionSchedule DistributionSchedule `json:"distribution_schedule" yaml:"distribution_schedule"`
|
|
||||||
|
|
||||||
DistributionFrequency time.Duration `json:"distribution_frequency" yaml:"distribution_frequency"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDelegatorDistributionSchedule returns a new DelegatorDistributionSchedule
|
|
||||||
func NewDelegatorDistributionSchedule(ds DistributionSchedule, frequency time.Duration) DelegatorDistributionSchedule {
|
|
||||||
return DelegatorDistributionSchedule{
|
|
||||||
DistributionSchedule: ds,
|
|
||||||
DistributionFrequency: frequency,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate performs a basic check of a reward fields.
|
|
||||||
func (dds DelegatorDistributionSchedule) Validate() error {
|
|
||||||
if err := dds.DistributionSchedule.Validate(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if dds.DistributionFrequency <= 0 {
|
|
||||||
return fmt.Errorf("distribution frequency should be positive, got %d", dds.DistributionFrequency)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DelegatorDistributionSchedules slice of DelegatorDistributionSchedule
|
|
||||||
type DelegatorDistributionSchedules []DelegatorDistributionSchedule
|
|
||||||
|
|
||||||
// Validate checks if all the LiquidityProviderSchedules are valid and there are no duplicated
|
|
||||||
// entries.
|
|
||||||
func (dds DelegatorDistributionSchedules) Validate() error {
|
|
||||||
seenPeriods := make(map[string]bool)
|
|
||||||
for _, ds := range dds {
|
|
||||||
if seenPeriods[ds.DistributionSchedule.DepositDenom] {
|
|
||||||
return fmt.Errorf("duplicated liquidity provider schedule with deposit denom %s", ds.DistributionSchedule.DepositDenom)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ds.Validate(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
seenPeriods[ds.DistributionSchedule.DepositDenom] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multiplier amount the claim rewards get increased by, along with how long the claim rewards are locked
|
// Multiplier amount the claim rewards get increased by, along with how long the claim rewards are locked
|
||||||
type Multiplier struct {
|
type Multiplier struct {
|
||||||
Name MultiplierName `json:"name" yaml:"name"`
|
Name MultiplierName `json:"name" yaml:"name"`
|
||||||
@ -211,16 +58,6 @@ func (m Multiplier) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMultiplier returns the named multiplier from the input distribution schedule
|
|
||||||
func (ds DistributionSchedule) GetMultiplier(name MultiplierName) (Multiplier, bool) {
|
|
||||||
for _, multiplier := range ds.ClaimMultipliers {
|
|
||||||
if multiplier.Name == name {
|
|
||||||
return multiplier, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Multiplier{}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multipliers slice of Multiplier
|
// Multipliers slice of Multiplier
|
||||||
type Multipliers []Multiplier
|
type Multipliers []Multiplier
|
||||||
|
|
||||||
@ -426,12 +263,9 @@ func (irm InterestRateModel) Equal(irmCompareTo InterestRateModel) bool {
|
|||||||
type InterestRateModels []InterestRateModel
|
type InterestRateModels []InterestRateModel
|
||||||
|
|
||||||
// NewParams returns a new params object
|
// NewParams returns a new params object
|
||||||
func NewParams(active bool, lps DistributionSchedules, dds DelegatorDistributionSchedules,
|
func NewParams(active bool, moneyMarkets MoneyMarkets, checkLtvIndexCount int) Params {
|
||||||
moneyMarkets MoneyMarkets, checkLtvIndexCount int) Params {
|
|
||||||
return Params{
|
return Params{
|
||||||
Active: active,
|
Active: active,
|
||||||
LiquidityProviderSchedules: lps,
|
|
||||||
DelegatorDistributionSchedules: dds,
|
|
||||||
MoneyMarkets: moneyMarkets,
|
MoneyMarkets: moneyMarkets,
|
||||||
CheckLtvIndexCount: checkLtvIndexCount,
|
CheckLtvIndexCount: checkLtvIndexCount,
|
||||||
}
|
}
|
||||||
@ -439,20 +273,16 @@ func NewParams(active bool, lps DistributionSchedules, dds DelegatorDistribution
|
|||||||
|
|
||||||
// DefaultParams returns default params for hard module
|
// DefaultParams returns default params for hard module
|
||||||
func DefaultParams() Params {
|
func DefaultParams() Params {
|
||||||
return NewParams(DefaultActive, DefaultLPSchedules, DefaultDelegatorSchedules,
|
return NewParams(DefaultActive, DefaultMoneyMarkets, DefaultCheckLtvIndexCount)
|
||||||
DefaultMoneyMarkets, DefaultCheckLtvIndexCount)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements fmt.Stringer
|
// String implements fmt.Stringer
|
||||||
func (p Params) String() string {
|
func (p Params) String() string {
|
||||||
return fmt.Sprintf(`Params:
|
return fmt.Sprintf(`Params:
|
||||||
Active: %t
|
Active: %t
|
||||||
Liquidity Provider Distribution Schedules %s
|
|
||||||
Delegator Distribution Schedule %s
|
|
||||||
Money Markets %v
|
Money Markets %v
|
||||||
Check LTV Index Count: %v`,
|
Check LTV Index Count: %v`,
|
||||||
p.Active, p.LiquidityProviderSchedules, p.DelegatorDistributionSchedules,
|
p.Active, p.MoneyMarkets, p.CheckLtvIndexCount)
|
||||||
p.MoneyMarkets, p.CheckLtvIndexCount)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParamKeyTable Key declaration for parameters
|
// ParamKeyTable Key declaration for parameters
|
||||||
@ -464,8 +294,6 @@ func ParamKeyTable() params.KeyTable {
|
|||||||
func (p *Params) ParamSetPairs() params.ParamSetPairs {
|
func (p *Params) ParamSetPairs() params.ParamSetPairs {
|
||||||
return params.ParamSetPairs{
|
return params.ParamSetPairs{
|
||||||
params.NewParamSetPair(KeyActive, &p.Active, validateActiveParam),
|
params.NewParamSetPair(KeyActive, &p.Active, validateActiveParam),
|
||||||
params.NewParamSetPair(KeyLPSchedules, &p.LiquidityProviderSchedules, validateLPParams),
|
|
||||||
params.NewParamSetPair(KeyDelegatorSchedule, &p.DelegatorDistributionSchedules, validateDelegatorParams),
|
|
||||||
params.NewParamSetPair(KeyMoneyMarkets, &p.MoneyMarkets, validateMoneyMarketParams),
|
params.NewParamSetPair(KeyMoneyMarkets, &p.MoneyMarkets, validateMoneyMarketParams),
|
||||||
params.NewParamSetPair(KeyCheckLtvIndexCount, &p.CheckLtvIndexCount, validateCheckLtvIndexCount),
|
params.NewParamSetPair(KeyCheckLtvIndexCount, &p.CheckLtvIndexCount, validateCheckLtvIndexCount),
|
||||||
}
|
}
|
||||||
@ -477,14 +305,6 @@ func (p Params) Validate() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateDelegatorParams(p.DelegatorDistributionSchedules); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := validateLPParams(p.LiquidityProviderSchedules); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := validateMoneyMarketParams(p.MoneyMarkets); err != nil {
|
if err := validateMoneyMarketParams(p.MoneyMarkets); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -501,31 +321,6 @@ func validateActiveParam(i interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateLPParams(i interface{}) error {
|
|
||||||
dss, ok := i.(DistributionSchedules)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("invalid parameter type: %T", i)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ds := range dss {
|
|
||||||
err := ds.Validate()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateDelegatorParams(i interface{}) error {
|
|
||||||
dds, ok := i.(DelegatorDistributionSchedules)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("invalid parameter type: %T", i)
|
|
||||||
}
|
|
||||||
|
|
||||||
return dds.Validate()
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateMoneyMarketParams(i interface{}) error {
|
func validateMoneyMarketParams(i interface{}) error {
|
||||||
mm, ok := i.(MoneyMarkets)
|
mm, ok := i.(MoneyMarkets)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -3,12 +3,9 @@ package types_test
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
|
|
||||||
"github.com/kava-labs/kava/x/hard/types"
|
"github.com/kava-labs/kava/x/hard/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,9 +15,6 @@ type ParamTestSuite struct {
|
|||||||
|
|
||||||
func (suite *ParamTestSuite) TestParamValidation() {
|
func (suite *ParamTestSuite) TestParamValidation() {
|
||||||
type args struct {
|
type args struct {
|
||||||
lps types.DistributionSchedules
|
|
||||||
gds types.DistributionSchedules
|
|
||||||
dds types.DelegatorDistributionSchedules
|
|
||||||
mms types.MoneyMarkets
|
mms types.MoneyMarkets
|
||||||
ltvCounter int
|
ltvCounter int
|
||||||
active bool
|
active bool
|
||||||
@ -34,8 +28,6 @@ func (suite *ParamTestSuite) TestParamValidation() {
|
|||||||
{
|
{
|
||||||
name: "default",
|
name: "default",
|
||||||
args: args{
|
args: args{
|
||||||
lps: types.DefaultLPSchedules,
|
|
||||||
dds: types.DefaultDelegatorSchedules,
|
|
||||||
active: types.DefaultActive,
|
active: types.DefaultActive,
|
||||||
},
|
},
|
||||||
expectPass: true,
|
expectPass: true,
|
||||||
@ -44,14 +36,6 @@ func (suite *ParamTestSuite) TestParamValidation() {
|
|||||||
{
|
{
|
||||||
name: "valid",
|
name: "valid",
|
||||||
args: args{
|
args: args{
|
||||||
lps: types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
dds: types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
mms: types.DefaultMoneyMarkets,
|
mms: types.DefaultMoneyMarkets,
|
||||||
ltvCounter: 10,
|
ltvCounter: 10,
|
||||||
active: true,
|
active: true,
|
||||||
@ -59,28 +43,10 @@ func (suite *ParamTestSuite) TestParamValidation() {
|
|||||||
expectPass: true,
|
expectPass: true,
|
||||||
expectedErr: "",
|
expectedErr: "",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "invalid rewards",
|
|
||||||
args: args{
|
|
||||||
lps: types.DistributionSchedules{
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("busd", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
},
|
|
||||||
dds: types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule(
|
|
||||||
types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}),
|
|
||||||
time.Hour*24,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
mms: types.DefaultMoneyMarkets,
|
|
||||||
ltvCounter: 10,
|
|
||||||
active: true,
|
|
||||||
},
|
|
||||||
expectPass: false,
|
|
||||||
expectedErr: "reward denom should be hard",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
suite.Run(tc.name, func() {
|
suite.Run(tc.name, func() {
|
||||||
params := types.NewParams(tc.args.active, tc.args.lps, tc.args.dds, tc.args.mms, tc.args.ltvCounter)
|
params := types.NewParams(tc.args.active, tc.args.mms, tc.args.ltvCounter)
|
||||||
err := params.Validate()
|
err := params.Validate()
|
||||||
if tc.expectPass {
|
if tc.expectPass {
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
@ -8,8 +8,21 @@ import (
|
|||||||
|
|
||||||
// BeginBlocker runs at the start of every block
|
// BeginBlocker runs at the start of every block
|
||||||
func BeginBlocker(ctx sdk.Context, k keeper.Keeper) {
|
func BeginBlocker(ctx sdk.Context, k keeper.Keeper) {
|
||||||
for _, rp := range k.GetParams(ctx).RewardPeriods {
|
params := k.GetParams(ctx)
|
||||||
err := k.AccumulateRewards(ctx, rp)
|
for _, rp := range params.USDXMintingRewardPeriods {
|
||||||
|
err := k.AccumulateUSDXMintingRewards(ctx, rp)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, rp := range params.HardSupplyRewardPeriods {
|
||||||
|
err := k.AccumulateHardSupplyRewards(ctx, rp)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, rp := range params.HardBorrowRewardPeriods {
|
||||||
|
err := k.AccumulateHardBorrowRewards(ctx, rp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,8 @@ var (
|
|||||||
RegisterCodec = types.RegisterCodec
|
RegisterCodec = types.RegisterCodec
|
||||||
|
|
||||||
// variable aliases
|
// variable aliases
|
||||||
BlockTimeKey = types.BlockTimeKey
|
PreviousUSDXMintingRewardAccrualTimeKeyPrefix = types.PreviousUSDXMintingRewardAccrualTimeKeyPrefix
|
||||||
ClaimKeyPrefix = types.ClaimKeyPrefix
|
USDXMintingClaimKeyPrefix = types.USDXMintingClaimKeyPrefix
|
||||||
DefaultActive = types.DefaultActive
|
DefaultActive = types.DefaultActive
|
||||||
DefaultClaimEnd = types.DefaultClaimEnd
|
DefaultClaimEnd = types.DefaultClaimEnd
|
||||||
DefaultClaims = types.DefaultClaims
|
DefaultClaims = types.DefaultClaims
|
||||||
@ -74,13 +74,12 @@ var (
|
|||||||
ErrZeroClaim = types.ErrZeroClaim
|
ErrZeroClaim = types.ErrZeroClaim
|
||||||
GovDenom = types.GovDenom
|
GovDenom = types.GovDenom
|
||||||
IncentiveMacc = types.IncentiveMacc
|
IncentiveMacc = types.IncentiveMacc
|
||||||
KeyActive = types.KeyActive
|
|
||||||
KeyClaimEnd = types.KeyClaimEnd
|
KeyClaimEnd = types.KeyClaimEnd
|
||||||
KeyMultipliers = types.KeyMultipliers
|
KeyMultipliers = types.KeyMultipliers
|
||||||
KeyRewards = types.KeyRewards
|
KeyUSDXMintingRewardPeriods = types.KeyUSDXMintingRewardPeriods
|
||||||
ModuleCdc = types.ModuleCdc
|
ModuleCdc = types.ModuleCdc
|
||||||
PrincipalDenom = types.PrincipalDenom
|
PrincipalDenom = types.PrincipalDenom
|
||||||
RewardFactorKey = types.RewardFactorKey
|
USDXMintingRewardFactorKeyPrefix = types.USDXMintingRewardFactorKeyPrefix
|
||||||
USDXMintingRewardDenom = types.USDXMintingRewardDenom
|
USDXMintingRewardDenom = types.USDXMintingRewardDenom
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -89,6 +88,7 @@ type (
|
|||||||
Keeper = keeper.Keeper
|
Keeper = keeper.Keeper
|
||||||
AccountKeeper = types.AccountKeeper
|
AccountKeeper = types.AccountKeeper
|
||||||
CDPHooks = types.CDPHooks
|
CDPHooks = types.CDPHooks
|
||||||
|
HARDHooks = types.HARDHooks
|
||||||
CdpKeeper = types.CdpKeeper
|
CdpKeeper = types.CdpKeeper
|
||||||
GenesisAccumulationTime = types.GenesisAccumulationTime
|
GenesisAccumulationTime = types.GenesisAccumulationTime
|
||||||
GenesisAccumulationTimes = types.GenesisAccumulationTimes
|
GenesisAccumulationTimes = types.GenesisAccumulationTimes
|
||||||
|
@ -22,7 +22,7 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, supplyKeeper types.SupplyKeep
|
|||||||
panic(fmt.Sprintf("failed to validate %s genesis state: %s", types.ModuleName, err))
|
panic(fmt.Sprintf("failed to validate %s genesis state: %s", types.ModuleName, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rp := range gs.Params.RewardPeriods {
|
for _, rp := range gs.Params.USDXMintingRewardPeriods {
|
||||||
_, found := cdpKeeper.GetCollateral(ctx, rp.CollateralType)
|
_, found := cdpKeeper.GetCollateral(ctx, rp.CollateralType)
|
||||||
if !found {
|
if !found {
|
||||||
panic(fmt.Sprintf("usdx minting collateral type %s not found in cdp collateral types", rp.CollateralType))
|
panic(fmt.Sprintf("usdx minting collateral type %s not found in cdp collateral types", rp.CollateralType))
|
||||||
@ -31,13 +31,15 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, supplyKeeper types.SupplyKeep
|
|||||||
|
|
||||||
k.SetParams(ctx, gs.Params)
|
k.SetParams(ctx, gs.Params)
|
||||||
|
|
||||||
|
// TODO: previous hard module accrual times/indexes should be set here
|
||||||
|
|
||||||
for _, gat := range gs.PreviousAccumulationTimes {
|
for _, gat := range gs.PreviousAccumulationTimes {
|
||||||
k.SetPreviousAccrualTime(ctx, gat.CollateralType, gat.PreviousAccumulationTime)
|
k.SetPreviousUSDXMintingAccrualTime(ctx, gat.CollateralType, gat.PreviousAccumulationTime)
|
||||||
k.SetRewardFactor(ctx, gat.CollateralType, gat.RewardFactor)
|
k.SetUSDXMintingRewardFactor(ctx, gat.CollateralType, gat.RewardFactor)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, claim := range gs.USDXMintingClaims {
|
for _, claim := range gs.USDXMintingClaims {
|
||||||
k.SetClaim(ctx, claim)
|
k.SetUSDXMintingClaim(ctx, claim)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -46,16 +48,16 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, supplyKeeper types.SupplyKeep
|
|||||||
func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState {
|
func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState {
|
||||||
params := k.GetParams(ctx)
|
params := k.GetParams(ctx)
|
||||||
|
|
||||||
claims := k.GetAllClaims(ctx)
|
claims := k.GetAllUSDXMintingClaims(ctx)
|
||||||
|
|
||||||
var gats GenesisAccumulationTimes
|
var gats GenesisAccumulationTimes
|
||||||
|
|
||||||
for _, rp := range params.RewardPeriods {
|
for _, rp := range params.USDXMintingRewardPeriods {
|
||||||
pat, found := k.GetPreviousAccrualTime(ctx, rp.CollateralType)
|
pat, found := k.GetPreviousUSDXMintingAccrualTime(ctx, rp.CollateralType)
|
||||||
if !found {
|
if !found {
|
||||||
pat = ctx.BlockTime()
|
pat = ctx.BlockTime()
|
||||||
}
|
}
|
||||||
factor, found := k.GetRewardFactor(ctx, rp.CollateralType)
|
factor, found := k.GetUSDXMintingRewardFactor(ctx, rp.CollateralType)
|
||||||
if !found {
|
if !found {
|
||||||
factor = sdk.ZeroDec()
|
factor = sdk.ZeroDec()
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,9 @@ func (suite *HandlerTestSuite) SetupTest() {
|
|||||||
authGS := app.NewAuthGenState(addrs, coins)
|
authGS := app.NewAuthGenState(addrs, coins)
|
||||||
incentiveGS := incentive.NewGenesisState(
|
incentiveGS := incentive.NewGenesisState(
|
||||||
incentive.NewParams(
|
incentive.NewParams(
|
||||||
|
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.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.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.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.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.Multipliers{incentive.NewMultiplier(incentive.MultiplierName("small"), 1, d("0.25")), incentive.NewMultiplier(incentive.MultiplierName("large"), 12, d("1.0"))},
|
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),
|
time.Date(2025, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
@ -66,7 +69,7 @@ func (suite *HandlerTestSuite) addClaim() {
|
|||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
c1 := incentive.NewUSDXMintingClaim(suite.addrs[0], c("ukava", 1000000), types.RewardIndexes{types.NewRewardIndex("bnb-s", sdk.ZeroDec())})
|
c1 := incentive.NewUSDXMintingClaim(suite.addrs[0], c("ukava", 1000000), types.RewardIndexes{types.NewRewardIndex("bnb-s", sdk.ZeroDec())})
|
||||||
suite.NotPanics(func() {
|
suite.NotPanics(func() {
|
||||||
suite.keeper.SetClaim(suite.ctx, c1)
|
suite.keeper.SetUSDXMintingClaim(suite.ctx, c1)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/kava-labs/kava/app"
|
"github.com/kava-labs/kava/app"
|
||||||
"github.com/kava-labs/kava/x/cdp"
|
"github.com/kava-labs/kava/x/cdp"
|
||||||
"github.com/kava-labs/kava/x/incentive"
|
"github.com/kava-labs/kava/x/incentive"
|
||||||
|
"github.com/kava-labs/kava/x/incentive/types"
|
||||||
"github.com/kava-labs/kava/x/pricefeed"
|
"github.com/kava-labs/kava/x/pricefeed"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -155,6 +156,9 @@ func NewIncentiveGenState(previousAccumTime, endTime time.Time, rewardPeriods ..
|
|||||||
genesis := incentive.NewGenesisState(
|
genesis := incentive.NewGenesisState(
|
||||||
incentive.NewParams(
|
incentive.NewParams(
|
||||||
rewardPeriods,
|
rewardPeriods,
|
||||||
|
types.RewardPeriods{},
|
||||||
|
types.RewardPeriods{},
|
||||||
|
types.RewardPeriods{},
|
||||||
incentive.Multipliers{
|
incentive.Multipliers{
|
||||||
incentive.NewMultiplier(incentive.Small, 1, d("0.25")),
|
incentive.NewMultiplier(incentive.Small, 1, d("0.25")),
|
||||||
incentive.NewMultiplier(incentive.Large, 12, d("1.0")),
|
incentive.NewMultiplier(incentive.Large, 12, d("1.0")),
|
||||||
|
@ -3,6 +3,7 @@ package keeper
|
|||||||
import (
|
import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
||||||
|
hardtypes "github.com/kava-labs/kava/x/hard/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Hooks wrapper struct for hooks
|
// Hooks wrapper struct for hooks
|
||||||
@ -11,18 +12,49 @@ type Hooks struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var _ cdptypes.CDPHooks = Hooks{}
|
var _ cdptypes.CDPHooks = Hooks{}
|
||||||
|
var _ hardtypes.HARDHooks = Hooks{}
|
||||||
|
|
||||||
// Hooks create new incentive hooks
|
// Hooks create new incentive hooks
|
||||||
func (k Keeper) Hooks() Hooks { return Hooks{k} }
|
func (k Keeper) Hooks() Hooks { return Hooks{k} }
|
||||||
|
|
||||||
// AfterCDPCreated function that runs after a cdp is created
|
// AfterCDPCreated function that runs after a cdp is created
|
||||||
func (h Hooks) AfterCDPCreated(ctx sdk.Context, cdp cdptypes.CDP) {
|
func (h Hooks) AfterCDPCreated(ctx sdk.Context, cdp cdptypes.CDP) {
|
||||||
h.k.InitializeClaim(ctx, cdp)
|
h.k.InitializeUSDXMintingClaim(ctx, cdp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeforeCDPModified function that runs before a cdp is modified
|
// BeforeCDPModified function that runs before a cdp is modified
|
||||||
// note that this is called immediately after interest is synchronized, and so could potentially
|
// note that this is called immediately after interest is synchronized, and so could potentially
|
||||||
// be called AfterCDPInterestUpdated or something like that, if we we're to expand the scope of cdp hooks
|
// be called AfterCDPInterestUpdated or something like that, if we we're to expand the scope of cdp hooks
|
||||||
func (h Hooks) BeforeCDPModified(ctx sdk.Context, cdp cdptypes.CDP) {
|
func (h Hooks) BeforeCDPModified(ctx sdk.Context, cdp cdptypes.CDP) {
|
||||||
h.k.SynchronizeReward(ctx, cdp)
|
h.k.SynchronizeUSDXMintingReward(ctx, cdp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterDepositCreated function that runs after a deposit is created
|
||||||
|
func (h Hooks) AfterDepositCreated(ctx sdk.Context, deposit hardtypes.Deposit) {
|
||||||
|
h.k.InitializeHardSupplyReward(ctx, deposit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeforeDepositModified function that runs before a deposit is modified
|
||||||
|
func (h Hooks) BeforeDepositModified(ctx sdk.Context, deposit hardtypes.Deposit) {
|
||||||
|
h.k.SynchronizeHardSupplyReward(ctx, deposit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterDepositModified function that runs after a deposit is modified
|
||||||
|
func (h Hooks) AfterDepositModified(ctx sdk.Context, deposit hardtypes.Deposit) {
|
||||||
|
h.k.UpdateHardSupplyIndexDenoms(ctx, deposit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterBorrowCreated function that runs after a borrow is created
|
||||||
|
func (h Hooks) AfterBorrowCreated(ctx sdk.Context, borrow hardtypes.Borrow) {
|
||||||
|
h.k.InitializeHardBorrowReward(ctx, borrow)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeforeBorrowModified function that runs before a borrow is modified
|
||||||
|
func (h Hooks) BeforeBorrowModified(ctx sdk.Context, borrow hardtypes.Borrow) {
|
||||||
|
h.k.SynchronizeHardBorrowReward(ctx, borrow)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterBorrowModified function that runs after a borrow is modified
|
||||||
|
func (h Hooks) AfterBorrowModified(ctx sdk.Context, borrow hardtypes.Borrow) {
|
||||||
|
h.k.UpdateHardBorrowIndexDenoms(ctx, borrow)
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/kava-labs/kava/app"
|
"github.com/kava-labs/kava/app"
|
||||||
"github.com/kava-labs/kava/x/cdp"
|
"github.com/kava-labs/kava/x/cdp"
|
||||||
"github.com/kava-labs/kava/x/incentive"
|
"github.com/kava-labs/kava/x/hard"
|
||||||
"github.com/kava-labs/kava/x/pricefeed"
|
"github.com/kava-labs/kava/x/pricefeed"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -104,6 +104,7 @@ func NewPricefeedGenStateMulti() app.GenesisState {
|
|||||||
pfGenesis := pricefeed.GenesisState{
|
pfGenesis := pricefeed.GenesisState{
|
||||||
Params: pricefeed.Params{
|
Params: pricefeed.Params{
|
||||||
Markets: []pricefeed.Market{
|
Markets: []pricefeed.Market{
|
||||||
|
{MarketID: "kava:usd", BaseAsset: "kava", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true},
|
||||||
{MarketID: "btc:usd", BaseAsset: "btc", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true},
|
{MarketID: "btc:usd", BaseAsset: "btc", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true},
|
||||||
{MarketID: "xrp:usd", BaseAsset: "xrp", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true},
|
{MarketID: "xrp:usd", BaseAsset: "xrp", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true},
|
||||||
{MarketID: "bnb:usd", BaseAsset: "bnb", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true},
|
{MarketID: "bnb:usd", BaseAsset: "bnb", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true},
|
||||||
@ -111,6 +112,12 @@ func NewPricefeedGenStateMulti() app.GenesisState {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
PostedPrices: []pricefeed.PostedPrice{
|
PostedPrices: []pricefeed.PostedPrice{
|
||||||
|
{
|
||||||
|
MarketID: "kava:usd",
|
||||||
|
OracleAddress: sdk.AccAddress{},
|
||||||
|
Price: sdk.MustNewDecFromStr("2.00"),
|
||||||
|
Expiry: time.Now().Add(1 * time.Hour),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
MarketID: "btc:usd",
|
MarketID: "btc:usd",
|
||||||
OracleAddress: sdk.AccAddress{},
|
OracleAddress: sdk.AccAddress{},
|
||||||
@ -140,73 +147,26 @@ func NewPricefeedGenStateMulti() app.GenesisState {
|
|||||||
return app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pfGenesis)}
|
return app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pfGenesis)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIncentiveGenState(previousAccumTime, endTime time.Time, rewardPeriods ...incentive.RewardPeriod) app.GenesisState {
|
func NewHardGenStateMulti() app.GenesisState {
|
||||||
var accumulationTimes incentive.GenesisAccumulationTimes
|
KAVA_CF := int64(1000000)
|
||||||
for _, rp := range rewardPeriods {
|
USDX_CF := int64(1000000)
|
||||||
accumulationTimes = append(
|
BNB_CF := int64(100000000)
|
||||||
accumulationTimes,
|
BTCB_CF := int64(100000000)
|
||||||
incentive.NewGenesisAccumulationTime(
|
|
||||||
rp.CollateralType,
|
|
||||||
previousAccumTime,
|
|
||||||
sdk.ZeroDec(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
genesis := incentive.NewGenesisState(
|
|
||||||
incentive.NewParams(
|
|
||||||
rewardPeriods,
|
|
||||||
incentive.Multipliers{
|
|
||||||
incentive.NewMultiplier(incentive.Small, 1, d("0.25")),
|
|
||||||
incentive.NewMultiplier(incentive.Large, 12, d("1.0")),
|
|
||||||
},
|
|
||||||
endTime,
|
|
||||||
),
|
|
||||||
accumulationTimes,
|
|
||||||
incentive.USDXMintingClaims{},
|
|
||||||
)
|
|
||||||
return app.GenesisState{incentive.ModuleName: incentive.ModuleCdc.MustMarshalJSON(genesis)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCDPGenStateHighInterest() app.GenesisState {
|
loanToValue, _ := sdk.NewDecFromStr("0.6")
|
||||||
cdpGenesis := cdp.GenesisState{
|
borrowLimit := sdk.NewDec(1000000000000000)
|
||||||
Params: cdp.Params{
|
|
||||||
GlobalDebtLimit: sdk.NewInt64Coin("usdx", 2000000000000),
|
hardGS := hard.NewGenesisState(hard.NewParams(
|
||||||
SurplusAuctionThreshold: cdp.DefaultSurplusThreshold,
|
true,
|
||||||
SurplusAuctionLot: cdp.DefaultSurplusLot,
|
hard.MoneyMarkets{
|
||||||
DebtAuctionThreshold: cdp.DefaultDebtThreshold,
|
hard.NewMoneyMarket("usdx", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "usdx:usd", sdk.NewInt(1000000), sdk.NewInt(USDX_CF*1000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
DebtAuctionLot: cdp.DefaultDebtLot,
|
hard.NewMoneyMarket("ukava", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "kava:usd", sdk.NewInt(1000000), sdk.NewInt(KAVA_CF*1000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
CollateralParams: cdp.CollateralParams{
|
hard.NewMoneyMarket("bnb", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "bnb:usd", sdk.NewInt(1000000), sdk.NewInt(BNB_CF*1000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
{
|
hard.NewMoneyMarket("btcb", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "btc:usd", sdk.NewInt(1000000), sdk.NewInt(BTCB_CF*1000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
Denom: "bnb",
|
hard.NewMoneyMarket("xrp", hard.NewBorrowLimit(false, borrowLimit, loanToValue), "xrp:usd", sdk.NewInt(1000000), sdk.NewInt(BTCB_CF*1000), hard.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()),
|
||||||
Type: "bnb-a",
|
|
||||||
LiquidationRatio: sdk.MustNewDecFromStr("1.5"),
|
|
||||||
DebtLimit: sdk.NewInt64Coin("usdx", 500000000000),
|
|
||||||
StabilityFee: sdk.MustNewDecFromStr("1.000000051034942716"), // 500% APR
|
|
||||||
LiquidationPenalty: d("0.05"),
|
|
||||||
AuctionSize: i(50000000000),
|
|
||||||
Prefix: 0x22,
|
|
||||||
SpotMarketID: "bnb:usd",
|
|
||||||
LiquidationMarketID: "bnb:usd",
|
|
||||||
ConversionFactor: i(8),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DebtParam: cdp.DebtParam{
|
|
||||||
Denom: "usdx",
|
|
||||||
ReferenceAsset: "usd",
|
|
||||||
ConversionFactor: i(6),
|
|
||||||
DebtFloor: i(10000000),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
StartingCdpID: cdp.DefaultCdpStartingID,
|
|
||||||
DebtDenom: cdp.DefaultDebtDenom,
|
|
||||||
GovDenom: cdp.DefaultGovDenom,
|
|
||||||
CDPs: cdp.CDPs{},
|
|
||||||
PreviousAccumulationTimes: cdp.GenesisAccumulationTimes{
|
|
||||||
cdp.NewGenesisAccumulationTime("bnb-a", time.Time{}, sdk.OneDec()),
|
|
||||||
},
|
|
||||||
TotalPrincipals: cdp.GenesisTotalPrincipals{
|
|
||||||
cdp.NewGenesisTotalPrincipal("bnb-a", sdk.ZeroInt()),
|
|
||||||
},
|
},
|
||||||
}
|
0, // LTV counter
|
||||||
return app.GenesisState{cdp.ModuleName: cdp.ModuleCdc.MustMarshalJSON(cdpGenesis)}
|
), hard.DefaultPreviousBlockTime)
|
||||||
|
|
||||||
|
return app.GenesisState{hard.ModuleName: hard.ModuleCdc.MustMarshalJSON(hardGS)}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ type Keeper struct {
|
|||||||
accountKeeper types.AccountKeeper
|
accountKeeper types.AccountKeeper
|
||||||
cdc *codec.Codec
|
cdc *codec.Codec
|
||||||
cdpKeeper types.CdpKeeper
|
cdpKeeper types.CdpKeeper
|
||||||
|
hardKeeper types.HardKeeper
|
||||||
key sdk.StoreKey
|
key sdk.StoreKey
|
||||||
paramSubspace subspace.Subspace
|
paramSubspace subspace.Subspace
|
||||||
supplyKeeper types.SupplyKeeper
|
supplyKeeper types.SupplyKeeper
|
||||||
@ -24,22 +25,23 @@ type Keeper struct {
|
|||||||
// NewKeeper creates a new keeper
|
// NewKeeper creates a new keeper
|
||||||
func NewKeeper(
|
func NewKeeper(
|
||||||
cdc *codec.Codec, key sdk.StoreKey, paramstore subspace.Subspace, sk types.SupplyKeeper,
|
cdc *codec.Codec, key sdk.StoreKey, paramstore subspace.Subspace, sk types.SupplyKeeper,
|
||||||
cdpk types.CdpKeeper, ak types.AccountKeeper,
|
cdpk types.CdpKeeper, hk types.HardKeeper, ak types.AccountKeeper,
|
||||||
) Keeper {
|
) Keeper {
|
||||||
|
|
||||||
return Keeper{
|
return Keeper{
|
||||||
accountKeeper: ak,
|
accountKeeper: ak,
|
||||||
cdc: cdc,
|
cdc: cdc,
|
||||||
cdpKeeper: cdpk,
|
cdpKeeper: cdpk,
|
||||||
|
hardKeeper: hk,
|
||||||
key: key,
|
key: key,
|
||||||
paramSubspace: paramstore.WithKeyTable(types.ParamKeyTable()),
|
paramSubspace: paramstore.WithKeyTable(types.ParamKeyTable()),
|
||||||
supplyKeeper: sk,
|
supplyKeeper: sk,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClaim returns the claim in the store corresponding the the input address collateral type and id and a boolean for if the claim was found
|
// GetUSDXMintingClaim returns the claim in the store corresponding the the input address collateral type and id and a boolean for if the claim was found
|
||||||
func (k Keeper) GetClaim(ctx sdk.Context, addr sdk.AccAddress) (types.USDXMintingClaim, bool) {
|
func (k Keeper) GetUSDXMintingClaim(ctx sdk.Context, addr sdk.AccAddress) (types.USDXMintingClaim, bool) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimKeyPrefix)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.USDXMintingClaimKeyPrefix)
|
||||||
bz := store.Get(addr)
|
bz := store.Get(addr)
|
||||||
if bz == nil {
|
if bz == nil {
|
||||||
return types.USDXMintingClaim{}, false
|
return types.USDXMintingClaim{}, false
|
||||||
@ -49,23 +51,23 @@ func (k Keeper) GetClaim(ctx sdk.Context, addr sdk.AccAddress) (types.USDXMintin
|
|||||||
return c, true
|
return c, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetClaim sets the claim in the store corresponding to the input address, collateral type, and id
|
// SetUSDXMintingClaim sets the claim in the store corresponding to the input address, collateral type, and id
|
||||||
func (k Keeper) SetClaim(ctx sdk.Context, c types.USDXMintingClaim) {
|
func (k Keeper) SetUSDXMintingClaim(ctx sdk.Context, c types.USDXMintingClaim) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimKeyPrefix)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.USDXMintingClaimKeyPrefix)
|
||||||
bz := k.cdc.MustMarshalBinaryBare(c)
|
bz := k.cdc.MustMarshalBinaryBare(c)
|
||||||
store.Set(c.Owner, bz)
|
store.Set(c.Owner, bz)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteClaim deletes the claim in the store corresponding to the input address, collateral type, and id
|
// DeleteUSDXMintingClaim deletes the claim in the store corresponding to the input address, collateral type, and id
|
||||||
func (k Keeper) DeleteClaim(ctx sdk.Context, owner sdk.AccAddress) {
|
func (k Keeper) DeleteUSDXMintingClaim(ctx sdk.Context, owner sdk.AccAddress) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimKeyPrefix)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.USDXMintingClaimKeyPrefix)
|
||||||
store.Delete(owner)
|
store.Delete(owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IterateClaims iterates over all claim objects in the store and preforms a callback function
|
// IterateUSDXMintingClaims iterates over all claim objects in the store and preforms a callback function
|
||||||
func (k Keeper) IterateClaims(ctx sdk.Context, cb func(c types.USDXMintingClaim) (stop bool)) {
|
func (k Keeper) IterateUSDXMintingClaims(ctx sdk.Context, cb func(c types.USDXMintingClaim) (stop bool)) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.ClaimKeyPrefix)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.USDXMintingClaimKeyPrefix)
|
||||||
iterator := sdk.KVStorePrefixIterator(store, []byte{})
|
iterator := sdk.KVStorePrefixIterator(store, []byte{})
|
||||||
defer iterator.Close()
|
defer iterator.Close()
|
||||||
for ; iterator.Valid(); iterator.Next() {
|
for ; iterator.Valid(); iterator.Next() {
|
||||||
@ -77,19 +79,19 @@ func (k Keeper) IterateClaims(ctx sdk.Context, cb func(c types.USDXMintingClaim)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllClaims returns all Claim objects in the store
|
// GetAllUSDXMintingClaims returns all Claim objects in the store
|
||||||
func (k Keeper) GetAllClaims(ctx sdk.Context) types.USDXMintingClaims {
|
func (k Keeper) GetAllUSDXMintingClaims(ctx sdk.Context) types.USDXMintingClaims {
|
||||||
cs := types.USDXMintingClaims{}
|
cs := types.USDXMintingClaims{}
|
||||||
k.IterateClaims(ctx, func(c types.USDXMintingClaim) (stop bool) {
|
k.IterateUSDXMintingClaims(ctx, func(c types.USDXMintingClaim) (stop bool) {
|
||||||
cs = append(cs, c)
|
cs = append(cs, c)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
return cs
|
return cs
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPreviousAccrualTime returns the last time a collateral type accrued rewards
|
// GetPreviousUSDXMintingAccrualTime returns the last time a collateral type accrued USDX minting rewards
|
||||||
func (k Keeper) GetPreviousAccrualTime(ctx sdk.Context, ctype string) (blockTime time.Time, found bool) {
|
func (k Keeper) GetPreviousUSDXMintingAccrualTime(ctx sdk.Context, ctype string) (blockTime time.Time, found bool) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.BlockTimeKey)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousUSDXMintingRewardAccrualTimeKeyPrefix)
|
||||||
bz := store.Get([]byte(ctype))
|
bz := store.Get([]byte(ctype))
|
||||||
if bz == nil {
|
if bz == nil {
|
||||||
return time.Time{}, false
|
return time.Time{}, false
|
||||||
@ -98,15 +100,15 @@ func (k Keeper) GetPreviousAccrualTime(ctx sdk.Context, ctype string) (blockTime
|
|||||||
return blockTime, true
|
return blockTime, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPreviousAccrualTime sets the last time a collateral type accrued rewards
|
// SetPreviousUSDXMintingAccrualTime sets the last time a collateral type accrued USDX minting rewards
|
||||||
func (k Keeper) SetPreviousAccrualTime(ctx sdk.Context, ctype string, blockTime time.Time) {
|
func (k Keeper) SetPreviousUSDXMintingAccrualTime(ctx sdk.Context, ctype string, blockTime time.Time) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.BlockTimeKey)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousUSDXMintingRewardAccrualTimeKeyPrefix)
|
||||||
store.Set([]byte(ctype), k.cdc.MustMarshalBinaryBare(blockTime))
|
store.Set([]byte(ctype), k.cdc.MustMarshalBinaryBare(blockTime))
|
||||||
}
|
}
|
||||||
|
|
||||||
// IterateAccrualTimes iterates over all previous accrual times and preforms a callback function
|
// IterateUSDXMintingAccrualTimes iterates over all previous USDX minting accrual times and preforms a callback function
|
||||||
func (k Keeper) IterateAccrualTimes(ctx sdk.Context, cb func(string, time.Time) (stop bool)) {
|
func (k Keeper) IterateUSDXMintingAccrualTimes(ctx sdk.Context, cb func(string, time.Time) (stop bool)) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.BlockTimeKey)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousUSDXMintingRewardAccrualTimeKeyPrefix)
|
||||||
iterator := sdk.KVStorePrefixIterator(store, []byte{})
|
iterator := sdk.KVStorePrefixIterator(store, []byte{})
|
||||||
defer iterator.Close()
|
defer iterator.Close()
|
||||||
for ; iterator.Valid(); iterator.Next() {
|
for ; iterator.Valid(); iterator.Next() {
|
||||||
@ -120,9 +122,9 @@ func (k Keeper) IterateAccrualTimes(ctx sdk.Context, cb func(string, time.Time)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRewardFactor returns the current reward factor for an individual collateral type
|
// GetUSDXMintingRewardFactor returns the current reward factor for an individual collateral type
|
||||||
func (k Keeper) GetRewardFactor(ctx sdk.Context, ctype string) (factor sdk.Dec, found bool) {
|
func (k Keeper) GetUSDXMintingRewardFactor(ctx sdk.Context, ctype string) (factor sdk.Dec, found bool) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.RewardFactorKey)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.USDXMintingRewardFactorKeyPrefix)
|
||||||
bz := store.Get([]byte(ctype))
|
bz := store.Get([]byte(ctype))
|
||||||
if bz == nil {
|
if bz == nil {
|
||||||
return sdk.ZeroDec(), false
|
return sdk.ZeroDec(), false
|
||||||
@ -131,8 +133,146 @@ func (k Keeper) GetRewardFactor(ctx sdk.Context, ctype string) (factor sdk.Dec,
|
|||||||
return factor, true
|
return factor, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRewardFactor sets the current reward factor for an individual collateral type
|
// SetUSDXMintingRewardFactor sets the current reward factor for an individual collateral type
|
||||||
func (k Keeper) SetRewardFactor(ctx sdk.Context, ctype string, factor sdk.Dec) {
|
func (k Keeper) SetUSDXMintingRewardFactor(ctx sdk.Context, ctype string, factor sdk.Dec) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.RewardFactorKey)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.USDXMintingRewardFactorKeyPrefix)
|
||||||
store.Set([]byte(ctype), k.cdc.MustMarshalBinaryBare(factor))
|
store.Set([]byte(ctype), k.cdc.MustMarshalBinaryBare(factor))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHardLiquidityProviderClaim returns the claim in the store corresponding the the input address collateral type and id and a boolean for if the claim was found
|
||||||
|
func (k Keeper) GetHardLiquidityProviderClaim(ctx sdk.Context, addr sdk.AccAddress) (types.HardLiquidityProviderClaim, bool) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.HardLiquidityClaimKeyPrefix)
|
||||||
|
bz := store.Get(addr)
|
||||||
|
if bz == nil {
|
||||||
|
return types.HardLiquidityProviderClaim{}, false
|
||||||
|
}
|
||||||
|
var c types.HardLiquidityProviderClaim
|
||||||
|
k.cdc.MustUnmarshalBinaryBare(bz, &c)
|
||||||
|
return c, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHardLiquidityProviderClaim sets the claim in the store corresponding to the input address, collateral type, and id
|
||||||
|
func (k Keeper) SetHardLiquidityProviderClaim(ctx sdk.Context, c types.HardLiquidityProviderClaim) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.HardLiquidityClaimKeyPrefix)
|
||||||
|
bz := k.cdc.MustMarshalBinaryBare(c)
|
||||||
|
store.Set(c.Owner, bz)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteHardLiquidityProviderClaim deletes the claim in the store corresponding to the input address, collateral type, and id
|
||||||
|
func (k Keeper) DeleteHardLiquidityProviderClaim(ctx sdk.Context, owner sdk.AccAddress) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.HardLiquidityClaimKeyPrefix)
|
||||||
|
store.Delete(owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IterateHardLiquidityProviderClaims iterates over all claim objects in the store and preforms a callback function
|
||||||
|
func (k Keeper) IterateHardLiquidityProviderClaims(ctx sdk.Context, cb func(c types.HardLiquidityProviderClaim) (stop bool)) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.HardLiquidityClaimKeyPrefix)
|
||||||
|
iterator := sdk.KVStorePrefixIterator(store, []byte{})
|
||||||
|
defer iterator.Close()
|
||||||
|
for ; iterator.Valid(); iterator.Next() {
|
||||||
|
var c types.HardLiquidityProviderClaim
|
||||||
|
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &c)
|
||||||
|
if cb(c) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllHardLiquidityProviderClaims returns all Claim objects in the store
|
||||||
|
func (k Keeper) GetAllHardLiquidityProviderClaims(ctx sdk.Context) types.HardLiquidityProviderClaims {
|
||||||
|
cs := types.HardLiquidityProviderClaims{}
|
||||||
|
k.IterateHardLiquidityProviderClaims(ctx, func(c types.HardLiquidityProviderClaim) (stop bool) {
|
||||||
|
cs = append(cs, c)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
return cs
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHardSupplyRewardFactor sets the current interest factor for an individual market
|
||||||
|
func (k Keeper) SetHardSupplyRewardFactor(ctx sdk.Context, denom string, borrowIndex sdk.Dec) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.HardSupplyRewardFactorKeyPrefix)
|
||||||
|
bz := k.cdc.MustMarshalBinaryBare(borrowIndex)
|
||||||
|
store.Set([]byte(denom), bz)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHardSupplyRewardFactor returns the current interest factor for an individual market
|
||||||
|
func (k Keeper) GetHardSupplyRewardFactor(ctx sdk.Context, denom string) (sdk.Dec, bool) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.HardSupplyRewardFactorKeyPrefix)
|
||||||
|
bz := store.Get([]byte(denom))
|
||||||
|
if bz == nil {
|
||||||
|
return sdk.ZeroDec(), false
|
||||||
|
}
|
||||||
|
var interestFactor sdk.Dec
|
||||||
|
k.cdc.MustUnmarshalBinaryBare(bz, &interestFactor)
|
||||||
|
return interestFactor, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHardBorrowRewardFactor sets the current interest factor for an individual market
|
||||||
|
func (k Keeper) SetHardBorrowRewardFactor(ctx sdk.Context, denom string, borrowIndex sdk.Dec) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.HardBorrowRewardFactorKeyPrefix)
|
||||||
|
bz := k.cdc.MustMarshalBinaryBare(borrowIndex)
|
||||||
|
store.Set([]byte(denom), bz)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHardBorrowRewardFactor returns the current interest factor for an individual market
|
||||||
|
func (k Keeper) GetHardBorrowRewardFactor(ctx sdk.Context, denom string) (sdk.Dec, bool) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.HardBorrowRewardFactorKeyPrefix)
|
||||||
|
bz := store.Get([]byte(denom))
|
||||||
|
if bz == nil {
|
||||||
|
return sdk.ZeroDec(), false
|
||||||
|
}
|
||||||
|
var interestFactor sdk.Dec
|
||||||
|
k.cdc.MustUnmarshalBinaryBare(bz, &interestFactor)
|
||||||
|
return interestFactor, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
if bz == nil {
|
||||||
|
return sdk.ZeroDec(), false
|
||||||
|
}
|
||||||
|
k.cdc.MustUnmarshalBinaryBare(bz, &factor)
|
||||||
|
return factor, 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))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPreviousHardSupplyRewardAccrualTime returns the last time a denom accrued Hard protocol supply-side rewards
|
||||||
|
func (k Keeper) GetPreviousHardSupplyRewardAccrualTime(ctx sdk.Context, denom string) (blockTime time.Time, found bool) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousHardSupplyRewardAccrualTimeKeyPrefix)
|
||||||
|
bz := store.Get([]byte(denom))
|
||||||
|
if bz == nil {
|
||||||
|
return time.Time{}, false
|
||||||
|
}
|
||||||
|
k.cdc.MustUnmarshalBinaryBare(bz, &blockTime)
|
||||||
|
return blockTime, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPreviousHardSupplyRewardAccrualTime sets the last time a denom accrued Hard protocol supply-side rewards
|
||||||
|
func (k Keeper) SetPreviousHardSupplyRewardAccrualTime(ctx sdk.Context, denom string, blockTime time.Time) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousHardSupplyRewardAccrualTimeKeyPrefix)
|
||||||
|
store.Set([]byte(denom), k.cdc.MustMarshalBinaryBare(blockTime))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPreviousHardBorrowRewardAccrualTime returns the last time a denom accrued Hard protocol borrow-side rewards
|
||||||
|
func (k Keeper) GetPreviousHardBorrowRewardAccrualTime(ctx sdk.Context, denom string) (blockTime time.Time, found bool) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousHardBorrowRewardAccrualTimeKeyPrefix)
|
||||||
|
bz := store.Get([]byte(denom))
|
||||||
|
if bz == nil {
|
||||||
|
return time.Time{}, false
|
||||||
|
}
|
||||||
|
k.cdc.MustUnmarshalBinaryBare(bz, &blockTime)
|
||||||
|
return blockTime, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPreviousHardBorrowRewardAccrualTime sets the last time a denom accrued Hard protocol borrow-side rewards
|
||||||
|
func (k Keeper) SetPreviousHardBorrowRewardAccrualTime(ctx sdk.Context, denom string, blockTime time.Time) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousHardBorrowRewardAccrualTimeKeyPrefix)
|
||||||
|
store.Set([]byte(denom), k.cdc.MustMarshalBinaryBare(blockTime))
|
||||||
|
}
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
tmtime "github.com/tendermint/tendermint/types/time"
|
tmtime "github.com/tendermint/tendermint/types/time"
|
||||||
|
|
||||||
"github.com/kava-labs/kava/app"
|
"github.com/kava-labs/kava/app"
|
||||||
|
hardkeeper "github.com/kava-labs/kava/x/hard/keeper"
|
||||||
"github.com/kava-labs/kava/x/incentive/keeper"
|
"github.com/kava-labs/kava/x/incentive/keeper"
|
||||||
"github.com/kava-labs/kava/x/incentive/types"
|
"github.com/kava-labs/kava/x/incentive/types"
|
||||||
)
|
)
|
||||||
@ -24,6 +25,7 @@ type KeeperTestSuite struct {
|
|||||||
suite.Suite
|
suite.Suite
|
||||||
|
|
||||||
keeper keeper.Keeper
|
keeper keeper.Keeper
|
||||||
|
hardKeeper hardkeeper.Keeper
|
||||||
app app.TestApp
|
app app.TestApp
|
||||||
ctx sdk.Context
|
ctx sdk.Context
|
||||||
addrs []sdk.AccAddress
|
addrs []sdk.AccAddress
|
||||||
@ -52,45 +54,41 @@ func (suite *KeeperTestSuite) getModuleAccount(name string) supplyexported.Modul
|
|||||||
return sk.GetModuleAccount(suite.ctx, name)
|
return sk.GetModuleAccount(suite.ctx, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestGetSetDeleteClaim() {
|
func (suite *KeeperTestSuite) TestGetSetDeleteUSDXMintingClaim() {
|
||||||
c := types.NewUSDXMintingClaim(suite.addrs[0], c("ukava", 1000000), types.RewardIndexes{types.NewRewardIndex("bnb-a", sdk.ZeroDec())})
|
c := types.NewUSDXMintingClaim(suite.addrs[0], c("ukava", 1000000), types.RewardIndexes{types.NewRewardIndex("bnb-a", sdk.ZeroDec())})
|
||||||
_, found := suite.keeper.GetClaim(suite.ctx, suite.addrs[0])
|
_, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0])
|
||||||
suite.Require().False(found)
|
suite.Require().False(found)
|
||||||
suite.Require().NotPanics(func() {
|
suite.Require().NotPanics(func() {
|
||||||
suite.keeper.SetClaim(suite.ctx, c)
|
suite.keeper.SetUSDXMintingClaim(suite.ctx, c)
|
||||||
})
|
})
|
||||||
testC, found := suite.keeper.GetClaim(suite.ctx, suite.addrs[0])
|
testC, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0])
|
||||||
suite.Require().True(found)
|
suite.Require().True(found)
|
||||||
suite.Require().Equal(c, testC)
|
suite.Require().Equal(c, testC)
|
||||||
suite.Require().NotPanics(func() {
|
suite.Require().NotPanics(func() {
|
||||||
suite.keeper.DeleteClaim(suite.ctx, suite.addrs[0])
|
suite.keeper.DeleteUSDXMintingClaim(suite.ctx, suite.addrs[0])
|
||||||
})
|
})
|
||||||
_, found = suite.keeper.GetClaim(suite.ctx, suite.addrs[0])
|
_, found = suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0])
|
||||||
suite.Require().False(found)
|
suite.Require().False(found)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestIterateClaims() {
|
func (suite *KeeperTestSuite) TestIterateUSDXMintingClaims() {
|
||||||
for i := 0; i < len(suite.addrs); i++ {
|
for i := 0; i < len(suite.addrs); i++ {
|
||||||
c := types.NewUSDXMintingClaim(suite.addrs[i], c("ukava", 100000), types.RewardIndexes{types.NewRewardIndex("bnb-a", sdk.ZeroDec())})
|
c := types.NewUSDXMintingClaim(suite.addrs[i], c("ukava", 100000), types.RewardIndexes{types.NewRewardIndex("bnb-a", sdk.ZeroDec())})
|
||||||
suite.Require().NotPanics(func() {
|
suite.Require().NotPanics(func() {
|
||||||
suite.keeper.SetClaim(suite.ctx, c)
|
suite.keeper.SetUSDXMintingClaim(suite.ctx, c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
claims := types.USDXMintingClaims{}
|
claims := types.USDXMintingClaims{}
|
||||||
suite.keeper.IterateClaims(suite.ctx, func(c types.USDXMintingClaim) bool {
|
suite.keeper.IterateUSDXMintingClaims(suite.ctx, func(c types.USDXMintingClaim) bool {
|
||||||
claims = append(claims, c)
|
claims = append(claims, c)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
suite.Require().Equal(len(suite.addrs), len(claims))
|
suite.Require().Equal(len(suite.addrs), len(claims))
|
||||||
|
|
||||||
claims = suite.keeper.GetAllClaims(suite.ctx)
|
claims = suite.keeper.GetAllUSDXMintingClaims(suite.ctx)
|
||||||
suite.Require().Equal(len(suite.addrs), len(claims))
|
suite.Require().Equal(len(suite.addrs), len(claims))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeeperTestSuite(t *testing.T) {
|
|
||||||
suite.Run(t, new(KeeperTestSuite))
|
|
||||||
}
|
|
||||||
|
|
||||||
func createPeriodicVestingAccount(origVesting sdk.Coins, periods vesting.Periods, startTime, endTime int64) (*vesting.PeriodicVestingAccount, error) {
|
func createPeriodicVestingAccount(origVesting sdk.Coins, periods vesting.Periods, startTime, endTime int64) (*vesting.PeriodicVestingAccount, error) {
|
||||||
_, addr := app.GeneratePrivKeyAddressPairs(1)
|
_, addr := app.GeneratePrivKeyAddressPairs(1)
|
||||||
bacc := auth.NewBaseAccountWithAddress(addr[0])
|
bacc := auth.NewBaseAccountWithAddress(addr[0])
|
||||||
@ -112,3 +110,7 @@ func i(in int64) sdk.Int { return sdk.NewInt(in) }
|
|||||||
func d(str string) sdk.Dec { return sdk.MustNewDecFromStr(str) }
|
func d(str string) sdk.Dec { return sdk.MustNewDecFromStr(str) }
|
||||||
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
|
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
|
||||||
func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) }
|
func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) }
|
||||||
|
|
||||||
|
func TestKeeperTestSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(KeeperTestSuite))
|
||||||
|
}
|
||||||
|
@ -20,10 +20,10 @@ func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
|
|||||||
k.paramSubspace.SetParamSet(ctx, ¶ms)
|
k.paramSubspace.SetParamSet(ctx, ¶ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRewardPeriod returns the reward period with the specified collateral type if it's found in the params
|
// GetUSDXMintingRewardPeriod returns the reward period with the specified collateral type if it's found in the params
|
||||||
func (k Keeper) GetRewardPeriod(ctx sdk.Context, collateralType string) (types.RewardPeriod, bool) {
|
func (k Keeper) GetUSDXMintingRewardPeriod(ctx sdk.Context, collateralType string) (types.RewardPeriod, bool) {
|
||||||
params := k.GetParams(ctx)
|
params := k.GetParams(ctx)
|
||||||
for _, rp := range params.RewardPeriods {
|
for _, rp := range params.USDXMintingRewardPeriods {
|
||||||
if rp.CollateralType == collateralType {
|
if rp.CollateralType == collateralType {
|
||||||
return rp, true
|
return rp, true
|
||||||
}
|
}
|
||||||
@ -31,6 +31,28 @@ func (k Keeper) GetRewardPeriod(ctx sdk.Context, collateralType string) (types.R
|
|||||||
return types.RewardPeriod{}, false
|
return types.RewardPeriod{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHardSupplyRewardPeriod returns the reward period with the specified collateral type if it's found in the params
|
||||||
|
func (k Keeper) GetHardSupplyRewardPeriod(ctx sdk.Context, denom string) (types.RewardPeriod, bool) {
|
||||||
|
params := k.GetParams(ctx)
|
||||||
|
for _, rp := range params.HardSupplyRewardPeriods {
|
||||||
|
if rp.CollateralType == denom {
|
||||||
|
return rp, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return types.RewardPeriod{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHardBorrowRewardPeriod returns the reward period with the specified collateral type if it's found in the params
|
||||||
|
func (k Keeper) GetHardBorrowRewardPeriod(ctx sdk.Context, denom string) (types.RewardPeriod, bool) {
|
||||||
|
params := k.GetParams(ctx)
|
||||||
|
for _, rp := range params.HardBorrowRewardPeriods {
|
||||||
|
if rp.CollateralType == denom {
|
||||||
|
return rp, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return types.RewardPeriod{}, false
|
||||||
|
}
|
||||||
|
|
||||||
// GetMultiplier returns the multiplier with the specified name if it's found in the params
|
// GetMultiplier returns the multiplier with the specified name if it's found in the params
|
||||||
func (k Keeper) GetMultiplier(ctx sdk.Context, name types.MultiplierName) (types.Multiplier, bool) {
|
func (k Keeper) GetMultiplier(ctx sdk.Context, name types.MultiplierName) (types.Multiplier, bool) {
|
||||||
params := k.GetParams(ctx)
|
params := k.GetParams(ctx)
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
// ClaimReward sends the reward amount to the input address and zero's out the claim in the store
|
// ClaimReward sends the reward amount to the input address and zero's out the claim in the store
|
||||||
func (k Keeper) ClaimReward(ctx sdk.Context, addr sdk.AccAddress, multiplierName types.MultiplierName) error {
|
func (k Keeper) ClaimReward(ctx sdk.Context, addr sdk.AccAddress, multiplierName types.MultiplierName) error {
|
||||||
claim, found := k.GetClaim(ctx, addr)
|
claim, found := k.GetUSDXMintingClaim(ctx, addr)
|
||||||
if !found {
|
if !found {
|
||||||
return sdkerrors.Wrapf(types.ErrClaimNotFound, "address: %s", addr)
|
return sdkerrors.Wrapf(types.ErrClaimNotFound, "address: %s", addr)
|
||||||
}
|
}
|
||||||
|
@ -86,18 +86,21 @@ func (suite *KeeperTestSuite) TestPayoutClaim() {
|
|||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
suite.Run(tc.name, func() {
|
suite.Run(tc.name, func() {
|
||||||
suite.SetupWithCDPGenState()
|
suite.SetupWithGenState()
|
||||||
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
||||||
|
|
||||||
// setup incentive state
|
// setup incentive state
|
||||||
params := types.NewParams(
|
params := types.NewParams(
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
tc.args.multipliers,
|
tc.args.multipliers,
|
||||||
tc.args.initialTime.Add(time.Hour*24*365*5),
|
tc.args.initialTime.Add(time.Hour*24*365*5),
|
||||||
)
|
)
|
||||||
suite.keeper.SetParams(suite.ctx, params)
|
suite.keeper.SetParams(suite.ctx, params)
|
||||||
suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime)
|
suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime)
|
||||||
suite.keeper.SetRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec())
|
suite.keeper.SetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec())
|
||||||
|
|
||||||
// setup account state
|
// setup account state
|
||||||
sk := suite.app.GetSupplyKeeper()
|
sk := suite.app.GetSupplyKeeper()
|
||||||
@ -115,15 +118,15 @@ func (suite *KeeperTestSuite) TestPayoutClaim() {
|
|||||||
err = cdpKeeper.AddCdp(suite.ctx, suite.addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype)
|
err = cdpKeeper.AddCdp(suite.ctx, suite.addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype)
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
claim, found := suite.keeper.GetClaim(suite.ctx, suite.addrs[0])
|
claim, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0])
|
||||||
suite.Require().True(found)
|
suite.Require().True(found)
|
||||||
suite.Require().Equal(sdk.ZeroDec(), claim.RewardIndexes[0].RewardFactor)
|
suite.Require().Equal(sdk.ZeroDec(), claim.RewardIndexes[0].RewardFactor)
|
||||||
|
|
||||||
updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed))
|
updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed))
|
||||||
suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime)
|
suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime)
|
||||||
rewardPeriod, found := suite.keeper.GetRewardPeriod(suite.ctx, tc.args.ctype)
|
rewardPeriod, found := suite.keeper.GetUSDXMintingRewardPeriod(suite.ctx, tc.args.ctype)
|
||||||
suite.Require().True(found)
|
suite.Require().True(found)
|
||||||
err = suite.keeper.AccumulateRewards(suite.ctx, rewardPeriod)
|
err = suite.keeper.AccumulateUSDXMintingRewards(suite.ctx, rewardPeriod)
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
err = suite.keeper.ClaimReward(suite.ctx, suite.addrs[0], tc.args.multiplier)
|
err = suite.keeper.ClaimReward(suite.ctx, suite.addrs[0], tc.args.multiplier)
|
||||||
@ -140,7 +143,7 @@ func (suite *KeeperTestSuite) TestPayoutClaim() {
|
|||||||
suite.Require().Equal(tc.args.expectedPeriods, vacc.VestingPeriods)
|
suite.Require().Equal(tc.args.expectedPeriods, vacc.VestingPeriods)
|
||||||
}
|
}
|
||||||
|
|
||||||
claim, found := suite.keeper.GetClaim(suite.ctx, suite.addrs[0])
|
claim, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0])
|
||||||
fmt.Println(claim)
|
fmt.Println(claim)
|
||||||
suite.Require().True(found)
|
suite.Require().True(found)
|
||||||
suite.Require().Equal(c("ukava", 0), claim.Reward)
|
suite.Require().Equal(c("ukava", 0), claim.Reward)
|
||||||
|
@ -46,10 +46,10 @@ func queryGetClaims(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, e
|
|||||||
}
|
}
|
||||||
var claims types.USDXMintingClaims
|
var claims types.USDXMintingClaims
|
||||||
if len(requestParams.Owner) > 0 {
|
if len(requestParams.Owner) > 0 {
|
||||||
claim, _ := k.GetClaim(ctx, requestParams.Owner)
|
claim, _ := k.GetUSDXMintingClaim(ctx, requestParams.Owner)
|
||||||
claims = append(claims, claim)
|
claims = append(claims, claim)
|
||||||
} else {
|
} else {
|
||||||
claims = k.GetAllClaims(ctx)
|
claims = k.GetAllUSDXMintingClaims(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
var paginatedClaims types.USDXMintingClaims
|
var paginatedClaims types.USDXMintingClaims
|
||||||
|
@ -1,24 +1,22 @@
|
|||||||
package keeper
|
package keeper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
||||||
|
hardtypes "github.com/kava-labs/kava/x/hard/types"
|
||||||
"github.com/kava-labs/kava/x/incentive/types"
|
"github.com/kava-labs/kava/x/incentive/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AccumulateRewards updates the rewards accumulated for the input reward period
|
// AccumulateUSDXMintingRewards updates the rewards accumulated for the input reward period
|
||||||
func (k Keeper) AccumulateRewards(ctx sdk.Context, rewardPeriod types.RewardPeriod) error {
|
func (k Keeper) AccumulateUSDXMintingRewards(ctx sdk.Context, rewardPeriod types.RewardPeriod) error {
|
||||||
if !rewardPeriod.Active {
|
previousAccrualTime, found := k.GetPreviousUSDXMintingAccrualTime(ctx, rewardPeriod.CollateralType)
|
||||||
k.SetPreviousAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
previousAccrualTime, found := k.GetPreviousAccrualTime(ctx, rewardPeriod.CollateralType)
|
|
||||||
if !found {
|
if !found {
|
||||||
k.SetPreviousAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
k.SetPreviousUSDXMintingAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
timeElapsed := CalculateTimeElapsed(rewardPeriod, ctx.BlockTime(), previousAccrualTime)
|
timeElapsed := CalculateTimeElapsed(rewardPeriod, ctx.BlockTime(), previousAccrualTime)
|
||||||
@ -26,50 +24,135 @@ func (k Keeper) AccumulateRewards(ctx sdk.Context, rewardPeriod types.RewardPeri
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if rewardPeriod.RewardsPerSecond.Amount.IsZero() {
|
if rewardPeriod.RewardsPerSecond.Amount.IsZero() {
|
||||||
k.SetPreviousAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
k.SetPreviousUSDXMintingAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
totalPrincipal := k.cdpKeeper.GetTotalPrincipal(ctx, rewardPeriod.CollateralType, types.PrincipalDenom).ToDec()
|
totalPrincipal := k.cdpKeeper.GetTotalPrincipal(ctx, rewardPeriod.CollateralType, types.PrincipalDenom).ToDec()
|
||||||
if totalPrincipal.IsZero() {
|
if totalPrincipal.IsZero() {
|
||||||
k.SetPreviousAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
k.SetPreviousUSDXMintingAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
newRewards := timeElapsed.Mul(rewardPeriod.RewardsPerSecond.Amount)
|
newRewards := timeElapsed.Mul(rewardPeriod.RewardsPerSecond.Amount)
|
||||||
cdpFactor, found := k.cdpKeeper.GetInterestFactor(ctx, rewardPeriod.CollateralType)
|
cdpFactor, found := k.cdpKeeper.GetInterestFactor(ctx, rewardPeriod.CollateralType)
|
||||||
if !found {
|
if !found {
|
||||||
k.SetPreviousAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
k.SetPreviousUSDXMintingAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
rewardFactor := newRewards.ToDec().Mul(cdpFactor).Quo(totalPrincipal)
|
rewardFactor := newRewards.ToDec().Mul(cdpFactor).Quo(totalPrincipal)
|
||||||
|
|
||||||
previousRewardFactor, found := k.GetRewardFactor(ctx, rewardPeriod.CollateralType)
|
previousRewardFactor, found := k.GetUSDXMintingRewardFactor(ctx, rewardPeriod.CollateralType)
|
||||||
if !found {
|
if !found {
|
||||||
previousRewardFactor = sdk.ZeroDec()
|
previousRewardFactor = sdk.ZeroDec()
|
||||||
}
|
}
|
||||||
newRewardFactor := previousRewardFactor.Add(rewardFactor)
|
newRewardFactor := previousRewardFactor.Add(rewardFactor)
|
||||||
k.SetRewardFactor(ctx, rewardPeriod.CollateralType, newRewardFactor)
|
k.SetUSDXMintingRewardFactor(ctx, rewardPeriod.CollateralType, newRewardFactor)
|
||||||
k.SetPreviousAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
k.SetPreviousUSDXMintingAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitializeClaim creates or updates a claim such that no new rewards are accrued, but any existing rewards are not lost.
|
// AccumulateHardBorrowRewards updates the rewards accumulated for the input reward period
|
||||||
|
func (k Keeper) AccumulateHardBorrowRewards(ctx sdk.Context, rewardPeriod types.RewardPeriod) error {
|
||||||
|
previousAccrualTime, found := k.GetPreviousHardBorrowRewardAccrualTime(ctx, rewardPeriod.CollateralType)
|
||||||
|
if !found {
|
||||||
|
k.SetPreviousHardBorrowRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
timeElapsed := CalculateTimeElapsed(rewardPeriod, ctx.BlockTime(), previousAccrualTime)
|
||||||
|
if timeElapsed.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if rewardPeriod.RewardsPerSecond.Amount.IsZero() {
|
||||||
|
k.SetPreviousHardBorrowRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
totalBorrowedCoins, foundTotalBorrowedCoins := k.hardKeeper.GetBorrowedCoins(ctx)
|
||||||
|
if foundTotalBorrowedCoins {
|
||||||
|
totalBorrowed := totalBorrowedCoins.AmountOf(rewardPeriod.CollateralType).ToDec()
|
||||||
|
if totalBorrowed.IsZero() {
|
||||||
|
k.SetPreviousHardBorrowRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
newRewards := timeElapsed.Mul(rewardPeriod.RewardsPerSecond.Amount)
|
||||||
|
hardFactor, found := k.hardKeeper.GetBorrowInterestFactor(ctx, rewardPeriod.CollateralType)
|
||||||
|
if !found {
|
||||||
|
k.SetPreviousHardBorrowRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
rewardFactor := newRewards.ToDec().Mul(hardFactor).Quo(totalBorrowed)
|
||||||
|
|
||||||
|
previousRewardFactor, found := k.GetHardBorrowRewardFactor(ctx, rewardPeriod.CollateralType)
|
||||||
|
if !found {
|
||||||
|
previousRewardFactor = sdk.ZeroDec()
|
||||||
|
}
|
||||||
|
newRewardFactor := previousRewardFactor.Add(rewardFactor)
|
||||||
|
k.SetHardBorrowRewardFactor(ctx, rewardPeriod.CollateralType, newRewardFactor)
|
||||||
|
}
|
||||||
|
k.SetPreviousHardBorrowRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccumulateHardSupplyRewards updates the rewards accumulated for the input reward period
|
||||||
|
func (k Keeper) AccumulateHardSupplyRewards(ctx sdk.Context, rewardPeriod types.RewardPeriod) error {
|
||||||
|
previousAccrualTime, found := k.GetPreviousHardSupplyRewardAccrualTime(ctx, rewardPeriod.CollateralType)
|
||||||
|
if !found {
|
||||||
|
k.SetPreviousHardSupplyRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
timeElapsed := CalculateTimeElapsed(rewardPeriod, ctx.BlockTime(), previousAccrualTime)
|
||||||
|
if timeElapsed.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if rewardPeriod.RewardsPerSecond.Amount.IsZero() {
|
||||||
|
k.SetPreviousHardSupplyRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
totalSuppliedCoins, foundTotalSuppliedCoins := k.hardKeeper.GetSuppliedCoins(ctx)
|
||||||
|
if foundTotalSuppliedCoins {
|
||||||
|
totalSupplied := totalSuppliedCoins.AmountOf(rewardPeriod.CollateralType).ToDec()
|
||||||
|
if totalSupplied.IsZero() {
|
||||||
|
k.SetPreviousHardSupplyRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
newRewards := timeElapsed.Mul(rewardPeriod.RewardsPerSecond.Amount)
|
||||||
|
hardFactor, found := k.hardKeeper.GetSupplyInterestFactor(ctx, rewardPeriod.CollateralType)
|
||||||
|
if !found {
|
||||||
|
k.SetPreviousHardSupplyRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
rewardFactor := newRewards.ToDec().Mul(hardFactor).Quo(totalSupplied)
|
||||||
|
|
||||||
|
previousRewardFactor, found := k.GetHardSupplyRewardFactor(ctx, rewardPeriod.CollateralType)
|
||||||
|
if !found {
|
||||||
|
previousRewardFactor = sdk.ZeroDec()
|
||||||
|
}
|
||||||
|
newRewardFactor := previousRewardFactor.Add(rewardFactor)
|
||||||
|
k.SetHardSupplyRewardFactor(ctx, rewardPeriod.CollateralType, newRewardFactor)
|
||||||
|
}
|
||||||
|
k.SetPreviousHardSupplyRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitializeUSDXMintingClaim creates or updates a claim such that no new rewards are accrued, but any existing rewards are not lost.
|
||||||
// this function should be called after a cdp is created. If a user previously had a cdp, then closed it, they shouldn't
|
// this function should be called after a cdp is created. If a user previously had a cdp, then closed it, they shouldn't
|
||||||
// accrue rewards during the period the cdp was closed. By setting the reward factor to the current global reward factor,
|
// accrue rewards during the period the cdp was closed. By setting the reward factor to the current global reward factor,
|
||||||
// any unclaimed rewards are preserved, but no new rewards are added.
|
// any unclaimed rewards are preserved, but no new rewards are added.
|
||||||
func (k Keeper) InitializeClaim(ctx sdk.Context, cdp cdptypes.CDP) {
|
func (k Keeper) InitializeUSDXMintingClaim(ctx sdk.Context, cdp cdptypes.CDP) {
|
||||||
_, found := k.GetRewardPeriod(ctx, cdp.Type)
|
_, found := k.GetUSDXMintingRewardPeriod(ctx, cdp.Type)
|
||||||
if !found {
|
if !found {
|
||||||
// this collateral type is not incentivized, do nothing
|
// this collateral type is not incentivized, do nothing
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rewardFactor, found := k.GetRewardFactor(ctx, cdp.Type)
|
rewardFactor, found := k.GetUSDXMintingRewardFactor(ctx, cdp.Type)
|
||||||
if !found {
|
if !found {
|
||||||
rewardFactor = sdk.ZeroDec()
|
rewardFactor = sdk.ZeroDec()
|
||||||
}
|
}
|
||||||
claim, found := k.GetClaim(ctx, cdp.Owner)
|
claim, found := k.GetUSDXMintingClaim(ctx, cdp.Owner)
|
||||||
if !found { // this is the owner's first usdx minting reward claim
|
if !found { // this is the owner's first usdx minting reward claim
|
||||||
claim = types.NewUSDXMintingClaim(cdp.Owner, sdk.NewCoin(types.USDXMintingRewardDenom, sdk.ZeroInt()), types.RewardIndexes{types.NewRewardIndex(cdp.Type, rewardFactor)})
|
claim = types.NewUSDXMintingClaim(cdp.Owner, sdk.NewCoin(types.USDXMintingRewardDenom, sdk.ZeroInt()), types.RewardIndexes{types.NewRewardIndex(cdp.Type, rewardFactor)})
|
||||||
k.SetClaim(ctx, claim)
|
k.SetUSDXMintingClaim(ctx, claim)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// the owner has an existing usdx minting reward claim
|
// the owner has an existing usdx minting reward claim
|
||||||
@ -79,26 +162,26 @@ func (k Keeper) InitializeClaim(ctx sdk.Context, cdp cdptypes.CDP) {
|
|||||||
} else { // the owner has a previous usdx minting reward for this collateral type
|
} else { // the owner has a previous usdx minting reward for this collateral type
|
||||||
claim.RewardIndexes[index] = types.NewRewardIndex(cdp.Type, rewardFactor)
|
claim.RewardIndexes[index] = types.NewRewardIndex(cdp.Type, rewardFactor)
|
||||||
}
|
}
|
||||||
k.SetClaim(ctx, claim)
|
k.SetUSDXMintingClaim(ctx, claim)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SynchronizeReward updates the claim object by adding any accumulated rewards and updating the reward index value.
|
// SynchronizeUSDXMintingReward updates the claim object by adding any accumulated rewards and updating the reward index value.
|
||||||
// this should be called before a cdp is modified, immediately after the 'SynchronizeInterest' method is called in the cdp module
|
// this should be called before a cdp is modified, immediately after the 'SynchronizeInterest' method is called in the cdp module
|
||||||
func (k Keeper) SynchronizeReward(ctx sdk.Context, cdp cdptypes.CDP) {
|
func (k Keeper) SynchronizeUSDXMintingReward(ctx sdk.Context, cdp cdptypes.CDP) {
|
||||||
_, found := k.GetRewardPeriod(ctx, cdp.Type)
|
_, found := k.GetUSDXMintingRewardPeriod(ctx, cdp.Type)
|
||||||
if !found {
|
if !found {
|
||||||
// this collateral type is not incentivized, do nothing
|
// this collateral type is not incentivized, do nothing
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
globalRewardFactor, found := k.GetRewardFactor(ctx, cdp.Type)
|
globalRewardFactor, found := k.GetUSDXMintingRewardFactor(ctx, cdp.Type)
|
||||||
if !found {
|
if !found {
|
||||||
globalRewardFactor = sdk.ZeroDec()
|
globalRewardFactor = sdk.ZeroDec()
|
||||||
}
|
}
|
||||||
claim, found := k.GetClaim(ctx, cdp.Owner)
|
claim, found := k.GetUSDXMintingClaim(ctx, cdp.Owner)
|
||||||
if !found {
|
if !found {
|
||||||
claim = types.NewUSDXMintingClaim(cdp.Owner, sdk.NewCoin(types.USDXMintingRewardDenom, sdk.ZeroInt()), types.RewardIndexes{types.NewRewardIndex(cdp.Type, globalRewardFactor)})
|
claim = types.NewUSDXMintingClaim(cdp.Owner, sdk.NewCoin(types.USDXMintingRewardDenom, sdk.ZeroInt()), types.RewardIndexes{types.NewRewardIndex(cdp.Type, globalRewardFactor)})
|
||||||
k.SetClaim(ctx, claim)
|
k.SetUSDXMintingClaim(ctx, claim)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +189,7 @@ func (k Keeper) SynchronizeReward(ctx sdk.Context, cdp cdptypes.CDP) {
|
|||||||
index, hasRewardIndex := claim.HasRewardIndex(cdp.Type)
|
index, hasRewardIndex := claim.HasRewardIndex(cdp.Type)
|
||||||
if !hasRewardIndex { // this is the owner's first usdx minting reward for this collateral type
|
if !hasRewardIndex { // this is the owner's first usdx minting reward for this collateral type
|
||||||
claim.RewardIndexes = append(claim.RewardIndexes, types.NewRewardIndex(cdp.Type, globalRewardFactor))
|
claim.RewardIndexes = append(claim.RewardIndexes, types.NewRewardIndex(cdp.Type, globalRewardFactor))
|
||||||
k.SetClaim(ctx, claim)
|
k.SetUSDXMintingClaim(ctx, claim)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
userRewardFactor := claim.RewardIndexes[index].RewardFactor
|
userRewardFactor := claim.RewardIndexes[index].RewardFactor
|
||||||
@ -115,21 +198,212 @@ func (k Keeper) SynchronizeReward(ctx sdk.Context, cdp cdptypes.CDP) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
claim.RewardIndexes[index].RewardFactor = globalRewardFactor
|
claim.RewardIndexes[index].RewardFactor = globalRewardFactor
|
||||||
newRewardsAmount := cdp.GetTotalPrincipal().Amount.ToDec().Quo(cdp.InterestFactor).Mul(rewardsAccumulatedFactor).RoundInt()
|
newRewardsAmount := rewardsAccumulatedFactor.Mul(cdp.GetTotalPrincipal().Amount.ToDec()).RoundInt()
|
||||||
if newRewardsAmount.IsZero() {
|
if newRewardsAmount.IsZero() {
|
||||||
k.SetClaim(ctx, claim)
|
k.SetUSDXMintingClaim(ctx, claim)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
newRewardsCoin := sdk.NewCoin(types.USDXMintingRewardDenom, newRewardsAmount)
|
newRewardsCoin := sdk.NewCoin(types.USDXMintingRewardDenom, newRewardsAmount)
|
||||||
claim.Reward = claim.Reward.Add(newRewardsCoin)
|
claim.Reward = claim.Reward.Add(newRewardsCoin)
|
||||||
k.SetClaim(ctx, claim)
|
k.SetUSDXMintingClaim(ctx, claim)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitializeHardSupplyReward initializes the supply-side of a hard liquidity provider claim
|
||||||
|
// by creating the claim and setting the supply reward factor index
|
||||||
|
func (k Keeper) InitializeHardSupplyReward(ctx sdk.Context, deposit hardtypes.Deposit) {
|
||||||
|
var supplyRewardIndexes types.RewardIndexes
|
||||||
|
for _, coin := range deposit.Amount {
|
||||||
|
_, rpFound := k.GetHardSupplyRewardPeriod(ctx, coin.Denom)
|
||||||
|
if !rpFound {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
supplyFactor, foundSupplyFactor := k.GetHardSupplyRewardFactor(ctx, coin.Denom)
|
||||||
|
if !foundSupplyFactor {
|
||||||
|
supplyFactor = sdk.ZeroDec()
|
||||||
|
}
|
||||||
|
|
||||||
|
supplyRewardIndexes = append(supplyRewardIndexes, types.NewRewardIndex(coin.Denom, supplyFactor))
|
||||||
|
}
|
||||||
|
|
||||||
|
claim, found := k.GetHardLiquidityProviderClaim(ctx, deposit.Depositor)
|
||||||
|
if found {
|
||||||
|
// Reset borrow reward indexes
|
||||||
|
claim.BorrowRewardIndexes = types.RewardIndexes{}
|
||||||
|
} else {
|
||||||
|
// Instantiate claim object
|
||||||
|
claim = types.NewHardLiquidityProviderClaim(deposit.Depositor,
|
||||||
|
sdk.NewCoin(types.HardLiquidityRewardDenom, sdk.ZeroInt()),
|
||||||
|
nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
claim.SupplyRewardIndexes = supplyRewardIndexes
|
||||||
|
k.SetHardLiquidityProviderClaim(ctx, claim)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SynchronizeHardSupplyReward updates the claim object by adding any accumulated rewards
|
||||||
|
// and updating the reward index value
|
||||||
|
func (k Keeper) SynchronizeHardSupplyReward(ctx sdk.Context, deposit hardtypes.Deposit) {
|
||||||
|
claim, found := k.GetHardLiquidityProviderClaim(ctx, deposit.Depositor)
|
||||||
|
if !found {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, coin := range deposit.Amount {
|
||||||
|
supplyFactor, found := k.GetHardSupplyRewardFactor(ctx, coin.Denom)
|
||||||
|
if !found {
|
||||||
|
fmt.Printf("\n[LOG]: %s does not have a supply factor", coin.Denom) // TODO: remove before production
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
supplyIndex, hasSupplyRewardIndex := claim.HasSupplyRewardIndex(coin.Denom)
|
||||||
|
if !hasSupplyRewardIndex {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
userRewardFactor := claim.SupplyRewardIndexes[supplyIndex].RewardFactor
|
||||||
|
rewardsAccumulatedFactor := supplyFactor.Sub(userRewardFactor)
|
||||||
|
if rewardsAccumulatedFactor.IsZero() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
claim.SupplyRewardIndexes[supplyIndex].RewardFactor = supplyFactor
|
||||||
|
|
||||||
|
newRewardsAmount := rewardsAccumulatedFactor.Mul(deposit.Amount.AmountOf(coin.Denom).ToDec()).RoundInt()
|
||||||
|
if newRewardsAmount.IsZero() || newRewardsAmount.IsNegative() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newRewardsCoin := sdk.NewCoin(types.HardLiquidityRewardDenom, newRewardsAmount)
|
||||||
|
claim.Reward = claim.Reward.Add(newRewardsCoin)
|
||||||
|
}
|
||||||
|
|
||||||
|
k.SetHardLiquidityProviderClaim(ctx, claim)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitializeHardBorrowReward initializes the borrow-side of a hard liquidity provider claim
|
||||||
|
// by creating the claim and setting the borrow reward factor index
|
||||||
|
func (k Keeper) InitializeHardBorrowReward(ctx sdk.Context, borrow hardtypes.Borrow) {
|
||||||
|
claim, found := k.GetHardLiquidityProviderClaim(ctx, borrow.Borrower)
|
||||||
|
if !found {
|
||||||
|
claim = types.NewHardLiquidityProviderClaim(borrow.Borrower,
|
||||||
|
sdk.NewCoin(types.HardLiquidityRewardDenom, sdk.ZeroInt()),
|
||||||
|
nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var borrowRewardIndexes types.RewardIndexes
|
||||||
|
for _, coin := range borrow.Amount {
|
||||||
|
_, rpFound := k.GetHardBorrowRewardPeriod(ctx, coin.Denom)
|
||||||
|
if !rpFound {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
borrowFactor, foundBorrowFactor := k.GetHardBorrowRewardFactor(ctx, coin.Denom)
|
||||||
|
if !foundBorrowFactor {
|
||||||
|
borrowFactor = sdk.ZeroDec()
|
||||||
|
}
|
||||||
|
|
||||||
|
borrowRewardIndexes = append(borrowRewardIndexes, types.NewRewardIndex(coin.Denom, borrowFactor))
|
||||||
|
}
|
||||||
|
|
||||||
|
claim.BorrowRewardIndexes = borrowRewardIndexes
|
||||||
|
k.SetHardLiquidityProviderClaim(ctx, claim)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SynchronizeHardBorrowReward updates the claim object by adding any accumulated rewards
|
||||||
|
// and updating the reward index value
|
||||||
|
func (k Keeper) SynchronizeHardBorrowReward(ctx sdk.Context, borrow hardtypes.Borrow) {
|
||||||
|
claim, found := k.GetHardLiquidityProviderClaim(ctx, borrow.Borrower)
|
||||||
|
if !found {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, coin := range borrow.Amount {
|
||||||
|
borrowFactor, found := k.GetHardBorrowRewardFactor(ctx, coin.Denom)
|
||||||
|
if !found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
borrowIndex, BorrowRewardIndex := claim.HasBorrowRewardIndex(coin.Denom)
|
||||||
|
if !BorrowRewardIndex {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
userRewardFactor := claim.BorrowRewardIndexes[borrowIndex].RewardFactor
|
||||||
|
rewardsAccumulatedFactor := borrowFactor.Sub(userRewardFactor)
|
||||||
|
if rewardsAccumulatedFactor.IsZero() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
claim.BorrowRewardIndexes[borrowIndex].RewardFactor = borrowFactor
|
||||||
|
|
||||||
|
newRewardsAmount := rewardsAccumulatedFactor.Mul(borrow.Amount.AmountOf(coin.Denom).ToDec()).RoundInt()
|
||||||
|
if newRewardsAmount.IsZero() || newRewardsAmount.IsNegative() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newRewardsCoin := sdk.NewCoin(types.HardLiquidityRewardDenom, newRewardsAmount)
|
||||||
|
claim.Reward = claim.Reward.Add(newRewardsCoin)
|
||||||
|
}
|
||||||
|
|
||||||
|
k.SetHardLiquidityProviderClaim(ctx, claim)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateHardSupplyIndexDenoms adds any new deposit denoms to the claim's supply reward index
|
||||||
|
func (k Keeper) UpdateHardSupplyIndexDenoms(ctx sdk.Context, deposit hardtypes.Deposit) {
|
||||||
|
claim, found := k.GetHardLiquidityProviderClaim(ctx, deposit.Depositor)
|
||||||
|
if !found {
|
||||||
|
claim = types.NewHardLiquidityProviderClaim(deposit.Depositor,
|
||||||
|
sdk.NewCoin(types.HardLiquidityRewardDenom, sdk.ZeroInt()),
|
||||||
|
nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
supplyRewardIndexes := claim.SupplyRewardIndexes
|
||||||
|
for _, coin := range deposit.Amount {
|
||||||
|
_, hasIndex := claim.HasSupplyRewardIndex(coin.Denom)
|
||||||
|
if !hasIndex {
|
||||||
|
supplyFactor, foundSupplyFactor := k.GetHardSupplyRewardFactor(ctx, coin.Denom)
|
||||||
|
if foundSupplyFactor {
|
||||||
|
supplyRewardIndexes = append(supplyRewardIndexes, types.NewRewardIndex(coin.Denom, supplyFactor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(supplyRewardIndexes) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
claim.SupplyRewardIndexes = supplyRewardIndexes
|
||||||
|
k.SetHardLiquidityProviderClaim(ctx, claim)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateHardBorrowIndexDenoms adds any new borrow denoms to the claim's supply reward index
|
||||||
|
func (k Keeper) UpdateHardBorrowIndexDenoms(ctx sdk.Context, borrow hardtypes.Borrow) {
|
||||||
|
claim, found := k.GetHardLiquidityProviderClaim(ctx, borrow.Borrower)
|
||||||
|
if !found {
|
||||||
|
claim = types.NewHardLiquidityProviderClaim(borrow.Borrower,
|
||||||
|
sdk.NewCoin(types.HardLiquidityRewardDenom, sdk.ZeroInt()),
|
||||||
|
nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
borrowRewardIndexes := claim.BorrowRewardIndexes
|
||||||
|
for _, coin := range borrow.Amount {
|
||||||
|
_, hasIndex := claim.HasBorrowRewardIndex(coin.Denom)
|
||||||
|
if !hasIndex {
|
||||||
|
borrowFactor, foundBorrowFactor := k.GetHardBorrowRewardFactor(ctx, coin.Denom)
|
||||||
|
if foundBorrowFactor {
|
||||||
|
borrowRewardIndexes = append(borrowRewardIndexes, types.NewRewardIndex(coin.Denom, borrowFactor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(borrowRewardIndexes) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
claim.BorrowRewardIndexes = borrowRewardIndexes
|
||||||
|
k.SetHardLiquidityProviderClaim(ctx, claim)
|
||||||
|
}
|
||||||
|
|
||||||
// ZeroClaim zeroes out the claim object's rewards and returns the updated claim object
|
// ZeroClaim zeroes out the claim object's rewards and returns the updated claim object
|
||||||
func (k Keeper) ZeroClaim(ctx sdk.Context, claim types.USDXMintingClaim) types.USDXMintingClaim {
|
func (k Keeper) ZeroClaim(ctx sdk.Context, claim types.USDXMintingClaim) types.USDXMintingClaim {
|
||||||
claim.Reward = sdk.NewCoin(claim.Reward.Denom, sdk.ZeroInt())
|
claim.Reward = sdk.NewCoin(claim.Reward.Denom, sdk.ZeroInt())
|
||||||
k.SetClaim(ctx, claim)
|
k.SetUSDXMintingClaim(ctx, claim)
|
||||||
return claim
|
return claim
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,8 +423,8 @@ func (k Keeper) SynchronizeClaim(ctx sdk.Context, claim types.USDXMintingClaim)
|
|||||||
|
|
||||||
// this function assumes a claim already exists, so don't call it if that's not the case
|
// this function assumes a claim already exists, so don't call it if that's not the case
|
||||||
func (k Keeper) synchronizeRewardAndReturnClaim(ctx sdk.Context, cdp cdptypes.CDP) types.USDXMintingClaim {
|
func (k Keeper) synchronizeRewardAndReturnClaim(ctx sdk.Context, cdp cdptypes.CDP) types.USDXMintingClaim {
|
||||||
k.SynchronizeReward(ctx, cdp)
|
k.SynchronizeUSDXMintingReward(ctx, cdp)
|
||||||
claim, _ := k.GetClaim(ctx, cdp.Owner)
|
claim, _ := k.GetUSDXMintingClaim(ctx, cdp.Owner)
|
||||||
return claim
|
return claim
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +1,21 @@
|
|||||||
package keeper_test
|
package keeper_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
tmtime "github.com/tendermint/tendermint/types/time"
|
tmtime "github.com/tendermint/tendermint/types/time"
|
||||||
|
|
||||||
"github.com/kava-labs/kava/app"
|
"github.com/kava-labs/kava/app"
|
||||||
cdpkeeper "github.com/kava-labs/kava/x/cdp/keeper"
|
|
||||||
cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
||||||
|
"github.com/kava-labs/kava/x/hard"
|
||||||
|
hardtypes "github.com/kava-labs/kava/x/hard/types"
|
||||||
"github.com/kava-labs/kava/x/incentive/types"
|
"github.com/kava-labs/kava/x/incentive/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestAccumulateRewards() {
|
func (suite *KeeperTestSuite) TestAccumulateUSDXMintingRewards() {
|
||||||
type args struct {
|
type args struct {
|
||||||
ctype string
|
ctype string
|
||||||
rewardsPerSecond sdk.Coin
|
rewardsPerSecond sdk.Coin
|
||||||
@ -67,7 +65,7 @@ func (suite *KeeperTestSuite) TestAccumulateRewards() {
|
|||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
suite.Run(tc.name, func() {
|
suite.Run(tc.name, func() {
|
||||||
suite.SetupWithCDPGenState()
|
suite.SetupWithGenState()
|
||||||
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
||||||
|
|
||||||
// setup cdp state
|
// setup cdp state
|
||||||
@ -76,28 +74,31 @@ func (suite *KeeperTestSuite) TestAccumulateRewards() {
|
|||||||
|
|
||||||
// setup incentive state
|
// setup incentive state
|
||||||
params := types.NewParams(
|
params := types.NewParams(
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
tc.args.initialTime.Add(time.Hour*24*365*5),
|
tc.args.initialTime.Add(time.Hour*24*365*5),
|
||||||
)
|
)
|
||||||
suite.keeper.SetParams(suite.ctx, params)
|
suite.keeper.SetParams(suite.ctx, params)
|
||||||
suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime)
|
suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime)
|
||||||
suite.keeper.SetRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec())
|
suite.keeper.SetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec())
|
||||||
|
|
||||||
updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed))
|
updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed))
|
||||||
suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime)
|
suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime)
|
||||||
rewardPeriod, found := suite.keeper.GetRewardPeriod(suite.ctx, tc.args.ctype)
|
rewardPeriod, found := suite.keeper.GetUSDXMintingRewardPeriod(suite.ctx, tc.args.ctype)
|
||||||
suite.Require().True(found)
|
suite.Require().True(found)
|
||||||
err := suite.keeper.AccumulateRewards(suite.ctx, rewardPeriod)
|
err := suite.keeper.AccumulateUSDXMintingRewards(suite.ctx, rewardPeriod)
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
rewardFactor, found := suite.keeper.GetRewardFactor(suite.ctx, tc.args.ctype)
|
rewardFactor, found := suite.keeper.GetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype)
|
||||||
suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor)
|
suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) TestSyncRewards() {
|
func (suite *KeeperTestSuite) TestSynchronizeUSDXMintingReward() {
|
||||||
type args struct {
|
type args struct {
|
||||||
ctype string
|
ctype string
|
||||||
rewardsPerSecond sdk.Coin
|
rewardsPerSecond sdk.Coin
|
||||||
@ -143,18 +144,21 @@ func (suite *KeeperTestSuite) TestSyncRewards() {
|
|||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
suite.Run(tc.name, func() {
|
suite.Run(tc.name, func() {
|
||||||
suite.SetupWithCDPGenState()
|
suite.SetupWithGenState()
|
||||||
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
||||||
|
|
||||||
// setup incentive state
|
// setup incentive state
|
||||||
params := types.NewParams(
|
params := types.NewParams(
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.ctype, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
tc.args.initialTime.Add(time.Hour*24*365*5),
|
tc.args.initialTime.Add(time.Hour*24*365*5),
|
||||||
)
|
)
|
||||||
suite.keeper.SetParams(suite.ctx, params)
|
suite.keeper.SetParams(suite.ctx, params)
|
||||||
suite.keeper.SetPreviousAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime)
|
suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, tc.args.ctype, tc.args.initialTime)
|
||||||
suite.keeper.SetRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec())
|
suite.keeper.SetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype, sdk.ZeroDec())
|
||||||
|
|
||||||
// setup account state
|
// setup account state
|
||||||
sk := suite.app.GetSupplyKeeper()
|
sk := suite.app.GetSupplyKeeper()
|
||||||
@ -166,7 +170,7 @@ func (suite *KeeperTestSuite) TestSyncRewards() {
|
|||||||
err := cdpKeeper.AddCdp(suite.ctx, suite.addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype)
|
err := cdpKeeper.AddCdp(suite.ctx, suite.addrs[0], tc.args.initialCollateral, tc.args.initialPrincipal, tc.args.ctype)
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
claim, found := suite.keeper.GetClaim(suite.ctx, suite.addrs[0])
|
claim, found := suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0])
|
||||||
suite.Require().True(found)
|
suite.Require().True(found)
|
||||||
suite.Require().Equal(sdk.ZeroDec(), claim.RewardIndexes[0].RewardFactor)
|
suite.Require().Equal(sdk.ZeroDec(), claim.RewardIndexes[0].RewardFactor)
|
||||||
|
|
||||||
@ -177,9 +181,9 @@ func (suite *KeeperTestSuite) TestSyncRewards() {
|
|||||||
updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t))
|
updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t))
|
||||||
previousBlockTime = updatedBlockTime
|
previousBlockTime = updatedBlockTime
|
||||||
blockCtx := suite.ctx.WithBlockTime(updatedBlockTime)
|
blockCtx := suite.ctx.WithBlockTime(updatedBlockTime)
|
||||||
rewardPeriod, found := suite.keeper.GetRewardPeriod(blockCtx, tc.args.ctype)
|
rewardPeriod, found := suite.keeper.GetUSDXMintingRewardPeriod(blockCtx, tc.args.ctype)
|
||||||
suite.Require().True(found)
|
suite.Require().True(found)
|
||||||
err := suite.keeper.AccumulateRewards(blockCtx, rewardPeriod)
|
err := suite.keeper.AccumulateUSDXMintingRewards(blockCtx, rewardPeriod)
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
}
|
}
|
||||||
updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed))
|
updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed))
|
||||||
@ -187,137 +191,711 @@ func (suite *KeeperTestSuite) TestSyncRewards() {
|
|||||||
cdp, found := cdpKeeper.GetCdpByOwnerAndCollateralType(suite.ctx, suite.addrs[0], tc.args.ctype)
|
cdp, found := cdpKeeper.GetCdpByOwnerAndCollateralType(suite.ctx, suite.addrs[0], tc.args.ctype)
|
||||||
suite.Require().True(found)
|
suite.Require().True(found)
|
||||||
suite.Require().NotPanics(func() {
|
suite.Require().NotPanics(func() {
|
||||||
suite.keeper.SynchronizeReward(suite.ctx, cdp)
|
suite.keeper.SynchronizeUSDXMintingReward(suite.ctx, cdp)
|
||||||
})
|
})
|
||||||
|
|
||||||
rewardFactor, found := suite.keeper.GetRewardFactor(suite.ctx, tc.args.ctype)
|
rewardFactor, found := suite.keeper.GetUSDXMintingRewardFactor(suite.ctx, tc.args.ctype)
|
||||||
suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor)
|
suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor)
|
||||||
|
|
||||||
claim, found = suite.keeper.GetClaim(suite.ctx, suite.addrs[0])
|
claim, found = suite.keeper.GetUSDXMintingClaim(suite.ctx, suite.addrs[0])
|
||||||
fmt.Println(claim)
|
|
||||||
suite.Require().True(found)
|
suite.Require().True(found)
|
||||||
suite.Require().Equal(tc.args.expectedRewardFactor, claim.RewardIndexes[0].RewardFactor)
|
suite.Require().Equal(tc.args.expectedRewardFactor, claim.RewardIndexes[0].RewardFactor)
|
||||||
suite.Require().Equal(tc.args.expectedRewards, claim.Reward)
|
suite.Require().Equal(tc.args.expectedRewards, claim.Reward)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRewardCalculation(t *testing.T) {
|
func (suite *KeeperTestSuite) TestAccumulateHardBorrowRewards() {
|
||||||
|
type args struct {
|
||||||
// Test Params
|
borrow sdk.Coin
|
||||||
ctype := "bnb-a"
|
rewardsPerSecond sdk.Coin
|
||||||
initialTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
initialTime time.Time
|
||||||
rewardsPerSecond := c("ukava", 122_354)
|
timeElapsed int
|
||||||
initialCollateral := c("bnb", 10_000_000_000)
|
expectedRewardFactor sdk.Dec
|
||||||
initialPrincipal := c("usdx", 100_000_000)
|
|
||||||
oneYear := time.Hour * 24 * 365
|
|
||||||
rewardPeriod := types.NewRewardPeriod(
|
|
||||||
true,
|
|
||||||
ctype,
|
|
||||||
initialTime,
|
|
||||||
initialTime.Add(4*oneYear),
|
|
||||||
rewardsPerSecond,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Setup app and module params
|
|
||||||
_, addrs := app.GeneratePrivKeyAddressPairs(5)
|
|
||||||
tApp := app.NewTestApp()
|
|
||||||
ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: initialTime})
|
|
||||||
tApp.InitializeFromGenesisStates(
|
|
||||||
app.NewAuthGenState(addrs[:1], []sdk.Coins{cs(initialCollateral)}),
|
|
||||||
NewPricefeedGenStateMulti(),
|
|
||||||
NewCDPGenStateHighInterest(),
|
|
||||||
NewIncentiveGenState(initialTime, initialTime.Add(oneYear), rewardPeriod),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create a CDP
|
|
||||||
cdpKeeper := tApp.GetCDPKeeper()
|
|
||||||
err := cdpKeeper.AddCdp(
|
|
||||||
ctx,
|
|
||||||
addrs[0],
|
|
||||||
initialCollateral,
|
|
||||||
initialPrincipal,
|
|
||||||
ctype,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Calculate expected cdp reward using iteration
|
|
||||||
|
|
||||||
// Use 10 blocks, each a very long 630720s, to total 6307200s or 1/5th of a year
|
|
||||||
// The cdp stability fee is set to the max value 500%, so this time ensures the debt increases a significant amount (doubles)
|
|
||||||
// High stability fees increase the chance of catching calculation bugs.
|
|
||||||
blockTimes := newRepeatingSliceInt(630720, 10)
|
|
||||||
expectedCDPReward := sdk.ZeroDec() //c(rewardPeriod.RewardsPerSecond.Denom, 0)
|
|
||||||
for _, bt := range blockTimes {
|
|
||||||
ctx = ctx.WithBlockTime(ctx.BlockTime().Add(time.Duration(int(time.Second) * bt)))
|
|
||||||
|
|
||||||
// run cdp and incentive begin blockers to update factors
|
|
||||||
tApp.BeginBlocker(ctx, abci.RequestBeginBlock{})
|
|
||||||
|
|
||||||
// calculate expected cdp reward
|
|
||||||
cdpBlockReward, err := calculateCDPBlockReward(ctx, cdpKeeper, addrs[0], ctype, sdk.NewInt(int64(bt)), rewardPeriod)
|
|
||||||
require.NoError(t, err)
|
|
||||||
expectedCDPReward = expectedCDPReward.Add(cdpBlockReward)
|
|
||||||
}
|
}
|
||||||
|
type test struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}
|
||||||
|
testCases := []test{
|
||||||
|
{
|
||||||
|
"7 seconds",
|
||||||
|
args{
|
||||||
|
borrow: c("bnb", 1000000000000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
timeElapsed: 7,
|
||||||
|
expectedRewardFactor: d("0.000000856478000001"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"1 day",
|
||||||
|
args{
|
||||||
|
borrow: c("bnb", 1000000000000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
timeElapsed: 86400,
|
||||||
|
expectedRewardFactor: d("0.010571385600010177"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"0 seconds",
|
||||||
|
args{
|
||||||
|
borrow: c("bnb", 1000000000000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
timeElapsed: 0,
|
||||||
|
expectedRewardFactor: d("0.0"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
suite.SetupWithGenState()
|
||||||
|
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
||||||
|
|
||||||
// calculate cdp reward using factor
|
// Mint coins to hard module account
|
||||||
cdp, found := cdpKeeper.GetCdpByOwnerAndCollateralType(ctx, addrs[0], ctype)
|
supplyKeeper := suite.app.GetSupplyKeeper()
|
||||||
require.True(t, found)
|
hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000)))
|
||||||
incentiveKeeper := tApp.GetIncentiveKeeper()
|
supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins)
|
||||||
require.NotPanics(t, func() {
|
|
||||||
incentiveKeeper.SynchronizeReward(ctx, cdp)
|
// setup incentive state
|
||||||
|
params := types.NewParams(
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
|
tc.args.initialTime.Add(time.Hour*24*365*5),
|
||||||
|
)
|
||||||
|
suite.keeper.SetParams(suite.ctx, params)
|
||||||
|
suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, tc.args.borrow.Denom, tc.args.initialTime)
|
||||||
|
suite.keeper.SetHardBorrowRewardFactor(suite.ctx, tc.args.borrow.Denom, sdk.ZeroDec())
|
||||||
|
|
||||||
|
// Set up hard state (interest factor for the relevant denom)
|
||||||
|
suite.hardKeeper.SetSupplyInterestFactor(suite.ctx, tc.args.borrow.Denom, sdk.MustNewDecFromStr("1.0"))
|
||||||
|
suite.hardKeeper.SetBorrowInterestFactor(suite.ctx, tc.args.borrow.Denom, sdk.MustNewDecFromStr("1.0"))
|
||||||
|
suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.borrow.Denom, tc.args.initialTime)
|
||||||
|
|
||||||
|
// User deposits and borrows to increase total borrowed amount
|
||||||
|
hardKeeper := suite.app.GetHardKeeper()
|
||||||
|
userAddr := suite.addrs[3]
|
||||||
|
err := hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(sdk.NewCoin(tc.args.borrow.Denom, tc.args.borrow.Amount.Mul(sdk.NewInt(2)))))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
err = hardKeeper.Borrow(suite.ctx, userAddr, sdk.NewCoins(tc.args.borrow))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Set up chain context at future time
|
||||||
|
runAtTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed))
|
||||||
|
runCtx := suite.ctx.WithBlockTime(runAtTime)
|
||||||
|
|
||||||
|
// Run Hard begin blocker in order to update the denom's index factor
|
||||||
|
hard.BeginBlocker(runCtx, suite.hardKeeper)
|
||||||
|
|
||||||
|
rewardPeriod, found := suite.keeper.GetHardBorrowRewardPeriod(runCtx, tc.args.borrow.Denom)
|
||||||
|
suite.Require().True(found)
|
||||||
|
err = suite.keeper.AccumulateHardBorrowRewards(runCtx, rewardPeriod)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
rewardFactor, found := suite.keeper.GetHardBorrowRewardFactor(runCtx, tc.args.borrow.Denom)
|
||||||
|
suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor)
|
||||||
})
|
})
|
||||||
claim, found := incentiveKeeper.GetClaim(ctx, addrs[0])
|
}
|
||||||
require.True(t, found)
|
}
|
||||||
|
|
||||||
// Compare two methods of calculation
|
func (suite *KeeperTestSuite) TestSynchronizeHardBorrowReward() {
|
||||||
relativeError := expectedCDPReward.Sub(claim.Reward.Amount.ToDec()).Quo(expectedCDPReward).Abs()
|
type args struct {
|
||||||
maxError := d("0.0001")
|
borrow sdk.Coin
|
||||||
require.Truef(t, relativeError.LT(maxError),
|
rewardsPerSecond sdk.Coin
|
||||||
"percent diff %s > %s , expected: %s, actual %s,", relativeError, maxError, expectedCDPReward, claim.Reward.Amount,
|
initialTime time.Time
|
||||||
|
blockTimes []int
|
||||||
|
expectedRewardFactor sdk.Dec
|
||||||
|
expectedRewards sdk.Coin
|
||||||
|
}
|
||||||
|
type test struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []test{
|
||||||
|
{
|
||||||
|
"10 blocks",
|
||||||
|
args{
|
||||||
|
borrow: c("bnb", 10000000000), // TODO: 2 decimal diff from TestAccumulateHardBorrowRewards's borrow
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10},
|
||||||
|
expectedRewardFactor: d("0.001223540000173228"),
|
||||||
|
expectedRewards: c("hard", 12235400),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"10 blocks - long block time",
|
||||||
|
args{
|
||||||
|
borrow: c("bnb", 10000000000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400},
|
||||||
|
expectedRewardFactor: d("10.571385603126235340"),
|
||||||
|
expectedRewards: c("hard", 105713856031),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
suite.SetupWithGenState()
|
||||||
|
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
||||||
|
|
||||||
|
// Mint coins to hard module account
|
||||||
|
supplyKeeper := suite.app.GetSupplyKeeper()
|
||||||
|
hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000)))
|
||||||
|
supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins)
|
||||||
|
|
||||||
|
// setup incentive state
|
||||||
|
params := types.NewParams(
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.borrow.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
|
tc.args.initialTime.Add(time.Hour*24*365*5),
|
||||||
)
|
)
|
||||||
|
suite.keeper.SetParams(suite.ctx, params)
|
||||||
|
suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, tc.args.borrow.Denom, tc.args.initialTime)
|
||||||
|
suite.keeper.SetHardBorrowRewardFactor(suite.ctx, tc.args.borrow.Denom, sdk.ZeroDec())
|
||||||
|
|
||||||
|
// Set up hard state (interest factor for the relevant denom)
|
||||||
|
suite.hardKeeper.SetSupplyInterestFactor(suite.ctx, tc.args.borrow.Denom, sdk.MustNewDecFromStr("1.0"))
|
||||||
|
suite.hardKeeper.SetBorrowInterestFactor(suite.ctx, tc.args.borrow.Denom, sdk.MustNewDecFromStr("1.0"))
|
||||||
|
suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.borrow.Denom, tc.args.initialTime)
|
||||||
|
|
||||||
|
// User deposits and borrows to increase total borrowed amount
|
||||||
|
hardKeeper := suite.app.GetHardKeeper()
|
||||||
|
userAddr := suite.addrs[3]
|
||||||
|
err := hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(sdk.NewCoin(tc.args.borrow.Denom, tc.args.borrow.Amount.Mul(sdk.NewInt(2)))))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
err = hardKeeper.Borrow(suite.ctx, userAddr, sdk.NewCoins(tc.args.borrow))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Check that Hard hooks initialized a HardLiquidityProviderClaim
|
||||||
|
claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().Equal(sdk.ZeroDec(), claim.BorrowRewardIndexes[0].RewardFactor)
|
||||||
|
|
||||||
|
// Run accumulator at several intervals
|
||||||
|
var timeElapsed int
|
||||||
|
previousBlockTime := suite.ctx.BlockTime()
|
||||||
|
for _, t := range tc.args.blockTimes {
|
||||||
|
timeElapsed += t
|
||||||
|
updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t))
|
||||||
|
previousBlockTime = updatedBlockTime
|
||||||
|
blockCtx := suite.ctx.WithBlockTime(updatedBlockTime)
|
||||||
|
|
||||||
|
// Run Hard begin blocker for each block ctx to update denom's interest factor
|
||||||
|
hard.BeginBlocker(blockCtx, suite.hardKeeper)
|
||||||
|
|
||||||
|
rewardPeriod, found := suite.keeper.GetHardBorrowRewardPeriod(blockCtx, tc.args.borrow.Denom)
|
||||||
|
suite.Require().True(found)
|
||||||
|
|
||||||
|
err := suite.keeper.AccumulateHardBorrowRewards(blockCtx, rewardPeriod)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
}
|
||||||
|
updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed))
|
||||||
|
suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime)
|
||||||
|
|
||||||
|
// After we've accumulated, run synchronize
|
||||||
|
borrow, found := hardKeeper.GetBorrow(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().NotPanics(func() {
|
||||||
|
suite.keeper.SynchronizeHardBorrowReward(suite.ctx, borrow)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Check that reward factor and claim have been updated as expected
|
||||||
|
rewardFactor, found := suite.keeper.GetHardBorrowRewardFactor(suite.ctx, tc.args.borrow.Denom)
|
||||||
|
suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor)
|
||||||
|
|
||||||
|
claim, found = suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().Equal(tc.args.expectedRewardFactor, claim.BorrowRewardIndexes[0].RewardFactor)
|
||||||
|
suite.Require().Equal(tc.args.expectedRewards, claim.Reward)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculateCDPBlockReward computes the reward that should be distributed to a cdp for the current block.
|
func (suite *KeeperTestSuite) TestAccumulateHardSupplyRewards() {
|
||||||
func calculateCDPBlockReward(ctx sdk.Context, cdpKeeper cdpkeeper.Keeper, owner sdk.AccAddress, ctype string, timeElapsed sdk.Int, rewardPeriod types.RewardPeriod) (sdk.Dec, error) {
|
type args struct {
|
||||||
// Calculate total rewards to distribute this block
|
deposit sdk.Coin
|
||||||
newRewards := timeElapsed.Mul(rewardPeriod.RewardsPerSecond.Amount)
|
rewardsPerSecond sdk.Coin
|
||||||
|
initialTime time.Time
|
||||||
// Calculate cdp's share of total debt
|
timeElapsed int
|
||||||
totalPrincipal := cdpKeeper.GetTotalPrincipal(ctx, ctype, types.PrincipalDenom).ToDec()
|
expectedRewardFactor sdk.Dec
|
||||||
// cdpDebt
|
|
||||||
cdp, found := cdpKeeper.GetCdpByOwnerAndCollateralType(ctx, owner, ctype)
|
|
||||||
if !found {
|
|
||||||
return sdk.Dec{}, fmt.Errorf("couldn't find cdp for owner '%s' and collateral type '%s'", owner, ctype)
|
|
||||||
}
|
}
|
||||||
accumulatedInterest := cdpKeeper.CalculateNewInterest(ctx, cdp)
|
type test struct {
|
||||||
cdpDebt := cdp.Principal.Add(cdp.AccumulatedFees).Add(accumulatedInterest).Amount
|
name string
|
||||||
|
args args
|
||||||
|
}
|
||||||
|
testCases := []test{
|
||||||
|
{
|
||||||
|
"7 seconds",
|
||||||
|
args{
|
||||||
|
deposit: c("bnb", 1000000000000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
timeElapsed: 7,
|
||||||
|
expectedRewardFactor: d("0.000000856478000000"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"1 day",
|
||||||
|
args{
|
||||||
|
deposit: c("bnb", 1000000000000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
timeElapsed: 86400,
|
||||||
|
expectedRewardFactor: d("0.010571385600000000"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"0 seconds",
|
||||||
|
args{
|
||||||
|
deposit: c("bnb", 1000000000000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
timeElapsed: 0,
|
||||||
|
expectedRewardFactor: d("0.0"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
suite.SetupWithGenState()
|
||||||
|
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
||||||
|
|
||||||
// Calculate cdp's reward
|
// Mint coins to hard module account
|
||||||
return newRewards.Mul(cdpDebt).ToDec().Quo(totalPrincipal), nil
|
supplyKeeper := suite.app.GetSupplyKeeper()
|
||||||
|
hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000)))
|
||||||
|
supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins)
|
||||||
|
|
||||||
|
// Set up incentive state
|
||||||
|
params := types.NewParams(
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
|
tc.args.initialTime.Add(time.Hour*24*365*5),
|
||||||
|
)
|
||||||
|
suite.keeper.SetParams(suite.ctx, params)
|
||||||
|
suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime)
|
||||||
|
suite.keeper.SetHardSupplyRewardFactor(suite.ctx, tc.args.deposit.Denom, sdk.ZeroDec())
|
||||||
|
|
||||||
|
// Set up hard state (interest factor for the relevant denom)
|
||||||
|
suite.hardKeeper.SetSupplyInterestFactor(suite.ctx, tc.args.deposit.Denom, sdk.MustNewDecFromStr("1.0"))
|
||||||
|
suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime)
|
||||||
|
|
||||||
|
// User deposits to increase total supplied amount
|
||||||
|
hardKeeper := suite.app.GetHardKeeper()
|
||||||
|
userAddr := suite.addrs[3]
|
||||||
|
err := hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(tc.args.deposit))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Set up chain context at future time
|
||||||
|
runAtTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed))
|
||||||
|
runCtx := suite.ctx.WithBlockTime(runAtTime)
|
||||||
|
|
||||||
|
// Run Hard begin blocker in order to update the denom's index factor
|
||||||
|
hard.BeginBlocker(runCtx, suite.hardKeeper)
|
||||||
|
|
||||||
|
rewardPeriod, found := suite.keeper.GetHardSupplyRewardPeriod(runCtx, tc.args.deposit.Denom)
|
||||||
|
suite.Require().True(found)
|
||||||
|
err = suite.keeper.AccumulateHardSupplyRewards(runCtx, rewardPeriod)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
rewardFactor, found := suite.keeper.GetHardSupplyRewardFactor(runCtx, tc.args.deposit.Denom)
|
||||||
|
suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) SetupWithCDPGenState() {
|
func (suite *KeeperTestSuite) TestSynchronizeHardSupplyReward() {
|
||||||
|
type args struct {
|
||||||
|
deposit sdk.Coin
|
||||||
|
rewardsPerSecond sdk.Coin
|
||||||
|
initialTime time.Time
|
||||||
|
blockTimes []int
|
||||||
|
expectedRewardFactor sdk.Dec
|
||||||
|
expectedRewards sdk.Coin
|
||||||
|
}
|
||||||
|
type test struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []test{
|
||||||
|
{
|
||||||
|
"10 blocks",
|
||||||
|
args{
|
||||||
|
deposit: c("bnb", 10000000000), // TODO: 2 decimal diff
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10},
|
||||||
|
expectedRewardFactor: d("0.001223540000000000"),
|
||||||
|
expectedRewards: c("hard", 12235400),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"10 blocks - long block time",
|
||||||
|
args{
|
||||||
|
deposit: c("bnb", 10000000000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400},
|
||||||
|
expectedRewardFactor: d("10.571385600000000000"),
|
||||||
|
expectedRewards: c("hard", 105713856000),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
suite.SetupWithGenState()
|
||||||
|
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
||||||
|
|
||||||
|
// Mint coins to hard module account
|
||||||
|
supplyKeeper := suite.app.GetSupplyKeeper()
|
||||||
|
hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000)))
|
||||||
|
supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins)
|
||||||
|
|
||||||
|
// setup incentive state
|
||||||
|
params := types.NewParams(
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.deposit.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
|
tc.args.initialTime.Add(time.Hour*24*365*5),
|
||||||
|
)
|
||||||
|
suite.keeper.SetParams(suite.ctx, params)
|
||||||
|
suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime)
|
||||||
|
suite.keeper.SetHardSupplyRewardFactor(suite.ctx, tc.args.deposit.Denom, sdk.ZeroDec())
|
||||||
|
|
||||||
|
// Set up hard state (interest factor for the relevant denom)
|
||||||
|
suite.hardKeeper.SetSupplyInterestFactor(suite.ctx, tc.args.deposit.Denom, sdk.MustNewDecFromStr("1.0"))
|
||||||
|
suite.hardKeeper.SetBorrowInterestFactor(suite.ctx, tc.args.deposit.Denom, sdk.MustNewDecFromStr("1.0"))
|
||||||
|
suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.deposit.Denom, tc.args.initialTime)
|
||||||
|
|
||||||
|
// User deposits and borrows to increase total borrowed amount
|
||||||
|
hardKeeper := suite.app.GetHardKeeper()
|
||||||
|
userAddr := suite.addrs[3]
|
||||||
|
err := hardKeeper.Deposit(suite.ctx, userAddr, sdk.NewCoins(tc.args.deposit))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Check that Hard hooks initialized a HardLiquidityProviderClaim
|
||||||
|
claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().Equal(sdk.ZeroDec(), claim.SupplyRewardIndexes[0].RewardFactor)
|
||||||
|
|
||||||
|
// Run accumulator at several intervals
|
||||||
|
var timeElapsed int
|
||||||
|
previousBlockTime := suite.ctx.BlockTime()
|
||||||
|
for _, t := range tc.args.blockTimes {
|
||||||
|
timeElapsed += t
|
||||||
|
updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t))
|
||||||
|
previousBlockTime = updatedBlockTime
|
||||||
|
blockCtx := suite.ctx.WithBlockTime(updatedBlockTime)
|
||||||
|
|
||||||
|
// Run Hard begin blocker for each block ctx to update denom's interest factor
|
||||||
|
hard.BeginBlocker(blockCtx, suite.hardKeeper)
|
||||||
|
|
||||||
|
rewardPeriod, found := suite.keeper.GetHardSupplyRewardPeriod(blockCtx, tc.args.deposit.Denom)
|
||||||
|
suite.Require().True(found)
|
||||||
|
|
||||||
|
err := suite.keeper.AccumulateHardSupplyRewards(blockCtx, rewardPeriod)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
}
|
||||||
|
updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed))
|
||||||
|
suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime)
|
||||||
|
|
||||||
|
// After we've accumulated, run synchronize
|
||||||
|
deposit, found := hardKeeper.GetDeposit(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().NotPanics(func() {
|
||||||
|
suite.keeper.SynchronizeHardSupplyReward(suite.ctx, deposit)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Check that reward factor and claim have been updated as expected
|
||||||
|
rewardFactor, found := suite.keeper.GetHardSupplyRewardFactor(suite.ctx, tc.args.deposit.Denom)
|
||||||
|
suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor)
|
||||||
|
|
||||||
|
claim, found = suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().Equal(tc.args.expectedRewardFactor, claim.SupplyRewardIndexes[0].RewardFactor)
|
||||||
|
suite.Require().Equal(tc.args.expectedRewards, claim.Reward)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KeeperTestSuite) TestUpdateHardSupplyIndexDenoms() {
|
||||||
|
type args struct {
|
||||||
|
firstDeposit sdk.Coins
|
||||||
|
secondDeposit sdk.Coins
|
||||||
|
rewardsPerSecond sdk.Coin
|
||||||
|
initialTime time.Time
|
||||||
|
expectedSupplyIndexDenoms []string
|
||||||
|
}
|
||||||
|
type test struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []test{
|
||||||
|
{
|
||||||
|
"update adds one supply reward index",
|
||||||
|
args{
|
||||||
|
firstDeposit: cs(c("bnb", 10000000000)),
|
||||||
|
secondDeposit: cs(c("ukava", 10000000000)),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
expectedSupplyIndexDenoms: []string{"bnb", "ukava"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"update adds multiple supply reward indexes",
|
||||||
|
args{
|
||||||
|
firstDeposit: cs(c("bnb", 10000000000)),
|
||||||
|
secondDeposit: cs(c("ukava", 10000000000), c("btcb", 10000000000), c("xrp", 10000000000)),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
expectedSupplyIndexDenoms: []string{"bnb", "ukava", "btcb", "xrp"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"update doesn't add duplicate supply reward index for same denom",
|
||||||
|
args{
|
||||||
|
firstDeposit: cs(c("bnb", 10000000000)),
|
||||||
|
secondDeposit: cs(c("bnb", 5000000000)),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
expectedSupplyIndexDenoms: []string{"bnb"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
suite.SetupWithGenState()
|
||||||
|
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
||||||
|
|
||||||
|
// Mint coins to hard module account
|
||||||
|
supplyKeeper := suite.app.GetSupplyKeeper()
|
||||||
|
hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000)))
|
||||||
|
supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins)
|
||||||
|
|
||||||
|
// Set up generic reward periods
|
||||||
|
var rewardPeriods types.RewardPeriods
|
||||||
|
for _, denom := range tc.args.expectedSupplyIndexDenoms {
|
||||||
|
rewardPeriod := types.NewRewardPeriod(true, denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)
|
||||||
|
rewardPeriods = append(rewardPeriods, rewardPeriod)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup incentive state
|
||||||
|
params := types.NewParams(
|
||||||
|
rewardPeriods, rewardPeriods, rewardPeriods, rewardPeriods,
|
||||||
|
types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
|
tc.args.initialTime.Add(time.Hour*24*365*5),
|
||||||
|
)
|
||||||
|
suite.keeper.SetParams(suite.ctx, params)
|
||||||
|
|
||||||
|
// Set each denom's previous accrual time and supply reward factor
|
||||||
|
for _, denom := range tc.args.expectedSupplyIndexDenoms {
|
||||||
|
suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, denom, tc.args.initialTime)
|
||||||
|
suite.keeper.SetHardSupplyRewardFactor(suite.ctx, denom, sdk.ZeroDec())
|
||||||
|
}
|
||||||
|
|
||||||
|
// User deposits (first time)
|
||||||
|
hardKeeper := suite.app.GetHardKeeper()
|
||||||
|
userAddr := suite.addrs[3]
|
||||||
|
err := hardKeeper.Deposit(suite.ctx, userAddr, tc.args.firstDeposit)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Confirm that a claim was created and populated with the correct supply indexes
|
||||||
|
claimAfterFirstDeposit, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
for _, coin := range tc.args.firstDeposit {
|
||||||
|
_, hasIndex := claimAfterFirstDeposit.HasSupplyRewardIndex(coin.Denom)
|
||||||
|
suite.Require().True(hasIndex)
|
||||||
|
}
|
||||||
|
suite.Require().True(len(claimAfterFirstDeposit.SupplyRewardIndexes) == len(tc.args.firstDeposit))
|
||||||
|
|
||||||
|
// User deposits (second time)
|
||||||
|
err = hardKeeper.Deposit(suite.ctx, userAddr, tc.args.secondDeposit)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Confirm that the claim contains all expected supply indexes
|
||||||
|
claimAfterSecondDeposit, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
for _, denom := range tc.args.expectedSupplyIndexDenoms {
|
||||||
|
_, hasIndex := claimAfterSecondDeposit.HasSupplyRewardIndex(denom)
|
||||||
|
suite.Require().True(hasIndex)
|
||||||
|
}
|
||||||
|
suite.Require().True(len(claimAfterSecondDeposit.SupplyRewardIndexes) == len(tc.args.expectedSupplyIndexDenoms))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() {
|
||||||
|
type args struct {
|
||||||
|
initialDeposit sdk.Coins
|
||||||
|
firstBorrow sdk.Coins
|
||||||
|
secondBorrow sdk.Coins
|
||||||
|
rewardsPerSecond sdk.Coin
|
||||||
|
initialTime time.Time
|
||||||
|
expectedBorrowIndexDenoms []string
|
||||||
|
}
|
||||||
|
type test struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []test{
|
||||||
|
{
|
||||||
|
"update adds one borrow reward index",
|
||||||
|
args{
|
||||||
|
initialDeposit: cs(c("bnb", 10000000000)),
|
||||||
|
firstBorrow: cs(c("bnb", 50000000)),
|
||||||
|
secondBorrow: cs(c("ukava", 500000000)),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
expectedBorrowIndexDenoms: []string{"bnb", "ukava"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"update adds multiple borrow supply reward indexes",
|
||||||
|
args{
|
||||||
|
initialDeposit: cs(c("btcb", 10000000000)),
|
||||||
|
firstBorrow: cs(c("btcb", 50000000)),
|
||||||
|
secondBorrow: cs(c("ukava", 500000000), c("bnb", 50000000000), c("xrp", 50000000000)),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
expectedBorrowIndexDenoms: []string{"btcb", "ukava", "bnb", "xrp"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"update doesn't add duplicate borrow reward index for same denom",
|
||||||
|
args{
|
||||||
|
initialDeposit: cs(c("bnb", 100000000000)),
|
||||||
|
firstBorrow: cs(c("bnb", 50000000)),
|
||||||
|
secondBorrow: cs(c("bnb", 50000000000)),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
expectedBorrowIndexDenoms: []string{"bnb"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
suite.SetupWithGenState()
|
||||||
|
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
||||||
|
|
||||||
|
// Mint coins to hard module account so it can service borrow requests
|
||||||
|
supplyKeeper := suite.app.GetSupplyKeeper()
|
||||||
|
hardMaccCoins := tc.args.firstBorrow.Add(tc.args.secondBorrow...)
|
||||||
|
supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins)
|
||||||
|
|
||||||
|
// Set up generic reward periods
|
||||||
|
var rewardPeriods types.RewardPeriods
|
||||||
|
for _, denom := range tc.args.expectedBorrowIndexDenoms {
|
||||||
|
rewardPeriod := types.NewRewardPeriod(true, denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)
|
||||||
|
rewardPeriods = append(rewardPeriods, rewardPeriod)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup incentive state
|
||||||
|
params := types.NewParams(
|
||||||
|
rewardPeriods, rewardPeriods, rewardPeriods, rewardPeriods,
|
||||||
|
types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
|
tc.args.initialTime.Add(time.Hour*24*365*5),
|
||||||
|
)
|
||||||
|
suite.keeper.SetParams(suite.ctx, params)
|
||||||
|
// Set each initial deposit denom's previous accrual time and supply reward factor
|
||||||
|
for _, coin := range tc.args.initialDeposit {
|
||||||
|
suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, coin.Denom, tc.args.initialTime)
|
||||||
|
suite.keeper.SetHardBorrowRewardFactor(suite.ctx, coin.Denom, sdk.ZeroDec())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set each expected borrow denom's previous accrual time and borrow reward factor
|
||||||
|
for _, denom := range tc.args.expectedBorrowIndexDenoms {
|
||||||
|
suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, denom, tc.args.initialTime)
|
||||||
|
suite.keeper.SetHardBorrowRewardFactor(suite.ctx, denom, sdk.ZeroDec())
|
||||||
|
}
|
||||||
|
|
||||||
|
// User deposits initial funds (so that user can borrow)
|
||||||
|
hardKeeper := suite.app.GetHardKeeper()
|
||||||
|
userAddr := suite.addrs[3]
|
||||||
|
err := hardKeeper.Deposit(suite.ctx, userAddr, tc.args.initialDeposit)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Confirm that claim exists but no borrow reward indexes have been added
|
||||||
|
claimAfterDeposit, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().Equal(0, len(claimAfterDeposit.BorrowRewardIndexes))
|
||||||
|
|
||||||
|
// User borrows (first time)
|
||||||
|
err = hardKeeper.Borrow(suite.ctx, userAddr, tc.args.firstBorrow)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Confirm that claim's borrow reward indexes have been updated
|
||||||
|
claimAfterFirstBorrow, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
for _, coin := range tc.args.firstBorrow {
|
||||||
|
_, hasIndex := claimAfterFirstBorrow.HasBorrowRewardIndex(coin.Denom)
|
||||||
|
suite.Require().True(hasIndex)
|
||||||
|
}
|
||||||
|
suite.Require().True(len(claimAfterFirstBorrow.BorrowRewardIndexes) == len(tc.args.firstBorrow))
|
||||||
|
|
||||||
|
// User borrows (second time)
|
||||||
|
err = hardKeeper.Borrow(suite.ctx, userAddr, tc.args.secondBorrow)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Confirm that claim's borrow reward indexes contain expected values
|
||||||
|
claimAfterSecondBorrow, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[3])
|
||||||
|
suite.Require().True(found)
|
||||||
|
for _, coin := range tc.args.secondBorrow {
|
||||||
|
_, hasIndex := claimAfterSecondBorrow.HasBorrowRewardIndex(coin.Denom)
|
||||||
|
suite.Require().True(hasIndex)
|
||||||
|
}
|
||||||
|
suite.Require().True(len(claimAfterSecondBorrow.BorrowRewardIndexes) == len(tc.args.expectedBorrowIndexDenoms))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KeeperTestSuite) SetupWithGenState() {
|
||||||
tApp := app.NewTestApp()
|
tApp := app.NewTestApp()
|
||||||
ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()})
|
ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()})
|
||||||
|
|
||||||
|
_, addrs := app.GeneratePrivKeyAddressPairs(5)
|
||||||
|
|
||||||
|
authGS := app.NewAuthGenState(
|
||||||
|
[]sdk.AccAddress{addrs[3]},
|
||||||
|
[]sdk.Coins{
|
||||||
|
sdk.NewCoins(
|
||||||
|
sdk.NewCoin("bnb", sdk.NewInt(1000000000000000)),
|
||||||
|
sdk.NewCoin("ukava", sdk.NewInt(1000000000000000)),
|
||||||
|
sdk.NewCoin("btcb", sdk.NewInt(1000000000000000)),
|
||||||
|
sdk.NewCoin("xrp", sdk.NewInt(1000000000000000)),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
tApp.InitializeFromGenesisStates(
|
tApp.InitializeFromGenesisStates(
|
||||||
|
authGS,
|
||||||
NewPricefeedGenStateMulti(),
|
NewPricefeedGenStateMulti(),
|
||||||
NewCDPGenStateMulti(),
|
NewCDPGenStateMulti(),
|
||||||
|
NewHardGenStateMulti(),
|
||||||
)
|
)
|
||||||
_, addrs := app.GeneratePrivKeyAddressPairs(5)
|
|
||||||
keeper := tApp.GetIncentiveKeeper()
|
keeper := tApp.GetIncentiveKeeper()
|
||||||
|
hardKeeper := tApp.GetHardKeeper()
|
||||||
suite.app = tApp
|
suite.app = tApp
|
||||||
suite.ctx = ctx
|
suite.ctx = ctx
|
||||||
suite.keeper = keeper
|
suite.keeper = keeper
|
||||||
|
suite.hardKeeper = hardKeeper
|
||||||
suite.addrs = addrs
|
suite.addrs = addrs
|
||||||
}
|
}
|
||||||
|
|
||||||
// newRepeatingSliceInt creates a slice of the specified length containing a single repeating element.
|
|
||||||
func newRepeatingSliceInt(element int, length int) []int {
|
|
||||||
slice := make([]int, length)
|
|
||||||
for i := 0; i < length; i++ {
|
|
||||||
slice[i] = element
|
|
||||||
}
|
|
||||||
return slice
|
|
||||||
}
|
|
||||||
|
@ -17,24 +17,66 @@ import (
|
|||||||
func DecodeStore(cdc *codec.Codec, kvA, kvB kv.Pair) string {
|
func DecodeStore(cdc *codec.Codec, kvA, kvB kv.Pair) string {
|
||||||
switch {
|
switch {
|
||||||
|
|
||||||
case bytes.Equal(kvA.Key[:1], types.ClaimKeyPrefix):
|
case bytes.Equal(kvA.Key[:1], types.USDXMintingClaimKeyPrefix):
|
||||||
var claimA, claimB types.USDXMintingClaim
|
var claimA, claimB types.USDXMintingClaim
|
||||||
cdc.MustUnmarshalBinaryBare(kvA.Value, &claimA)
|
cdc.MustUnmarshalBinaryBare(kvA.Value, &claimA)
|
||||||
cdc.MustUnmarshalBinaryBare(kvB.Value, &claimB)
|
cdc.MustUnmarshalBinaryBare(kvB.Value, &claimB)
|
||||||
return fmt.Sprintf("%v\n%v", claimA, claimB)
|
return fmt.Sprintf("%v\n%v", claimA, claimB)
|
||||||
|
|
||||||
case bytes.Equal(kvA.Key[:1], types.BlockTimeKey):
|
case bytes.Equal(kvA.Key[:1], types.PreviousUSDXMintingRewardAccrualTimeKeyPrefix):
|
||||||
var timeA, timeB time.Time
|
var timeA, timeB time.Time
|
||||||
cdc.MustUnmarshalBinaryBare(kvA.Value, &timeA)
|
cdc.MustUnmarshalBinaryBare(kvA.Value, &timeA)
|
||||||
cdc.MustUnmarshalBinaryBare(kvB.Value, &timeB)
|
cdc.MustUnmarshalBinaryBare(kvB.Value, &timeB)
|
||||||
return fmt.Sprintf("%s\n%s", timeA, timeB)
|
return fmt.Sprintf("%s\n%s", timeA, timeB)
|
||||||
|
|
||||||
case bytes.Equal(kvA.Key[:1], types.RewardFactorKey):
|
case bytes.Equal(kvA.Key[:1], types.USDXMintingRewardFactorKeyPrefix):
|
||||||
var factorA, factorB sdk.Dec
|
var factorA, factorB sdk.Dec
|
||||||
cdc.MustUnmarshalBinaryBare(kvA.Value, &factorA)
|
cdc.MustUnmarshalBinaryBare(kvA.Value, &factorA)
|
||||||
cdc.MustUnmarshalBinaryBare(kvB.Value, &factorB)
|
cdc.MustUnmarshalBinaryBare(kvB.Value, &factorB)
|
||||||
return fmt.Sprintf("%s\n%s", factorA, factorB)
|
return fmt.Sprintf("%s\n%s", factorA, factorB)
|
||||||
|
|
||||||
|
// case bytes.Equal(kvA.Key[:1], types.HardLiquidityClaimKeyPrefix):
|
||||||
|
// var claimA, claimB types.HardLiquidityProviderClaim
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvA.Value, &claimA)
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvB.Value, &claimB)
|
||||||
|
// return fmt.Sprintf("%v\n%v", claimA, claimB)
|
||||||
|
|
||||||
|
// case bytes.Equal(kvA.Key[:1], types.PreviousHardSupplyRewardAccrualTimeKeyPrefix):
|
||||||
|
// var timeA, timeB time.Time
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvA.Value, &timeA)
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvB.Value, &timeB)
|
||||||
|
// return fmt.Sprintf("%s\n%s", timeA, timeB)
|
||||||
|
|
||||||
|
// case bytes.Equal(kvA.Key[:1], types.HardSupplyRewardFactorKeyPrefix):
|
||||||
|
// var factorA, factorB sdk.Dec
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvA.Value, &factorA)
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvB.Value, &factorB)
|
||||||
|
// return fmt.Sprintf("%s\n%s", factorA, factorB)
|
||||||
|
|
||||||
|
// case bytes.Equal(kvA.Key[:1], types.PreviousHardBorrowRewardAccrualTimeKeyPrefix):
|
||||||
|
// var timeA, timeB time.Time
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvA.Value, &timeA)
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvB.Value, &timeB)
|
||||||
|
// return fmt.Sprintf("%s\n%s", timeA, timeB)
|
||||||
|
|
||||||
|
// case bytes.Equal(kvA.Key[:1], types.HardSupplyRewardFactorKeyPrefix):
|
||||||
|
// var factorA, factorB sdk.Dec
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvA.Value, &factorA)
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvB.Value, &factorB)
|
||||||
|
// return fmt.Sprintf("%s\n%s", factorA, factorB)
|
||||||
|
|
||||||
|
// case bytes.Equal(kvA.Key[:1], types.PreviousHardDelegatorRewardAccrualTimeKeyPrefix):
|
||||||
|
// var timeA, timeB time.Time
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvA.Value, &timeA)
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvB.Value, &timeB)
|
||||||
|
// return fmt.Sprintf("%s\n%s", timeA, timeB)
|
||||||
|
|
||||||
|
// case bytes.Equal(kvA.Key[:1], types.HardDelegatorRewardFactorKeyPrefix):
|
||||||
|
// var factorA, factorB sdk.Dec
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvA.Value, &factorA)
|
||||||
|
// cdc.MustUnmarshalBinaryBare(kvB.Value, &factorB)
|
||||||
|
// return fmt.Sprintf("%s\n%s", factorA, factorB)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("invalid %s key prefix %X", types.ModuleName, kvA.Key[:1]))
|
panic(fmt.Sprintf("invalid %s key prefix %X", types.ModuleName, kvA.Key[:1]))
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,16 @@ func TestDecodeDistributionStore(t *testing.T) {
|
|||||||
factor := sdk.ZeroDec()
|
factor := sdk.ZeroDec()
|
||||||
|
|
||||||
kvPairs := kv.Pairs{
|
kvPairs := kv.Pairs{
|
||||||
kv.Pair{Key: types.ClaimKeyPrefix, Value: cdc.MustMarshalBinaryBare(claim)},
|
kv.Pair{Key: types.USDXMintingClaimKeyPrefix, Value: cdc.MustMarshalBinaryBare(claim)},
|
||||||
kv.Pair{Key: []byte(types.BlockTimeKey), Value: cdc.MustMarshalBinaryBare(prevBlockTime)},
|
kv.Pair{Key: []byte(types.PreviousUSDXMintingRewardAccrualTimeKeyPrefix), Value: cdc.MustMarshalBinaryBare(prevBlockTime)},
|
||||||
kv.Pair{Key: []byte(types.RewardFactorKey), Value: cdc.MustMarshalBinaryBare(factor)},
|
kv.Pair{Key: []byte(types.USDXMintingRewardFactorKeyPrefix), Value: cdc.MustMarshalBinaryBare(factor)},
|
||||||
|
// kv.Pair{Key: types.HardLiquidityClaimKeyPrefix, Value: cdc.MustMarshalBinaryBare(claim)},
|
||||||
|
// kv.Pair{Key: []byte(types.HardSupplyRewardFactorKeyPrefix), Value: cdc.MustMarshalBinaryBare(factor)},
|
||||||
|
// kv.Pair{Key: []byte(types.PreviousHardSupplyRewardAccrualTimeKeyPrefix), Value: cdc.MustMarshalBinaryBare(prevBlockTime)},
|
||||||
|
// kv.Pair{Key: []byte(types.HardBorrowRewardFactorKeyPrefix), Value: cdc.MustMarshalBinaryBare(factor)},
|
||||||
|
// kv.Pair{Key: []byte(types.PreviousHardBorrowRewardAccrualTimeKeyPrefix), Value: cdc.MustMarshalBinaryBare(prevBlockTime)},
|
||||||
|
// kv.Pair{Key: []byte(types.HardDelegatorRewardFactorKeyPrefix), Value: cdc.MustMarshalBinaryBare(factor)},
|
||||||
|
// kv.Pair{Key: []byte(types.PreviousHardDelegatorRewardAccrualTimeKeyPrefix), Value: cdc.MustMarshalBinaryBare(prevBlockTime)},
|
||||||
kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}},
|
kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,9 +47,16 @@ func TestDecodeDistributionStore(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
expectedLog string
|
expectedLog string
|
||||||
}{
|
}{
|
||||||
{"Claim", fmt.Sprintf("%v\n%v", claim, claim)},
|
{"USDXMintingClaim", fmt.Sprintf("%v\n%v", claim, claim)},
|
||||||
{"PreviousBlockTime", fmt.Sprintf("%v\n%v", prevBlockTime, prevBlockTime)},
|
{"PreviousUSDXMintingRewardAccrualTime", fmt.Sprintf("%v\n%v", prevBlockTime, prevBlockTime)},
|
||||||
{"RewardFactor", fmt.Sprintf("%v\n%v", factor, factor)},
|
{"USDXMintingRewardFactor", fmt.Sprintf("%v\n%v", factor, factor)},
|
||||||
|
// {"HardLiquidityClaim", fmt.Sprintf("%v\n%v", claim, claim)},
|
||||||
|
// {"PreviousHardSupplyRewardAccrualTime", fmt.Sprintf("%v\n%v", prevBlockTime, prevBlockTime)},
|
||||||
|
// {"HardSupplyRewardFactor", fmt.Sprintf("%v\n%v", factor, factor)},
|
||||||
|
// {"PreviousHardBorrowRewardAccrualTime", fmt.Sprintf("%v\n%v", prevBlockTime, prevBlockTime)},
|
||||||
|
// {"HardBorrowRewardFactor", fmt.Sprintf("%v\n%v", factor, factor)},
|
||||||
|
// {"PreviousHardDelegatorRewardAccrualTime", fmt.Sprintf("%v\n%v", prevBlockTime, prevBlockTime)},
|
||||||
|
// {"HardSupplyDelegatorFactor", fmt.Sprintf("%v\n%v", factor, factor)},
|
||||||
{"other", ""},
|
{"other", ""},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
|
@ -8,40 +8,91 @@ import (
|
|||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// USDXMintingClaim stores the usdx mintng rewards that can be claimed by owner
|
const (
|
||||||
type USDXMintingClaim struct {
|
USDXMintingClaimType = "usdx_minting"
|
||||||
|
HardLiquidityProviderClaimType = "hard_liquidity_provider"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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"`
|
Owner sdk.AccAddress `json:"owner" yaml:"owner"`
|
||||||
Reward sdk.Coin `json:"reward" yaml:"reward"`
|
Reward sdk.Coin `json:"reward" yaml:"reward"`
|
||||||
RewardIndexes RewardIndexes `json:"reward_indexes" yaml:"reward_indexes"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUSDXMintingClaim returns a new USDXMintingClaim
|
// GetOwner is a getter for Claim Owner
|
||||||
func NewUSDXMintingClaim(owner sdk.AccAddress, reward sdk.Coin, rewardIndexes RewardIndexes) USDXMintingClaim {
|
func (c BaseClaim) GetOwner() sdk.AccAddress { return c.Owner }
|
||||||
return USDXMintingClaim{
|
|
||||||
Owner: owner,
|
|
||||||
Reward: reward,
|
|
||||||
RewardIndexes: rewardIndexes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate performs a basic check of a Claim fields.
|
// GetReward is a getter for Claim Reward
|
||||||
func (c USDXMintingClaim) Validate() error {
|
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() {
|
if c.Owner.Empty() {
|
||||||
return errors.New("claim owner cannot be empty")
|
return errors.New("claim owner cannot be empty")
|
||||||
}
|
}
|
||||||
if !c.Reward.IsValid() {
|
if !c.Reward.IsValid() {
|
||||||
return fmt.Errorf("invalid reward amount: %s", c.Reward)
|
return fmt.Errorf("invalid reward amount: %s", c.Reward)
|
||||||
}
|
}
|
||||||
return c.RewardIndexes.Validate()
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements fmt.Stringer
|
||||||
|
func (c BaseClaim) 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 type, used to identify auctions in event attributes
|
||||||
|
func (c USDXMintingClaim) GetType() string { return USDXMintingClaimType }
|
||||||
|
|
||||||
|
// 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
|
// String implements fmt.Stringer
|
||||||
func (c USDXMintingClaim) String() string {
|
func (c USDXMintingClaim) String() string {
|
||||||
return fmt.Sprintf(`Claim:
|
return fmt.Sprintf(`%s
|
||||||
Owner: %s,
|
|
||||||
Reward: %s,
|
|
||||||
Reward Indexes: %s,
|
Reward Indexes: %s,
|
||||||
`, c.Owner, c.Reward, c.RewardIndexes)
|
`, c.BaseClaim, c.RewardIndexes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasRewardIndex check if a claim has a reward index for the input collateral type
|
// HasRewardIndex check if a claim has a reward index for the input collateral type
|
||||||
@ -54,7 +105,7 @@ func (c USDXMintingClaim) HasRewardIndex(collateralType string) (int64, bool) {
|
|||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// USDXMintingClaims array of USDXMintingClaim
|
// USDXMintingClaims slice of USDXMintingClaim
|
||||||
type USDXMintingClaims []USDXMintingClaim
|
type USDXMintingClaims []USDXMintingClaim
|
||||||
|
|
||||||
// Validate checks if all the claims are valid and there are no duplicated
|
// Validate checks if all the claims are valid and there are no duplicated
|
||||||
@ -69,6 +120,106 @@ func (cs USDXMintingClaims) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HardLiquidityProviderClaim stores the hard liquidity provider rewards that can be claimed by owner
|
||||||
|
type HardLiquidityProviderClaim struct {
|
||||||
|
BaseClaim `json:"base_claim" yaml:"base_claim"`
|
||||||
|
SupplyRewardIndexes RewardIndexes `json:"supply_reward_indexes" yaml:"supply_reward_indexes"`
|
||||||
|
BorrowRewardIndexes RewardIndexes `json:"borrow_reward_indexes" yaml:"borrow_reward_indexes"`
|
||||||
|
DelegationRewardIndexes RewardIndexes `json:"delegation_reward_indexes" yaml:"delegation_reward_indexes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHardLiquidityProviderClaim returns a new HardLiquidityProviderClaim
|
||||||
|
func NewHardLiquidityProviderClaim(owner sdk.AccAddress, reward sdk.Coin, supplyRewardIndexes,
|
||||||
|
borrowRewardIndexes, delegationRewardIndexes RewardIndexes) HardLiquidityProviderClaim {
|
||||||
|
return HardLiquidityProviderClaim{
|
||||||
|
BaseClaim: BaseClaim{
|
||||||
|
Owner: owner,
|
||||||
|
Reward: reward,
|
||||||
|
},
|
||||||
|
SupplyRewardIndexes: supplyRewardIndexes,
|
||||||
|
BorrowRewardIndexes: borrowRewardIndexes,
|
||||||
|
DelegationRewardIndexes: delegationRewardIndexes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetType returns the claim type, used to identify auctions in event attributes
|
||||||
|
func (c HardLiquidityProviderClaim) GetType() string { return HardLiquidityProviderClaimType }
|
||||||
|
|
||||||
|
// 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.DelegationRewardIndexes.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.BaseClaim.Validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements fmt.Stringer
|
||||||
|
func (c HardLiquidityProviderClaim) String() string {
|
||||||
|
return fmt.Sprintf(`%s
|
||||||
|
Supply Reward Indexes: %s,
|
||||||
|
Borrow Reward Indexes: %s,
|
||||||
|
Delegation Reward Indexes: %s,
|
||||||
|
`, c.BaseClaim, c.SupplyRewardIndexes, c.BorrowRewardIndexes, c.DelegationRewardIndexes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasDelegationRewardIndex check if a claim has a delegation reward index for the input collateral type
|
||||||
|
func (c HardLiquidityProviderClaim) HasDelegationRewardIndex(collateralType string) (int64, bool) {
|
||||||
|
for index, ri := range c.SupplyRewardIndexes {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------- Subcomponents of Custom Claim Types --------------
|
||||||
|
|
||||||
|
// TODO: refactor RewardPeriod name from 'collateralType' to 'denom'
|
||||||
|
|
||||||
// RewardIndex stores reward accumulation information
|
// RewardIndex stores reward accumulation information
|
||||||
type RewardIndex struct {
|
type RewardIndex struct {
|
||||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||||
|
@ -28,7 +28,11 @@ func TestClaimsValidate(t *testing.T) {
|
|||||||
{
|
{
|
||||||
"invalid owner",
|
"invalid owner",
|
||||||
USDXMintingClaims{
|
USDXMintingClaims{
|
||||||
{Owner: nil},
|
USDXMintingClaim{
|
||||||
|
BaseClaim: BaseClaim{
|
||||||
|
Owner: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
@ -36,18 +40,22 @@ func TestClaimsValidate(t *testing.T) {
|
|||||||
"invalid reward",
|
"invalid reward",
|
||||||
USDXMintingClaims{
|
USDXMintingClaims{
|
||||||
{
|
{
|
||||||
|
BaseClaim: BaseClaim{
|
||||||
Owner: owner,
|
Owner: owner,
|
||||||
Reward: sdk.Coin{Denom: "", Amount: sdk.ZeroInt()},
|
Reward: sdk.Coin{Denom: "", Amount: sdk.ZeroInt()},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"invalid collateral type",
|
"invalid collateral type",
|
||||||
USDXMintingClaims{
|
USDXMintingClaims{
|
||||||
{
|
{
|
||||||
|
BaseClaim: BaseClaim{
|
||||||
Owner: owner,
|
Owner: owner,
|
||||||
Reward: sdk.NewCoin("bnb", sdk.OneInt()),
|
Reward: sdk.NewCoin("bnb", sdk.OneInt()),
|
||||||
|
},
|
||||||
RewardIndexes: []RewardIndex{{"", sdk.ZeroDec()}},
|
RewardIndexes: []RewardIndex{{"", sdk.ZeroDec()}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -14,5 +14,10 @@ func init() {
|
|||||||
|
|
||||||
// RegisterCodec registers the necessary types for incentive module
|
// RegisterCodec registers the necessary types for incentive module
|
||||||
func RegisterCodec(cdc *codec.Codec) {
|
func RegisterCodec(cdc *codec.Codec) {
|
||||||
|
cdc.RegisterInterface((*Claim)(nil), nil)
|
||||||
|
cdc.RegisterConcrete(USDXMintingClaim{}, "incentive/USDXMintingClaim", nil)
|
||||||
|
cdc.RegisterConcrete(HardLiquidityProviderClaim{}, "incentive/HardLiquidityProviderClaim", nil)
|
||||||
|
|
||||||
|
// Register msgs
|
||||||
cdc.RegisterConcrete(MsgClaimUSDXMintingReward{}, "incentive/MsgClaimUSDXMintingReward", nil)
|
cdc.RegisterConcrete(MsgClaimUSDXMintingReward{}, "incentive/MsgClaimUSDXMintingReward", nil)
|
||||||
}
|
}
|
||||||
|
@ -6,23 +6,31 @@ import (
|
|||||||
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
|
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||||
|
|
||||||
cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
||||||
|
hardtypes "github.com/kava-labs/kava/x/hard/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SupplyKeeper defines the expected supply keeper for module accounts
|
// SupplyKeeper defines the expected supply keeper for module accounts
|
||||||
type SupplyKeeper interface {
|
type SupplyKeeper interface {
|
||||||
GetModuleAccount(ctx sdk.Context, name string) supplyexported.ModuleAccountI
|
GetModuleAccount(ctx sdk.Context, name string) supplyexported.ModuleAccountI
|
||||||
|
|
||||||
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
|
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// CdpKeeper defines the expected cdp keeper for interacting with cdps
|
// CdpKeeper defines the expected cdp keeper for interacting with cdps
|
||||||
type CdpKeeper interface {
|
type CdpKeeper interface {
|
||||||
|
GetInterestFactor(ctx sdk.Context, collateralType string) (sdk.Dec, bool)
|
||||||
GetTotalPrincipal(ctx sdk.Context, collateralType string, principalDenom string) (total sdk.Int)
|
GetTotalPrincipal(ctx sdk.Context, collateralType string, principalDenom string) (total sdk.Int)
|
||||||
GetCdpByOwnerAndCollateralType(ctx sdk.Context, owner sdk.AccAddress, collateralType string) (cdptypes.CDP, bool)
|
GetCdpByOwnerAndCollateralType(ctx sdk.Context, owner sdk.AccAddress, collateralType string) (cdptypes.CDP, bool)
|
||||||
GetInterestFactor(ctx sdk.Context, collateralType string) (sdk.Dec, bool)
|
|
||||||
GetCollateral(ctx sdk.Context, collateralType string) (cdptypes.CollateralParam, bool)
|
GetCollateral(ctx sdk.Context, collateralType string) (cdptypes.CollateralParam, bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HardKeeper defines the expected hard keeper for interacting with Hard protocol
|
||||||
|
type HardKeeper interface {
|
||||||
|
GetSupplyInterestFactor(ctx sdk.Context, denom string) (sdk.Dec, bool)
|
||||||
|
GetBorrowInterestFactor(ctx sdk.Context, denom string) (sdk.Dec, bool)
|
||||||
|
GetBorrowedCoins(ctx sdk.Context) (coins sdk.Coins, found bool)
|
||||||
|
GetSuppliedCoins(ctx sdk.Context) (coins sdk.Coins, found bool)
|
||||||
|
}
|
||||||
|
|
||||||
// AccountKeeper defines the expected keeper interface for interacting with account
|
// AccountKeeper defines the expected keeper interface for interacting with account
|
||||||
type AccountKeeper interface {
|
type AccountKeeper interface {
|
||||||
GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account
|
GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account
|
||||||
@ -34,3 +42,13 @@ type CDPHooks interface {
|
|||||||
AfterCDPCreated(ctx sdk.Context, cdp cdptypes.CDP)
|
AfterCDPCreated(ctx sdk.Context, cdp cdptypes.CDP)
|
||||||
BeforeCDPModified(ctx sdk.Context, cdp cdptypes.CDP)
|
BeforeCDPModified(ctx sdk.Context, cdp cdptypes.CDP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HARDHooks event hooks for other keepers to run code in response to HARD modifications
|
||||||
|
type HARDHooks interface {
|
||||||
|
AfterDepositCreated(ctx sdk.Context, deposit hardtypes.Deposit)
|
||||||
|
BeforeDepositModified(ctx sdk.Context, deposit hardtypes.Deposit)
|
||||||
|
AfterDepositModified(ctx sdk.Context, deposit hardtypes.Deposit)
|
||||||
|
AfterBorrowCreated(ctx sdk.Context, borrow hardtypes.Borrow)
|
||||||
|
BeforeBorrowModified(ctx sdk.Context, borrow hardtypes.Borrow)
|
||||||
|
AfterBorrowModified(ctx sdk.Context, deposit hardtypes.Deposit)
|
||||||
|
}
|
||||||
|
@ -89,9 +89,6 @@ func (gats GenesisAccumulationTimes) Validate() error {
|
|||||||
|
|
||||||
// Validate performs validation of GenesisAccumulationTime
|
// Validate performs validation of GenesisAccumulationTime
|
||||||
func (gat GenesisAccumulationTime) Validate() error {
|
func (gat GenesisAccumulationTime) Validate() error {
|
||||||
if gat.RewardFactor == (sdk.Dec{}) {
|
|
||||||
return fmt.Errorf("reward factor not initialized for %s", gat.CollateralType)
|
|
||||||
}
|
|
||||||
if gat.RewardFactor.LT(sdk.ZeroDec()) {
|
if gat.RewardFactor.LT(sdk.ZeroDec()) {
|
||||||
return fmt.Errorf("reward factor should be ≥ 0.0, is %s for %s", gat.RewardFactor, gat.CollateralType)
|
return fmt.Errorf("reward factor should be ≥ 0.0, is %s for %s", gat.RewardFactor, gat.CollateralType)
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tendermint/tendermint/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenesisStateValidate(t *testing.T) {
|
func TestGenesisStateValidate(t *testing.T) {
|
||||||
@ -44,7 +42,24 @@ func TestGenesisStateValidate(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "valid",
|
name: "valid",
|
||||||
args: args{
|
args: args{
|
||||||
params: NewParams(RewardPeriods{NewRewardPeriod(true, "bnb-a", time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 10, 15, 14, 0, 0, 0, time.UTC), sdk.NewCoin("ukava", sdk.NewInt(25000)))}, Multipliers{NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33"))}, time.Date(2025, 10, 15, 14, 0, 0, 0, time.UTC)),
|
params: NewParams(
|
||||||
|
RewardPeriods{
|
||||||
|
NewRewardPeriod(
|
||||||
|
true,
|
||||||
|
"bnb-a",
|
||||||
|
time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
time.Date(2024, 10, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
sdk.NewCoin("ukava", sdk.NewInt(25000)),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
DefaultRewardPeriods,
|
||||||
|
DefaultRewardPeriods,
|
||||||
|
DefaultRewardPeriods,
|
||||||
|
Multipliers{
|
||||||
|
NewMultiplier(Small, 1, sdk.MustNewDecFromStr("0.33")),
|
||||||
|
},
|
||||||
|
time.Date(2025, 10, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
),
|
||||||
genAccTimes: GenesisAccumulationTimes{GenesisAccumulationTime{
|
genAccTimes: GenesisAccumulationTimes{GenesisAccumulationTime{
|
||||||
CollateralType: "bnb-a",
|
CollateralType: "bnb-a",
|
||||||
PreviousAccumulationTime: time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC),
|
PreviousAccumulationTime: time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC),
|
||||||
@ -52,9 +67,10 @@ func TestGenesisStateValidate(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
claims: USDXMintingClaims{
|
claims: USDXMintingClaims{
|
||||||
{
|
{
|
||||||
|
BaseClaim: BaseClaim{
|
||||||
Owner: sdk.AccAddress(crypto.AddressHash([]byte("KavaTestUser1"))),
|
Owner: sdk.AccAddress(crypto.AddressHash([]byte("KavaTestUser1"))),
|
||||||
Reward: sdk.NewCoin("ukava", sdk.NewInt(100000000)),
|
Reward: sdk.NewCoin("ukava", sdk.NewInt(100000000)),
|
||||||
|
},
|
||||||
RewardIndexes: []RewardIndex{
|
RewardIndexes: []RewardIndex{
|
||||||
{
|
{
|
||||||
CollateralType: "bnb-a",
|
CollateralType: "bnb-a",
|
||||||
@ -86,24 +102,6 @@ func TestGenesisStateValidate(t *testing.T) {
|
|||||||
contains: "reward factor should be ≥ 0.0",
|
contains: "reward factor should be ≥ 0.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "invalid genesis accumulation time",
|
|
||||||
args: args{
|
|
||||||
params: DefaultParams(),
|
|
||||||
genAccTimes: GenesisAccumulationTimes{
|
|
||||||
{
|
|
||||||
CollateralType: "btcb-a",
|
|
||||||
PreviousAccumulationTime: time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC),
|
|
||||||
RewardFactor: sdk.Dec{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
claims: DefaultClaims,
|
|
||||||
},
|
|
||||||
errArgs: errArgs{
|
|
||||||
expectPass: false,
|
|
||||||
contains: "reward factor not initialized",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "invalid claim",
|
name: "invalid claim",
|
||||||
args: args{
|
args: args{
|
||||||
@ -111,9 +109,10 @@ func TestGenesisStateValidate(t *testing.T) {
|
|||||||
genAccTimes: DefaultGenesisAccumulationTimes,
|
genAccTimes: DefaultGenesisAccumulationTimes,
|
||||||
claims: USDXMintingClaims{
|
claims: USDXMintingClaims{
|
||||||
{
|
{
|
||||||
|
BaseClaim: BaseClaim{
|
||||||
Owner: sdk.AccAddress{},
|
Owner: sdk.AccAddress{},
|
||||||
Reward: sdk.NewCoin("ukava", sdk.NewInt(100000000)),
|
Reward: sdk.NewCoin("ukava", sdk.NewInt(100000000)),
|
||||||
|
},
|
||||||
RewardIndexes: []RewardIndex{
|
RewardIndexes: []RewardIndex{
|
||||||
{
|
{
|
||||||
CollateralType: "bnb-a",
|
CollateralType: "bnb-a",
|
||||||
|
@ -17,11 +17,23 @@ const (
|
|||||||
QuerierRoute = ModuleName
|
QuerierRoute = ModuleName
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: Refactor so that each incentive type has:
|
||||||
|
// 1. [Incentive]ClaimKeyPrefix
|
||||||
|
// 2. [Incentve]AccumulatorKeyPrefix { PreviousAccrualTime block.Time, IndexFactors types.IndexFactors }
|
||||||
|
|
||||||
// Key Prefixes
|
// Key Prefixes
|
||||||
var (
|
var (
|
||||||
ClaimKeyPrefix = []byte{0x01} // prefix for keys that store claims
|
USDXMintingClaimKeyPrefix = []byte{0x01} // prefix for keys that store USDX minting claims
|
||||||
BlockTimeKey = []byte{0x02} // prefix for key that stores the blocktime
|
USDXMintingRewardFactorKeyPrefix = []byte{0x02} // prefix for key that stores USDX minting reward factors
|
||||||
RewardFactorKey = []byte{0x03} // prefix for key that stores reward factors
|
PreviousUSDXMintingRewardAccrualTimeKeyPrefix = []byte{0x03} // prefix for key that stores the blocktime
|
||||||
|
HardLiquidityClaimKeyPrefix = []byte{0x04} // prefix for keys that store Hard liquidity claims
|
||||||
|
HardSupplyRewardFactorKeyPrefix = []byte{0x05} // prefix for key that stores Hard supply reward factors
|
||||||
|
PreviousHardSupplyRewardAccrualTimeKeyPrefix = []byte{0x06} // prefix for key that stores the previous time Hard supply rewards accrued
|
||||||
|
HardBorrowRewardFactorKeyPrefix = []byte{0x07} // prefix for key that stores Hard borrow reward factors
|
||||||
|
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
|
||||||
|
PreviousHardDelegatorRewardAccrualTimeKeyPrefix = []byte{0x10} // prefix for key that stores the previous time Hard delegator rewards accrued
|
||||||
|
|
||||||
USDXMintingRewardDenom = "ukava"
|
USDXMintingRewardDenom = "ukava"
|
||||||
|
HardLiquidityRewardDenom = "hard"
|
||||||
)
|
)
|
||||||
|
@ -24,8 +24,10 @@ const (
|
|||||||
|
|
||||||
// Parameter keys and default values
|
// Parameter keys and default values
|
||||||
var (
|
var (
|
||||||
KeyActive = []byte("Active")
|
KeyUSDXMintingRewardPeriods = []byte("USDXMintingRewardPeriods")
|
||||||
KeyRewards = []byte("RewardPeriods")
|
KeyHardSupplyRewardPeriods = []byte("HardSupplyRewardPeriods")
|
||||||
|
KeyHardBorrowRewardPeriods = []byte("HardBorrowRewardPeriods")
|
||||||
|
KeyHardDelegatorRewardPeriods = []byte("HardDelegatorRewardPeriods")
|
||||||
KeyClaimEnd = []byte("ClaimEnd")
|
KeyClaimEnd = []byte("ClaimEnd")
|
||||||
KeyMultipliers = []byte("ClaimMultipliers")
|
KeyMultipliers = []byte("ClaimMultipliers")
|
||||||
DefaultActive = false
|
DefaultActive = false
|
||||||
@ -41,15 +43,22 @@ var (
|
|||||||
|
|
||||||
// Params governance parameters for the incentive module
|
// Params governance parameters for the incentive module
|
||||||
type Params struct {
|
type Params struct {
|
||||||
RewardPeriods RewardPeriods `json:"reward_periods" yaml:"reward_periods"`
|
USDXMintingRewardPeriods RewardPeriods `json:"usdx_minting_reward_periods" yaml:"usdx_minting_reward_periods"`
|
||||||
|
HardSupplyRewardPeriods RewardPeriods `json:"hard_supply_reward_periods" yaml:"hard_supply_reward_periods"`
|
||||||
|
HardBorrowRewardPeriods RewardPeriods `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"`
|
ClaimMultipliers Multipliers `json:"claim_multipliers" yaml:"claim_multipliers"`
|
||||||
ClaimEnd time.Time `json:"claim_end" yaml:"claim_end"`
|
ClaimEnd time.Time `json:"claim_end" yaml:"claim_end"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParams returns a new params object
|
// NewParams returns a new params object
|
||||||
func NewParams(rewards RewardPeriods, multipliers Multipliers, claimEnd time.Time) Params {
|
func NewParams(usdxMinting, hardSupply, hardBorrow, hardDelegator RewardPeriods,
|
||||||
|
multipliers Multipliers, claimEnd time.Time) Params {
|
||||||
return Params{
|
return Params{
|
||||||
RewardPeriods: rewards,
|
USDXMintingRewardPeriods: usdxMinting,
|
||||||
|
HardSupplyRewardPeriods: hardSupply,
|
||||||
|
HardBorrowRewardPeriods: hardBorrow,
|
||||||
|
HardDelegatorRewardPeriods: hardDelegator,
|
||||||
ClaimMultipliers: multipliers,
|
ClaimMultipliers: multipliers,
|
||||||
ClaimEnd: claimEnd,
|
ClaimEnd: claimEnd,
|
||||||
}
|
}
|
||||||
@ -57,16 +66,21 @@ func NewParams(rewards RewardPeriods, multipliers Multipliers, claimEnd time.Tim
|
|||||||
|
|
||||||
// DefaultParams returns default params for incentive module
|
// DefaultParams returns default params for incentive module
|
||||||
func DefaultParams() Params {
|
func DefaultParams() Params {
|
||||||
return NewParams(DefaultRewardPeriods, DefaultMultipliers, DefaultClaimEnd)
|
return NewParams(DefaultRewardPeriods, DefaultRewardPeriods,
|
||||||
|
DefaultRewardPeriods, DefaultRewardPeriods, DefaultMultipliers, DefaultClaimEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements fmt.Stringer
|
// String implements fmt.Stringer
|
||||||
func (p Params) String() string {
|
func (p Params) String() string {
|
||||||
return fmt.Sprintf(`Params:
|
return fmt.Sprintf(`Params:
|
||||||
Rewards: %s
|
USDX Minting Reward Periods: %s
|
||||||
|
Hard Supply Reward Periods: %s
|
||||||
|
Hard Borrow Reward Periods: %s
|
||||||
|
Hard Delegator Reward Periods: %s
|
||||||
Claim Multipliers :%s
|
Claim Multipliers :%s
|
||||||
Claim End Time: %s
|
Claim End Time: %s
|
||||||
`, p.RewardPeriods, p.ClaimMultipliers, p.ClaimEnd)
|
`, p.USDXMintingRewardPeriods, p.HardSupplyRewardPeriods, p.HardBorrowRewardPeriods,
|
||||||
|
p.HardDelegatorRewardPeriods, p.ClaimMultipliers, p.ClaimEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParamKeyTable Key declaration for parameters
|
// ParamKeyTable Key declaration for parameters
|
||||||
@ -77,7 +91,10 @@ func ParamKeyTable() params.KeyTable {
|
|||||||
// ParamSetPairs implements the ParamSet interface and returns all the key/value pairs
|
// ParamSetPairs implements the ParamSet interface and returns all the key/value pairs
|
||||||
func (p *Params) ParamSetPairs() params.ParamSetPairs {
|
func (p *Params) ParamSetPairs() params.ParamSetPairs {
|
||||||
return params.ParamSetPairs{
|
return params.ParamSetPairs{
|
||||||
params.NewParamSetPair(KeyRewards, &p.RewardPeriods, validateRewardsParam),
|
params.NewParamSetPair(KeyUSDXMintingRewardPeriods, &p.USDXMintingRewardPeriods, validateRewardPeriodsParam),
|
||||||
|
params.NewParamSetPair(KeyHardSupplyRewardPeriods, &p.HardSupplyRewardPeriods, validateRewardPeriodsParam),
|
||||||
|
params.NewParamSetPair(KeyHardBorrowRewardPeriods, &p.HardBorrowRewardPeriods, validateRewardPeriodsParam),
|
||||||
|
params.NewParamSetPair(KeyHardDelegatorRewardPeriods, &p.HardDelegatorRewardPeriods, validateRewardPeriodsParam),
|
||||||
params.NewParamSetPair(KeyClaimEnd, &p.ClaimEnd, validateClaimEndParam),
|
params.NewParamSetPair(KeyClaimEnd, &p.ClaimEnd, validateClaimEndParam),
|
||||||
params.NewParamSetPair(KeyMultipliers, &p.ClaimMultipliers, validateMultipliersParam),
|
params.NewParamSetPair(KeyMultipliers, &p.ClaimMultipliers, validateMultipliersParam),
|
||||||
}
|
}
|
||||||
@ -85,22 +102,27 @@ func (p *Params) ParamSetPairs() params.ParamSetPairs {
|
|||||||
|
|
||||||
// Validate checks that the parameters have valid values.
|
// Validate checks that the parameters have valid values.
|
||||||
func (p Params) Validate() error {
|
func (p Params) Validate() error {
|
||||||
|
|
||||||
if err := validateMultipliersParam(p.ClaimMultipliers); err != nil {
|
if err := validateMultipliersParam(p.ClaimMultipliers); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return validateRewardsParam(p.RewardPeriods)
|
if err := validateRewardPeriodsParam(p.USDXMintingRewardPeriods); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateActiveParam(i interface{}) error {
|
if err := validateRewardPeriodsParam(p.HardSupplyRewardPeriods); err != nil {
|
||||||
_, ok := i.(bool)
|
return err
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("invalid parameter type: %T", i)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateRewardsParam(i interface{}) error {
|
if err := validateRewardPeriodsParam(p.HardBorrowRewardPeriods); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return validateRewardPeriodsParam(p.HardDelegatorRewardPeriods)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateRewardPeriodsParam(i interface{}) error {
|
||||||
rewards, ok := i.(RewardPeriods)
|
rewards, ok := i.(RewardPeriods)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("invalid parameter type: %T", i)
|
return fmt.Errorf("invalid parameter type: %T", i)
|
||||||
@ -224,9 +246,6 @@ func (m Multiplier) Validate() error {
|
|||||||
if m.MonthsLockup < 0 {
|
if m.MonthsLockup < 0 {
|
||||||
return fmt.Errorf("expected non-negative lockup, got %d", m.MonthsLockup)
|
return fmt.Errorf("expected non-negative lockup, got %d", m.MonthsLockup)
|
||||||
}
|
}
|
||||||
if m.Factor == (sdk.Dec{}) {
|
|
||||||
return fmt.Errorf("claim multiplier factor not initialized for %s", m.Name)
|
|
||||||
}
|
|
||||||
if m.Factor.IsNegative() {
|
if m.Factor.IsNegative() {
|
||||||
return fmt.Errorf("expected non-negative factor, got %s", m.Factor.String())
|
return fmt.Errorf("expected non-negative factor, got %s", m.Factor.String())
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,10 @@ func (suite *ParamTestSuite) SetupTest() {}
|
|||||||
|
|
||||||
func (suite *ParamTestSuite) TestParamValidation() {
|
func (suite *ParamTestSuite) TestParamValidation() {
|
||||||
type args struct {
|
type args struct {
|
||||||
rewardPeriods types.RewardPeriods
|
usdxMintingRewardPeriods types.RewardPeriods
|
||||||
|
hardSupplyRewardPeriods types.RewardPeriods
|
||||||
|
hardBorrowRewardPeriods types.RewardPeriods
|
||||||
|
hardDelegatorRewardPeriods types.RewardPeriods
|
||||||
multipliers types.Multipliers
|
multipliers types.Multipliers
|
||||||
end time.Time
|
end time.Time
|
||||||
}
|
}
|
||||||
@ -39,7 +42,10 @@ func (suite *ParamTestSuite) TestParamValidation() {
|
|||||||
{
|
{
|
||||||
"default",
|
"default",
|
||||||
args{
|
args{
|
||||||
rewardPeriods: types.DefaultRewardPeriods,
|
usdxMintingRewardPeriods: types.DefaultRewardPeriods,
|
||||||
|
hardSupplyRewardPeriods: types.DefaultRewardPeriods,
|
||||||
|
hardBorrowRewardPeriods: types.DefaultRewardPeriods,
|
||||||
|
hardDelegatorRewardPeriods: types.DefaultRewardPeriods,
|
||||||
multipliers: types.DefaultMultipliers,
|
multipliers: types.DefaultMultipliers,
|
||||||
end: types.DefaultClaimEnd,
|
end: types.DefaultClaimEnd,
|
||||||
},
|
},
|
||||||
@ -51,7 +57,7 @@ func (suite *ParamTestSuite) TestParamValidation() {
|
|||||||
{
|
{
|
||||||
"valid",
|
"valid",
|
||||||
args{
|
args{
|
||||||
rewardPeriods: types.RewardPeriods{types.NewRewardPeriod(
|
usdxMintingRewardPeriods: types.RewardPeriods{types.NewRewardPeriod(
|
||||||
true, "bnb-a", time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 10, 15, 14, 0, 0, 0, time.UTC),
|
true, "bnb-a", time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 10, 15, 14, 0, 0, 0, time.UTC),
|
||||||
sdk.NewCoin(types.USDXMintingRewardDenom, sdk.NewInt(122354)))},
|
sdk.NewCoin(types.USDXMintingRewardDenom, sdk.NewInt(122354)))},
|
||||||
multipliers: types.Multipliers{
|
multipliers: types.Multipliers{
|
||||||
@ -62,6 +68,9 @@ func (suite *ParamTestSuite) TestParamValidation() {
|
|||||||
types.Large, 1, sdk.MustNewDecFromStr("1.0"),
|
types.Large, 1, sdk.MustNewDecFromStr("1.0"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
hardSupplyRewardPeriods: types.DefaultRewardPeriods,
|
||||||
|
hardBorrowRewardPeriods: types.DefaultRewardPeriods,
|
||||||
|
hardDelegatorRewardPeriods: types.DefaultRewardPeriods,
|
||||||
end: time.Date(2025, 10, 15, 14, 0, 0, 0, time.UTC),
|
end: time.Date(2025, 10, 15, 14, 0, 0, 0, time.UTC),
|
||||||
},
|
},
|
||||||
errArgs{
|
errArgs{
|
||||||
@ -69,33 +78,12 @@ func (suite *ParamTestSuite) TestParamValidation() {
|
|||||||
contains: "",
|
contains: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"invalid: empty reward factor",
|
|
||||||
args{
|
|
||||||
rewardPeriods: types.RewardPeriods{types.NewRewardPeriod(
|
|
||||||
true, "bnb-a", time.Date(2020, 10, 15, 14, 0, 0, 0, time.UTC), time.Date(2024, 10, 15, 14, 0, 0, 0, time.UTC),
|
|
||||||
sdk.NewCoin(types.USDXMintingRewardDenom, sdk.NewInt(122354)))},
|
|
||||||
multipliers: types.Multipliers{
|
|
||||||
types.NewMultiplier(
|
|
||||||
types.Small, 1, sdk.MustNewDecFromStr("0.25"),
|
|
||||||
),
|
|
||||||
types.NewMultiplier(
|
|
||||||
types.Large, 1, sdk.Dec{},
|
|
||||||
),
|
|
||||||
},
|
|
||||||
end: time.Date(2025, 10, 15, 14, 0, 0, 0, time.UTC),
|
|
||||||
},
|
|
||||||
errArgs{
|
|
||||||
expectPass: false,
|
|
||||||
contains: "claim multiplier factor not initialized",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
suite.Run(tc.name, func() {
|
suite.Run(tc.name, func() {
|
||||||
params := types.NewParams(
|
params := types.NewParams(tc.args.usdxMintingRewardPeriods, tc.args.hardSupplyRewardPeriods,
|
||||||
tc.args.rewardPeriods, tc.args.multipliers, tc.args.end,
|
tc.args.hardBorrowRewardPeriods, tc.args.hardDelegatorRewardPeriods, tc.args.multipliers, tc.args.end,
|
||||||
)
|
)
|
||||||
err := params.Validate()
|
err := params.Validate()
|
||||||
if tc.errArgs.expectPass {
|
if tc.errArgs.expectPass {
|
||||||
|
Loading…
Reference in New Issue
Block a user