mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-11-13 03:25:20 +00:00
Hard: Kava delegators earn HARD rewards via the Incentive module (#776)
* add staking keeper to incentive module * update hard with delegator methods * add delegator methods to incentive * implement delegator hook scaffolds * implement hard delegator reward accumulation * update claim names to delegator * stakingKeeper expected keeper methods * accumulate delegator rewards * initialize delegator reward * synchronize delegator reward * add TODO comments to rewards * implement staking hooks interface * initial revisions * remove outdated TODO * update methods for test compatibility * update method names for test compatibility * implement initial accumulate delegator reward test * attempt validator set up in staking module * initial synchronize delegator reward test * delegator accumulation test passing * synchronize delegator rewards test (not passing) * synchronize delegator rewards passing * revisions
This commit is contained in:
parent
dc330d02bf
commit
72a6df17fd
@ -382,6 +382,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
|
|||||||
&cdpKeeper,
|
&cdpKeeper,
|
||||||
&hardKeeper,
|
&hardKeeper,
|
||||||
app.accountKeeper,
|
app.accountKeeper,
|
||||||
|
&stakingKeeper,
|
||||||
)
|
)
|
||||||
app.issuanceKeeper = issuance.NewKeeper(
|
app.issuanceKeeper = issuance.NewKeeper(
|
||||||
app.cdc,
|
app.cdc,
|
||||||
@ -394,7 +395,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
|
|||||||
// 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
|
||||||
app.stakingKeeper = *stakingKeeper.SetHooks(
|
app.stakingKeeper = *stakingKeeper.SetHooks(
|
||||||
staking.NewMultiStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()))
|
staking.NewMultiStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks(), app.incentiveKeeper.Hooks()))
|
||||||
|
|
||||||
app.cdpKeeper = *cdpKeeper.SetHooks(cdp.NewMultiCDPHooks(app.incentiveKeeper.Hooks()))
|
app.cdpKeeper = *cdpKeeper.SetHooks(cdp.NewMultiCDPHooks(app.incentiveKeeper.Hooks()))
|
||||||
|
|
||||||
|
@ -34,18 +34,19 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
PreviousBlockTimeKey = []byte{0x01}
|
PreviousBlockTimeKey = []byte{0x01}
|
||||||
DepositsKeyPrefix = []byte{0x03}
|
DepositsKeyPrefix = []byte{0x03}
|
||||||
BorrowsKeyPrefix = []byte{0x05}
|
BorrowsKeyPrefix = []byte{0x05}
|
||||||
BorrowedCoinsPrefix = []byte{0x06}
|
BorrowedCoinsPrefix = []byte{0x06}
|
||||||
SuppliedCoinsPrefix = []byte{0x07}
|
SuppliedCoinsPrefix = []byte{0x07}
|
||||||
MoneyMarketsPrefix = []byte{0x08}
|
MoneyMarketsPrefix = []byte{0x08}
|
||||||
PreviousAccrualTimePrefix = []byte{0x09} // denom -> time
|
PreviousAccrualTimePrefix = []byte{0x09} // denom -> time
|
||||||
TotalReservesPrefix = []byte{0x10} // denom -> sdk.Coin
|
TotalReservesPrefix = []byte{0x10} // denom -> sdk.Coin
|
||||||
BorrowInterestFactorPrefix = []byte{0x11} // denom -> sdk.Dec
|
BorrowInterestFactorPrefix = []byte{0x11} // denom -> sdk.Dec
|
||||||
SupplyInterestFactorPrefix = []byte{0x12} // denom -> sdk.Dec
|
SupplyInterestFactorPrefix = []byte{0x12} // denom -> sdk.Dec
|
||||||
LtvIndexPrefix = []byte{0x13}
|
DelegatorInterestFactorPrefix = []byte{0x12} // denom -> sdk.Dec
|
||||||
sep = []byte(":")
|
LtvIndexPrefix = []byte{0x13}
|
||||||
|
sep = []byte(":")
|
||||||
)
|
)
|
||||||
|
|
||||||
// DepositTypeIteratorKey returns an interator prefix for interating over deposits by deposit denom
|
// DepositTypeIteratorKey returns an interator prefix for interating over deposits by deposit denom
|
||||||
|
@ -2,6 +2,8 @@ package keeper
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/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"
|
hardtypes "github.com/kava-labs/kava/x/hard/types"
|
||||||
)
|
)
|
||||||
@ -13,10 +15,13 @@ type Hooks struct {
|
|||||||
|
|
||||||
var _ cdptypes.CDPHooks = Hooks{}
|
var _ cdptypes.CDPHooks = Hooks{}
|
||||||
var _ hardtypes.HARDHooks = Hooks{}
|
var _ hardtypes.HARDHooks = Hooks{}
|
||||||
|
var _ stakingtypes.StakingHooks = 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} }
|
||||||
|
|
||||||
|
// ------------------- Cdp Module Hooks -------------------
|
||||||
|
|
||||||
// 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.InitializeUSDXMintingClaim(ctx, cdp)
|
h.k.InitializeUSDXMintingClaim(ctx, cdp)
|
||||||
@ -29,6 +34,8 @@ func (h Hooks) BeforeCDPModified(ctx sdk.Context, cdp cdptypes.CDP) {
|
|||||||
h.k.SynchronizeUSDXMintingReward(ctx, cdp)
|
h.k.SynchronizeUSDXMintingReward(ctx, cdp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------- Hard Module Hooks -------------------
|
||||||
|
|
||||||
// AfterDepositCreated function that runs after a deposit is created
|
// AfterDepositCreated function that runs after a deposit is created
|
||||||
func (h Hooks) AfterDepositCreated(ctx sdk.Context, deposit hardtypes.Deposit) {
|
func (h Hooks) AfterDepositCreated(ctx sdk.Context, deposit hardtypes.Deposit) {
|
||||||
h.k.InitializeHardSupplyReward(ctx, deposit)
|
h.k.InitializeHardSupplyReward(ctx, deposit)
|
||||||
@ -58,3 +65,46 @@ func (h Hooks) BeforeBorrowModified(ctx sdk.Context, borrow hardtypes.Borrow) {
|
|||||||
func (h Hooks) AfterBorrowModified(ctx sdk.Context, borrow hardtypes.Borrow) {
|
func (h Hooks) AfterBorrowModified(ctx sdk.Context, borrow hardtypes.Borrow) {
|
||||||
h.k.UpdateHardBorrowIndexDenoms(ctx, borrow)
|
h.k.UpdateHardBorrowIndexDenoms(ctx, borrow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------- Staking Module Hooks -------------------
|
||||||
|
|
||||||
|
// BeforeDelegationCreated runs before a delegation is created
|
||||||
|
func (h Hooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||||
|
h.k.InitializeHardDelegatorReward(ctx, delAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeforeDelegationSharesModified runs before an existing delegation is modified
|
||||||
|
func (h Hooks) BeforeDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||||
|
h.k.SynchronizeHardDelegatorRewards(ctx, delAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: following hooks are just implemented to ensure StakingHooks interface compliance
|
||||||
|
|
||||||
|
// BeforeValidatorSlashed is called before a validator is slashed
|
||||||
|
func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec) {}
|
||||||
|
|
||||||
|
// AfterValidatorBeginUnbonding is called after a validator begins unbonding
|
||||||
|
func (h Hooks) AfterValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterValidatorBonded is called after a validator is bonded
|
||||||
|
func (h Hooks) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterDelegationModified runs after a delegation is modified
|
||||||
|
func (h Hooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeforeDelegationRemoved runs directly before a delegation is deleted
|
||||||
|
func (h Hooks) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterValidatorCreated runs after a validator is created
|
||||||
|
func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {}
|
||||||
|
|
||||||
|
// BeforeValidatorModified runs before a validator is modified
|
||||||
|
func (h Hooks) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {}
|
||||||
|
|
||||||
|
// AfterValidatorRemoved runs after a validator is removed
|
||||||
|
func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||||
|
}
|
||||||
|
@ -20,12 +20,13 @@ type Keeper struct {
|
|||||||
key sdk.StoreKey
|
key sdk.StoreKey
|
||||||
paramSubspace subspace.Subspace
|
paramSubspace subspace.Subspace
|
||||||
supplyKeeper types.SupplyKeeper
|
supplyKeeper types.SupplyKeeper
|
||||||
|
stakingKeeper types.StakingKeeper
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, hk types.HardKeeper, ak types.AccountKeeper,
|
cdpk types.CdpKeeper, hk types.HardKeeper, ak types.AccountKeeper, stk types.StakingKeeper,
|
||||||
) Keeper {
|
) Keeper {
|
||||||
|
|
||||||
return Keeper{
|
return Keeper{
|
||||||
@ -36,6 +37,7 @@ func NewKeeper(
|
|||||||
key: key,
|
key: key,
|
||||||
paramSubspace: paramstore.WithKeyTable(types.ParamKeyTable()),
|
paramSubspace: paramstore.WithKeyTable(types.ParamKeyTable()),
|
||||||
supplyKeeper: sk,
|
supplyKeeper: sk,
|
||||||
|
stakingKeeper: stk,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,3 +278,20 @@ func (k Keeper) SetPreviousHardBorrowRewardAccrualTime(ctx sdk.Context, denom st
|
|||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousHardBorrowRewardAccrualTimeKeyPrefix)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousHardBorrowRewardAccrualTimeKeyPrefix)
|
||||||
store.Set([]byte(denom), k.cdc.MustMarshalBinaryBare(blockTime))
|
store.Set([]byte(denom), k.cdc.MustMarshalBinaryBare(blockTime))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPreviousHardDelegatorRewardAccrualTime returns the last time a denom accrued Hard protocol delegator rewards
|
||||||
|
func (k Keeper) GetPreviousHardDelegatorRewardAccrualTime(ctx sdk.Context, denom string) (blockTime time.Time, found bool) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousHardDelegatorRewardAccrualTimeKeyPrefix)
|
||||||
|
bz := store.Get([]byte(denom))
|
||||||
|
if bz == nil {
|
||||||
|
return time.Time{}, false
|
||||||
|
}
|
||||||
|
k.cdc.MustUnmarshalBinaryBare(bz, &blockTime)
|
||||||
|
return blockTime, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPreviousHardDelegatorRewardAccrualTime sets the last time a denom accrued Hard protocol delegator rewards
|
||||||
|
func (k Keeper) SetPreviousHardDelegatorRewardAccrualTime(ctx sdk.Context, denom string, blockTime time.Time) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousHardDelegatorRewardAccrualTimeKeyPrefix)
|
||||||
|
store.Set([]byte(denom), k.cdc.MustMarshalBinaryBare(blockTime))
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
|
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
|
||||||
|
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
|
||||||
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
|
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
@ -24,18 +25,22 @@ import (
|
|||||||
type KeeperTestSuite struct {
|
type KeeperTestSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
|
|
||||||
keeper keeper.Keeper
|
keeper keeper.Keeper
|
||||||
hardKeeper hardkeeper.Keeper
|
hardKeeper hardkeeper.Keeper
|
||||||
app app.TestApp
|
stakingKeeper stakingkeeper.Keeper
|
||||||
ctx sdk.Context
|
app app.TestApp
|
||||||
addrs []sdk.AccAddress
|
ctx sdk.Context
|
||||||
|
addrs []sdk.AccAddress
|
||||||
|
validatorAddrs []sdk.ValAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
// The default state used by each test
|
// The default state used by each test
|
||||||
func (suite *KeeperTestSuite) SetupTest() {
|
func (suite *KeeperTestSuite) SetupTest() {
|
||||||
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()})
|
||||||
|
|
||||||
tApp.InitializeFromGenesisStates()
|
tApp.InitializeFromGenesisStates()
|
||||||
|
|
||||||
_, addrs := app.GeneratePrivKeyAddressPairs(5)
|
_, addrs := app.GeneratePrivKeyAddressPairs(5)
|
||||||
keeper := tApp.GetIncentiveKeeper()
|
keeper := tApp.GetIncentiveKeeper()
|
||||||
suite.app = tApp
|
suite.app = tApp
|
||||||
|
@ -53,6 +53,17 @@ func (k Keeper) GetHardBorrowRewardPeriod(ctx sdk.Context, denom string) (types.
|
|||||||
return types.RewardPeriod{}, false
|
return types.RewardPeriod{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHardDelegatorRewardPeriod returns the reward period with the specified collateral type if it's found in the params
|
||||||
|
func (k Keeper) GetHardDelegatorRewardPeriod(ctx sdk.Context, denom string) (types.RewardPeriod, bool) {
|
||||||
|
params := k.GetParams(ctx)
|
||||||
|
for _, rp := range params.HardDelegatorRewardPeriods {
|
||||||
|
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)
|
||||||
|
@ -54,7 +54,7 @@ func (suite *KeeperTestSuite) TestPayoutClaim() {
|
|||||||
multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
multipliers: types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
multiplier: types.MultiplierName("large"),
|
multiplier: types.MultiplierName("large"),
|
||||||
timeElapsed: 86400,
|
timeElapsed: 86400,
|
||||||
expectedBalance: cs(c("usdx", 10000000000), c("ukava", 10571385600)),
|
expectedBalance: cs(c("usdx", 10000000000), c("ukava", 10576385600)),
|
||||||
expectedPeriods: vesting.Periods{vesting.Period{Length: 31536000, Amount: cs(c("ukava", 10571385600))}},
|
expectedPeriods: vesting.Periods{vesting.Period{Length: 31536000, Amount: cs(c("ukava", 10571385600))}},
|
||||||
isPeriodicVestingAccount: true,
|
isPeriodicVestingAccount: true,
|
||||||
},
|
},
|
||||||
|
@ -400,6 +400,124 @@ func (k Keeper) UpdateHardBorrowIndexDenoms(ctx sdk.Context, borrow hardtypes.Bo
|
|||||||
k.SetHardLiquidityProviderClaim(ctx, claim)
|
k.SetHardLiquidityProviderClaim(ctx, claim)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SynchronizeHardDelegatorRewards updates the claim object by adding any accumulated rewards
|
||||||
|
func (k Keeper) SynchronizeHardDelegatorRewards(ctx sdk.Context, delegator sdk.AccAddress) {
|
||||||
|
claim, found := k.GetHardLiquidityProviderClaim(ctx, delegator)
|
||||||
|
if !found {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
delagatorFactor, found := k.GetHardDelegatorRewardFactor(ctx, types.BondDenom)
|
||||||
|
if !found {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
delegatorIndex, hasDelegatorRewardIndex := claim.HasDelegatorRewardIndex(types.BondDenom)
|
||||||
|
if !hasDelegatorRewardIndex {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userRewardFactor := claim.DelegatorRewardIndexes[delegatorIndex].RewardFactor
|
||||||
|
rewardsAccumulatedFactor := delagatorFactor.Sub(userRewardFactor)
|
||||||
|
if rewardsAccumulatedFactor.IsZero() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
claim.DelegatorRewardIndexes[delegatorIndex].RewardFactor = delagatorFactor
|
||||||
|
|
||||||
|
totalDelegated := sdk.ZeroDec()
|
||||||
|
|
||||||
|
// TODO: set reasonable max limit on delegation iteration
|
||||||
|
maxUInt := ^uint16(0)
|
||||||
|
delegations := k.stakingKeeper.GetDelegatorDelegations(ctx, delegator, maxUInt)
|
||||||
|
for _, delegation := range delegations {
|
||||||
|
validator, found := k.stakingKeeper.GetValidator(ctx, delegation.GetValidatorAddr())
|
||||||
|
if !found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delegators don't accumulate rewards if their validator is unbonded/slashed
|
||||||
|
if validator.GetStatus() != sdk.Bonded {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if validator.GetTokens().IsZero() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
delegatedTokens := validator.TokensFromShares(delegation.GetShares())
|
||||||
|
if delegatedTokens.IsZero() || delegatedTokens.IsNegative() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
totalDelegated = totalDelegated.Add(delegatedTokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
rewardsEarned := rewardsAccumulatedFactor.Mul(totalDelegated).RoundInt()
|
||||||
|
if rewardsEarned.IsZero() || rewardsEarned.IsNegative() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add rewards to delegator's hard claim
|
||||||
|
newRewardsCoin := sdk.NewCoin(types.HardLiquidityRewardDenom, rewardsEarned)
|
||||||
|
claim.Reward = claim.Reward.Add(newRewardsCoin)
|
||||||
|
k.SetHardLiquidityProviderClaim(ctx, claim)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccumulateHardDelegatorRewards updates the rewards accumulated for the input reward period
|
||||||
|
func (k Keeper) AccumulateHardDelegatorRewards(ctx sdk.Context, rewardPeriod types.RewardPeriod) error {
|
||||||
|
previousAccrualTime, found := k.GetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriod.CollateralType)
|
||||||
|
if !found {
|
||||||
|
k.SetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
timeElapsed := CalculateTimeElapsed(rewardPeriod, ctx.BlockTime(), previousAccrualTime)
|
||||||
|
if timeElapsed.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if rewardPeriod.RewardsPerSecond.Amount.IsZero() {
|
||||||
|
k.SetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
totalBonded := k.stakingKeeper.TotalBondedTokens(ctx).ToDec()
|
||||||
|
if totalBonded.IsZero() {
|
||||||
|
k.SetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newRewards := timeElapsed.Mul(rewardPeriod.RewardsPerSecond.Amount)
|
||||||
|
rewardFactor := newRewards.ToDec().Quo(totalBonded)
|
||||||
|
|
||||||
|
previousRewardFactor, found := k.GetHardDelegatorRewardFactor(ctx, rewardPeriod.CollateralType)
|
||||||
|
if !found {
|
||||||
|
previousRewardFactor = sdk.ZeroDec()
|
||||||
|
}
|
||||||
|
newRewardFactor := previousRewardFactor.Add(rewardFactor)
|
||||||
|
k.SetHardDelegatorRewardFactor(ctx, rewardPeriod.CollateralType, newRewardFactor)
|
||||||
|
k.SetPreviousHardDelegatorRewardAccrualTime(ctx, rewardPeriod.CollateralType, ctx.BlockTime())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitializeHardDelegatorReward initializes the delegator reward index of a hard claim
|
||||||
|
func (k Keeper) InitializeHardDelegatorReward(ctx sdk.Context, delegator sdk.AccAddress) {
|
||||||
|
delegatorFactor, foundDelegatorFactor := k.GetHardDelegatorRewardFactor(ctx, types.BondDenom)
|
||||||
|
if !foundDelegatorFactor { // Should always be found...
|
||||||
|
delegatorFactor = sdk.ZeroDec()
|
||||||
|
}
|
||||||
|
|
||||||
|
delegatorRewardIndexes := types.NewRewardIndex(types.BondDenom, delegatorFactor)
|
||||||
|
|
||||||
|
claim, found := k.GetHardLiquidityProviderClaim(ctx, delegator)
|
||||||
|
if !found {
|
||||||
|
// Instantiate claim object
|
||||||
|
claim = types.NewHardLiquidityProviderClaim(delegator,
|
||||||
|
sdk.NewCoin(types.HardLiquidityRewardDenom, sdk.ZeroInt()),
|
||||||
|
nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
claim.DelegatorRewardIndexes = types.RewardIndexes{delegatorRewardIndexes}
|
||||||
|
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())
|
||||||
|
@ -4,8 +4,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||||
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"
|
||||||
@ -866,36 +867,292 @@ func (suite *KeeperTestSuite) TestUpdateHardBorrowIndexDenoms() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *KeeperTestSuite) TestAccumulateHardDelegatorRewards() {
|
||||||
|
type args struct {
|
||||||
|
delegation sdk.Coin
|
||||||
|
rewardsPerSecond sdk.Coin
|
||||||
|
initialTime time.Time
|
||||||
|
timeElapsed int
|
||||||
|
expectedRewardFactor sdk.Dec
|
||||||
|
}
|
||||||
|
type test struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}
|
||||||
|
testCases := []test{
|
||||||
|
{
|
||||||
|
"7 seconds",
|
||||||
|
args{
|
||||||
|
delegation: c("ukava", 1_000_000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
timeElapsed: 7,
|
||||||
|
expectedRewardFactor: d("0.428239000000000000"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"1 day",
|
||||||
|
args{
|
||||||
|
delegation: c("ukava", 1_000_000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
timeElapsed: 86400,
|
||||||
|
expectedRewardFactor: d("5285.692800000000000000"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"0 seconds",
|
||||||
|
args{
|
||||||
|
delegation: c("ukava", 1_000_000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
timeElapsed: 0,
|
||||||
|
expectedRewardFactor: d("0.0"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
suite.SetupWithGenState()
|
||||||
|
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
||||||
|
|
||||||
|
// Mint coins to hard module account
|
||||||
|
supplyKeeper := suite.app.GetSupplyKeeper()
|
||||||
|
hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000)))
|
||||||
|
supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins)
|
||||||
|
|
||||||
|
// Set up incentive state
|
||||||
|
params := types.NewParams(
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
|
tc.args.initialTime.Add(time.Hour*24*365*5),
|
||||||
|
)
|
||||||
|
suite.keeper.SetParams(suite.ctx, params)
|
||||||
|
suite.keeper.SetPreviousHardDelegatorRewardAccrualTime(suite.ctx, tc.args.delegation.Denom, tc.args.initialTime)
|
||||||
|
suite.keeper.SetHardDelegatorRewardFactor(suite.ctx, tc.args.delegation.Denom, sdk.ZeroDec())
|
||||||
|
|
||||||
|
// Set up hard state (interest factor for the relevant denom)
|
||||||
|
suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.delegation.Denom, tc.args.initialTime)
|
||||||
|
|
||||||
|
err := suite.deliverMsgCreateValidator(suite.ctx, suite.validatorAddrs[0], tc.args.delegation)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
suite.deliverMsgDelegate(suite.ctx, suite.addrs[0], suite.validatorAddrs[0], tc.args.delegation)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
staking.EndBlocker(suite.ctx, suite.stakingKeeper)
|
||||||
|
|
||||||
|
// Set up chain context at future time
|
||||||
|
runAtTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * tc.args.timeElapsed))
|
||||||
|
runCtx := suite.ctx.WithBlockTime(runAtTime)
|
||||||
|
|
||||||
|
// Run Hard begin blocker in order to update the denom's index factor
|
||||||
|
hard.BeginBlocker(runCtx, suite.hardKeeper)
|
||||||
|
|
||||||
|
rewardPeriod, found := suite.keeper.GetHardDelegatorRewardPeriod(runCtx, tc.args.delegation.Denom)
|
||||||
|
suite.Require().True(found)
|
||||||
|
err = suite.keeper.AccumulateHardDelegatorRewards(runCtx, rewardPeriod)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
rewardFactor, found := suite.keeper.GetHardDelegatorRewardFactor(runCtx, tc.args.delegation.Denom)
|
||||||
|
suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KeeperTestSuite) TestSynchronizeHardDelegatorReward() {
|
||||||
|
type args struct {
|
||||||
|
delegation sdk.Coin
|
||||||
|
rewardsPerSecond sdk.Coin
|
||||||
|
initialTime time.Time
|
||||||
|
blockTimes []int
|
||||||
|
expectedRewardFactor sdk.Dec
|
||||||
|
expectedRewards sdk.Coin
|
||||||
|
}
|
||||||
|
type test struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []test{
|
||||||
|
{
|
||||||
|
"10 blocks",
|
||||||
|
args{
|
||||||
|
delegation: c("ukava", 1_000_000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
blockTimes: []int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10},
|
||||||
|
expectedRewardFactor: d("6.117700000000000000"),
|
||||||
|
expectedRewards: c("hard", 6117700),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"10 blocks - long block time",
|
||||||
|
args{
|
||||||
|
delegation: c("ukava", 1_000_000),
|
||||||
|
rewardsPerSecond: c("hard", 122354),
|
||||||
|
initialTime: time.Date(2020, 12, 15, 14, 0, 0, 0, time.UTC),
|
||||||
|
blockTimes: []int{86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400, 86400},
|
||||||
|
expectedRewardFactor: d("52856.928000000000000000"),
|
||||||
|
expectedRewards: c("hard", 52856928000),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
suite.SetupWithGenState()
|
||||||
|
suite.ctx = suite.ctx.WithBlockTime(tc.args.initialTime)
|
||||||
|
|
||||||
|
// Mint coins to hard module account
|
||||||
|
supplyKeeper := suite.app.GetSupplyKeeper()
|
||||||
|
hardMaccCoins := sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(200000000)))
|
||||||
|
supplyKeeper.MintCoins(suite.ctx, hardtypes.ModuleAccountName, hardMaccCoins)
|
||||||
|
|
||||||
|
// setup incentive state
|
||||||
|
params := types.NewParams(
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.RewardPeriods{types.NewRewardPeriod(true, tc.args.delegation.Denom, tc.args.initialTime, tc.args.initialTime.Add(time.Hour*24*365*4), tc.args.rewardsPerSecond)},
|
||||||
|
types.Multipliers{types.NewMultiplier(types.MultiplierName("small"), 1, d("0.25")), types.NewMultiplier(types.MultiplierName("large"), 12, d("1.0"))},
|
||||||
|
tc.args.initialTime.Add(time.Hour*24*365*5),
|
||||||
|
)
|
||||||
|
suite.keeper.SetParams(suite.ctx, params)
|
||||||
|
suite.keeper.SetPreviousHardDelegatorRewardAccrualTime(suite.ctx, tc.args.delegation.Denom, tc.args.initialTime)
|
||||||
|
suite.keeper.SetHardDelegatorRewardFactor(suite.ctx, tc.args.delegation.Denom, sdk.ZeroDec())
|
||||||
|
|
||||||
|
// Set up hard state (interest factor for the relevant denom)
|
||||||
|
suite.hardKeeper.SetPreviousAccrualTime(suite.ctx, tc.args.delegation.Denom, tc.args.initialTime)
|
||||||
|
|
||||||
|
// Delegator delegates
|
||||||
|
err := suite.deliverMsgCreateValidator(suite.ctx, suite.validatorAddrs[0], tc.args.delegation)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
suite.deliverMsgDelegate(suite.ctx, suite.addrs[0], suite.validatorAddrs[0], tc.args.delegation)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
staking.EndBlocker(suite.ctx, suite.stakingKeeper)
|
||||||
|
|
||||||
|
// Check that Staking hooks initialized a HardLiquidityProviderClaim
|
||||||
|
claim, found := suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[0])
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().Equal(sdk.ZeroDec(), claim.DelegatorRewardIndexes[0].RewardFactor)
|
||||||
|
|
||||||
|
// Run accumulator at several intervals
|
||||||
|
var timeElapsed int
|
||||||
|
previousBlockTime := suite.ctx.BlockTime()
|
||||||
|
for _, t := range tc.args.blockTimes {
|
||||||
|
timeElapsed += t
|
||||||
|
updatedBlockTime := previousBlockTime.Add(time.Duration(int(time.Second) * t))
|
||||||
|
previousBlockTime = updatedBlockTime
|
||||||
|
blockCtx := suite.ctx.WithBlockTime(updatedBlockTime)
|
||||||
|
|
||||||
|
// Run Hard begin blocker for each block ctx to update denom's interest factor
|
||||||
|
hard.BeginBlocker(blockCtx, suite.hardKeeper)
|
||||||
|
|
||||||
|
rewardPeriod, found := suite.keeper.GetHardDelegatorRewardPeriod(blockCtx, tc.args.delegation.Denom)
|
||||||
|
suite.Require().True(found)
|
||||||
|
|
||||||
|
err := suite.keeper.AccumulateHardDelegatorRewards(blockCtx, rewardPeriod)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
}
|
||||||
|
updatedBlockTime := suite.ctx.BlockTime().Add(time.Duration(int(time.Second) * timeElapsed))
|
||||||
|
suite.ctx = suite.ctx.WithBlockTime(updatedBlockTime)
|
||||||
|
|
||||||
|
// After we've accumulated, run synchronize
|
||||||
|
suite.Require().NotPanics(func() {
|
||||||
|
suite.keeper.SynchronizeHardDelegatorRewards(suite.ctx, suite.addrs[0])
|
||||||
|
})
|
||||||
|
|
||||||
|
// Check that reward factor and claim have been updated as expected
|
||||||
|
rewardFactor, found := suite.keeper.GetHardDelegatorRewardFactor(suite.ctx, tc.args.delegation.Denom)
|
||||||
|
suite.Require().Equal(tc.args.expectedRewardFactor, rewardFactor)
|
||||||
|
|
||||||
|
claim, found = suite.keeper.GetHardLiquidityProviderClaim(suite.ctx, suite.addrs[0])
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().Equal(tc.args.expectedRewardFactor, claim.DelegatorRewardIndexes[0].RewardFactor)
|
||||||
|
suite.Require().Equal(tc.args.expectedRewards, claim.Reward)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *KeeperTestSuite) SetupWithGenState() {
|
func (suite *KeeperTestSuite) SetupWithGenState() {
|
||||||
|
config := sdk.GetConfig()
|
||||||
|
app.SetBech32AddressPrefixes(config)
|
||||||
|
|
||||||
|
_, allAddrs := app.GeneratePrivKeyAddressPairs(10)
|
||||||
|
suite.addrs = allAddrs[:5]
|
||||||
|
for _, a := range allAddrs[5:] {
|
||||||
|
suite.validatorAddrs = append(suite.validatorAddrs, sdk.ValAddress(a))
|
||||||
|
}
|
||||||
|
|
||||||
tApp := app.NewTestApp()
|
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,
|
coinsAuthGenState(allAddrs, cs(c("ukava", 5_000_000))),
|
||||||
|
stakingGenesisState(),
|
||||||
NewPricefeedGenStateMulti(),
|
NewPricefeedGenStateMulti(),
|
||||||
NewCDPGenStateMulti(),
|
NewCDPGenStateMulti(),
|
||||||
NewHardGenStateMulti(),
|
NewHardGenStateMulti(),
|
||||||
)
|
)
|
||||||
|
|
||||||
keeper := tApp.GetIncentiveKeeper()
|
|
||||||
hardKeeper := tApp.GetHardKeeper()
|
|
||||||
suite.app = tApp
|
suite.app = tApp
|
||||||
suite.ctx = ctx
|
suite.ctx = ctx
|
||||||
suite.keeper = keeper
|
suite.keeper = tApp.GetIncentiveKeeper()
|
||||||
suite.hardKeeper = hardKeeper
|
suite.hardKeeper = tApp.GetHardKeeper()
|
||||||
suite.addrs = addrs
|
suite.stakingKeeper = tApp.GetStakingKeeper()
|
||||||
|
}
|
||||||
|
|
||||||
|
func coinsAuthGenState(addresses []sdk.AccAddress, coins sdk.Coins) app.GenesisState {
|
||||||
|
coinsList := []sdk.Coins{}
|
||||||
|
for range addresses {
|
||||||
|
coinsList = append(coinsList, coins)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load up our primary user address
|
||||||
|
if len(addresses) >= 4 {
|
||||||
|
coinsList[3] = sdk.NewCoins(
|
||||||
|
sdk.NewCoin("bnb", sdk.NewInt(1000000000000000)),
|
||||||
|
sdk.NewCoin("ukava", sdk.NewInt(1000000000000000)),
|
||||||
|
sdk.NewCoin("btcb", sdk.NewInt(1000000000000000)),
|
||||||
|
sdk.NewCoin("xrp", sdk.NewInt(1000000000000000)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.NewAuthGenState(addresses, coinsList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func stakingGenesisState() app.GenesisState {
|
||||||
|
genState := staking.DefaultGenesisState()
|
||||||
|
genState.Params.BondDenom = "ukava"
|
||||||
|
return app.GenesisState{
|
||||||
|
staking.ModuleName: staking.ModuleCdc.MustMarshalJSON(genState),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KeeperTestSuite) deliverMsgCreateValidator(ctx sdk.Context, address sdk.ValAddress, selfDelegation sdk.Coin) error {
|
||||||
|
msg := staking.NewMsgCreateValidator(
|
||||||
|
address,
|
||||||
|
ed25519.GenPrivKey().PubKey(),
|
||||||
|
selfDelegation,
|
||||||
|
staking.Description{},
|
||||||
|
staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
||||||
|
sdk.NewInt(1_000_000),
|
||||||
|
)
|
||||||
|
handleStakingMsg := staking.NewHandler(suite.stakingKeeper)
|
||||||
|
_, err := handleStakingMsg(ctx, msg)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KeeperTestSuite) deliverMsgDelegate(ctx sdk.Context, delegator sdk.AccAddress, validator sdk.ValAddress, amount sdk.Coin) error {
|
||||||
|
msg := staking.NewMsgDelegate(
|
||||||
|
delegator,
|
||||||
|
validator,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
handleStakingMsg := staking.NewHandler(suite.stakingKeeper)
|
||||||
|
_, err := handleStakingMsg(ctx, msg)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
USDXMintingClaimType = "usdx_minting"
|
USDXMintingClaimType = "usdx_minting"
|
||||||
HardLiquidityProviderClaimType = "hard_liquidity_provider"
|
HardLiquidityProviderClaimType = "hard_liquidity_provider"
|
||||||
|
BondDenom = "ukava"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Claim is an interface for handling common claim actions
|
// Claim is an interface for handling common claim actions
|
||||||
@ -122,23 +123,23 @@ func (cs USDXMintingClaims) Validate() error {
|
|||||||
|
|
||||||
// HardLiquidityProviderClaim stores the hard liquidity provider rewards that can be claimed by owner
|
// HardLiquidityProviderClaim stores the hard liquidity provider rewards that can be claimed by owner
|
||||||
type HardLiquidityProviderClaim struct {
|
type HardLiquidityProviderClaim struct {
|
||||||
BaseClaim `json:"base_claim" yaml:"base_claim"`
|
BaseClaim `json:"base_claim" yaml:"base_claim"`
|
||||||
SupplyRewardIndexes RewardIndexes `json:"supply_reward_indexes" yaml:"supply_reward_indexes"`
|
SupplyRewardIndexes RewardIndexes `json:"supply_reward_indexes" yaml:"supply_reward_indexes"`
|
||||||
BorrowRewardIndexes RewardIndexes `json:"borrow_reward_indexes" yaml:"borrow_reward_indexes"`
|
BorrowRewardIndexes RewardIndexes `json:"borrow_reward_indexes" yaml:"borrow_reward_indexes"`
|
||||||
DelegationRewardIndexes RewardIndexes `json:"delegation_reward_indexes" yaml:"delegation_reward_indexes"`
|
DelegatorRewardIndexes RewardIndexes `json:"delegator_reward_indexes" yaml:"delegator_reward_indexes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHardLiquidityProviderClaim returns a new HardLiquidityProviderClaim
|
// NewHardLiquidityProviderClaim returns a new HardLiquidityProviderClaim
|
||||||
func NewHardLiquidityProviderClaim(owner sdk.AccAddress, reward sdk.Coin, supplyRewardIndexes,
|
func NewHardLiquidityProviderClaim(owner sdk.AccAddress, reward sdk.Coin, supplyRewardIndexes,
|
||||||
borrowRewardIndexes, delegationRewardIndexes RewardIndexes) HardLiquidityProviderClaim {
|
borrowRewardIndexes, delegatorRewardIndexes RewardIndexes) HardLiquidityProviderClaim {
|
||||||
return HardLiquidityProviderClaim{
|
return HardLiquidityProviderClaim{
|
||||||
BaseClaim: BaseClaim{
|
BaseClaim: BaseClaim{
|
||||||
Owner: owner,
|
Owner: owner,
|
||||||
Reward: reward,
|
Reward: reward,
|
||||||
},
|
},
|
||||||
SupplyRewardIndexes: supplyRewardIndexes,
|
SupplyRewardIndexes: supplyRewardIndexes,
|
||||||
BorrowRewardIndexes: borrowRewardIndexes,
|
BorrowRewardIndexes: borrowRewardIndexes,
|
||||||
DelegationRewardIndexes: delegationRewardIndexes,
|
DelegatorRewardIndexes: delegatorRewardIndexes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +156,7 @@ func (c HardLiquidityProviderClaim) Validate() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.DelegationRewardIndexes.Validate(); err != nil {
|
if err := c.DelegatorRewardIndexes.Validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,8 +168,8 @@ func (c HardLiquidityProviderClaim) String() string {
|
|||||||
return fmt.Sprintf(`%s
|
return fmt.Sprintf(`%s
|
||||||
Supply Reward Indexes: %s,
|
Supply Reward Indexes: %s,
|
||||||
Borrow Reward Indexes: %s,
|
Borrow Reward Indexes: %s,
|
||||||
Delegation Reward Indexes: %s,
|
Delegator Reward Indexes: %s,
|
||||||
`, c.BaseClaim, c.SupplyRewardIndexes, c.BorrowRewardIndexes, c.DelegationRewardIndexes)
|
`, c.BaseClaim, c.SupplyRewardIndexes, c.BorrowRewardIndexes, c.DelegatorRewardIndexes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasSupplyRewardIndex check if a claim has a supply reward index for the input collateral type
|
// HasSupplyRewardIndex check if a claim has a supply reward index for the input collateral type
|
||||||
@ -191,9 +192,9 @@ func (c HardLiquidityProviderClaim) HasBorrowRewardIndex(denom string) (int64, b
|
|||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasDelegationRewardIndex check if a claim has a delegation reward index for the input collateral type
|
// HasDelegatorRewardIndex check if a claim has a delegator reward index for the input collateral type
|
||||||
func (c HardLiquidityProviderClaim) HasDelegationRewardIndex(collateralType string) (int64, bool) {
|
func (c HardLiquidityProviderClaim) HasDelegatorRewardIndex(collateralType string) (int64, bool) {
|
||||||
for index, ri := range c.SupplyRewardIndexes {
|
for index, ri := range c.DelegatorRewardIndexes {
|
||||||
if ri.CollateralType == collateralType {
|
if ri.CollateralType == collateralType {
|
||||||
return int64(index), true
|
return int64(index), true
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package types
|
|||||||
import (
|
import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||||
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||||
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"
|
||||||
@ -15,6 +16,13 @@ type SupplyKeeper interface {
|
|||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StakingKeeper defines the expected staking keeper for module accounts
|
||||||
|
type StakingKeeper interface {
|
||||||
|
GetDelegatorDelegations(ctx sdk.Context, delegator sdk.AccAddress, maxRetrieve uint16) (delegations []stakingtypes.Delegation)
|
||||||
|
GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator stakingtypes.Validator, found bool)
|
||||||
|
TotalBondedTokens(ctx sdk.Context) sdk.Int
|
||||||
|
}
|
||||||
|
|
||||||
// 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)
|
GetInterestFactor(ctx sdk.Context, collateralType string) (sdk.Dec, bool)
|
||||||
|
Loading…
Reference in New Issue
Block a user