mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 23:35:19 +00:00
Add weighted bkava support for earn incentives (#1299)
* Add bkava handler for earn incentives * Add bkava accum tests * Add bkava denoms in index state * Set storeTimeEquals to default value * Add supply expected keepers * Add tests for proportional adjustment * Add liquid keeper to incentive keeper * Use weighted reward periods for bkava * Add liquid keeper to tests * Add Accumulate override rewards period with deccoins * Adjust test to handle sub unit coins * Add liquid keeper to test * Fix div by zero for proportional rewards * Update test for actual expected values * Update expected indexes to be same for different vaults * Allow no stored time for vaults that have no indexes or state * Add test for partial bkava deposit * Add math check to test * Deterministically iterate over bkava denoms * Remove unused expected liquid method GetAllDerivativeDenoms
This commit is contained in:
parent
26a4b93588
commit
651de460ca
@ -619,6 +619,8 @@ func NewApp(
|
||||
app.stakingKeeper,
|
||||
&swapKeeper,
|
||||
&savingsKeeper,
|
||||
// TODO: Liquid keeper
|
||||
nil,
|
||||
&earnKeeper,
|
||||
)
|
||||
|
||||
|
@ -36,7 +36,7 @@ func (suite *ClaimTests) TestCannotClaimWhenMultiplierNotRecognised() {
|
||||
},
|
||||
},
|
||||
}
|
||||
suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
claim := types.DelegatorClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
@ -70,7 +70,7 @@ func (suite *ClaimTests) TestCannotClaimAfterEndTime() {
|
||||
ClaimEnd: endTime,
|
||||
},
|
||||
}
|
||||
suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
suite.ctx = suite.ctx.WithBlockTime(endTime.Add(time.Nanosecond))
|
||||
|
||||
|
@ -18,7 +18,12 @@ import (
|
||||
func i(in int64) sdk.Int { return sdk.NewInt(in) }
|
||||
func d(str string) sdk.Dec { return sdk.MustNewDecFromStr(str) }
|
||||
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
|
||||
func dc(denom string, amount string) sdk.DecCoin {
|
||||
return sdk.NewDecCoinFromDec(denom, sdk.MustNewDecFromStr(amount))
|
||||
}
|
||||
func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) }
|
||||
func toDcs(coins ...sdk.Coin) sdk.DecCoins { return sdk.NewDecCoinsFromCoins(coins...) }
|
||||
func dcs(coins ...sdk.DecCoin) sdk.DecCoins { return sdk.NewDecCoins(coins...) }
|
||||
|
||||
func NewCDPGenStateMulti(cdc codec.JSONCodec) app.GenesisState {
|
||||
cdpGenesis := cdptypes.GenesisState{
|
||||
|
@ -22,6 +22,7 @@ type Keeper struct {
|
||||
stakingKeeper types.StakingKeeper
|
||||
swapKeeper types.SwapKeeper
|
||||
savingsKeeper types.SavingsKeeper
|
||||
liquidKeeper types.LiquidKeeper
|
||||
earnKeeper types.EarnKeeper
|
||||
}
|
||||
|
||||
@ -29,7 +30,7 @@ type Keeper struct {
|
||||
func NewKeeper(
|
||||
cdc codec.Codec, key sdk.StoreKey, paramstore types.ParamSubspace, bk types.BankKeeper,
|
||||
cdpk types.CdpKeeper, hk types.HardKeeper, ak types.AccountKeeper, stk types.StakingKeeper,
|
||||
swpk types.SwapKeeper, svk types.SavingsKeeper, ek types.EarnKeeper,
|
||||
swpk types.SwapKeeper, svk types.SavingsKeeper, lqk types.LiquidKeeper, ek types.EarnKeeper,
|
||||
) Keeper {
|
||||
if !paramstore.HasKeyTable() {
|
||||
paramstore = paramstore.WithKeyTable(types.ParamKeyTable())
|
||||
@ -46,6 +47,7 @@ func NewKeeper(
|
||||
stakingKeeper: stk,
|
||||
swapKeeper: swpk,
|
||||
savingsKeeper: svk,
|
||||
liquidKeeper: lqk,
|
||||
earnKeeper: ek,
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ func (suite *AccumulateBorrowRewardsTests) TestStateUpdatedWhenBlockTimeHasIncre
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
suite.storeGlobalBorrowIndexes(types.MultiRewardIndexes{
|
||||
{
|
||||
@ -91,7 +91,7 @@ func (suite *AccumulateBorrowRewardsTests) TestStateUnchangedWhenBlockTimeHasNot
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -136,7 +136,7 @@ func (suite *AccumulateBorrowRewardsTests) TestNoAccumulationWhenSourceSharesAre
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper() // zero total borrows
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -182,7 +182,7 @@ func (suite *AccumulateBorrowRewardsTests) TestStateAddedWhenStateDoesNotExist()
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
@ -225,7 +225,7 @@ func (suite *AccumulateBorrowRewardsTests) TestNoPanicWhenStateDoesNotExist() {
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper()
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
@ -253,7 +253,7 @@ func (suite *AccumulateBorrowRewardsTests) TestNoAccumulationWhenBeforeStartTime
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -299,7 +299,7 @@ func (suite *AccumulateBorrowRewardsTests) TestPanicWhenCurrentTimeLessThanPrevi
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, denom, previousAccrualTime)
|
||||
|
@ -36,7 +36,7 @@ func TestAccumulateDelegatorRewards(t *testing.T) {
|
||||
|
||||
func (suite *AccumulateDelegatorRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreased() {
|
||||
stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
suite.storeGlobalDelegatorIndexes(types.MultiRewardIndexes{
|
||||
{
|
||||
@ -86,7 +86,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestStateUpdatedWhenBlockTimeHasIn
|
||||
|
||||
func (suite *AccumulateDelegatorRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIncreased() {
|
||||
stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -129,7 +129,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestStateUnchangedWhenBlockTimeHas
|
||||
|
||||
func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenSourceSharesAreZero() {
|
||||
stakingKeeper := newFakeStakingKeeper() // zero total bonded
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -173,7 +173,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenSourceShares
|
||||
|
||||
func (suite *AccumulateDelegatorRewardsTests) TestStateAddedWhenStateDoesNotExist() {
|
||||
stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
@ -214,7 +214,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestStateAddedWhenStateDoesNotExis
|
||||
|
||||
func (suite *AccumulateDelegatorRewardsTests) TestNoPanicWhenStateDoesNotExist() {
|
||||
stakingKeeper := newFakeStakingKeeper()
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
@ -240,7 +240,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestNoPanicWhenStateDoesNotExist()
|
||||
|
||||
func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenBeforeStartTime() {
|
||||
stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -284,7 +284,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenBeforeStartT
|
||||
|
||||
func (suite *AccumulateDelegatorRewardsTests) TestPanicWhenCurrentTimeLessThanPrevious() {
|
||||
stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
suite.keeper.SetPreviousDelegatorRewardAccrualTime(suite.ctx, types.BondDenom, previousAccrualTime)
|
||||
|
@ -58,7 +58,7 @@ func (suite *InitializeDelegatorRewardTests) TestClaimIsSyncedAndIndexesAreSetWh
|
||||
DelegatorShares: d("1000"),
|
||||
}},
|
||||
}
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, sk, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, sk, nil, nil, nil, nil)
|
||||
|
||||
claim := types.DelegatorClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
|
@ -37,7 +37,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestClaimIndexesAreUnchangedWhenGl
|
||||
delegator := arbitraryAddress()
|
||||
|
||||
stakingKeeper := &fakeStakingKeeper{} // use an empty staking keeper that returns no delegations
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
claim := types.DelegatorClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
@ -58,7 +58,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestClaimIndexesAreUnchangedWhenGl
|
||||
func (suite *SynchronizeDelegatorRewardTests) TestClaimIndexesAreUpdatedWhenGlobalFactorIncreased() {
|
||||
delegator := arbitraryAddress()
|
||||
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, &fakeStakingKeeper{}, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, &fakeStakingKeeper{}, nil, nil, nil, nil)
|
||||
|
||||
claim := types.DelegatorClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
@ -97,7 +97,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestRewardIsUnchangedWhenGlobalFac
|
||||
unslashedBondedValidator(validatorAddress),
|
||||
},
|
||||
}
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
claim := types.DelegatorClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
@ -142,7 +142,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestRewardIsIncreasedWhenNewReward
|
||||
unslashedBondedValidator(validatorAddress),
|
||||
},
|
||||
}
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
claim := types.DelegatorClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
@ -192,7 +192,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestRewardIsIncreasedWhenGlobalFac
|
||||
unslashedBondedValidator(validatorAddress),
|
||||
},
|
||||
}
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
claim := types.DelegatorClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
@ -299,7 +299,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestGetDelegatedWhenValAddrIsNil()
|
||||
unslashedNotBondedValidator(validatorAddresses[3]),
|
||||
},
|
||||
}
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
suite.Equal(
|
||||
d("11"), // delegation to bonded validators
|
||||
@ -343,7 +343,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestGetDelegatedWhenExcludingAVali
|
||||
unslashedNotBondedValidator(validatorAddresses[3]),
|
||||
},
|
||||
}
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
suite.Equal(
|
||||
d("10"),
|
||||
@ -387,7 +387,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestGetDelegatedWhenIncludingAVali
|
||||
unslashedNotBondedValidator(validatorAddresses[3]),
|
||||
},
|
||||
}
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil, nil)
|
||||
|
||||
suite.Equal(
|
||||
d("111"),
|
||||
|
@ -2,6 +2,9 @@ package keeper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
@ -12,26 +15,137 @@ import (
|
||||
// AccumulateEarnRewards calculates new rewards to distribute this block and updates the global indexes to reflect this.
|
||||
// The provided rewardPeriod must be valid to avoid panics in calculating time durations.
|
||||
func (k Keeper) AccumulateEarnRewards(ctx sdk.Context, rewardPeriod types.MultiRewardPeriod) {
|
||||
previousAccrualTime, found := k.GetEarnRewardAccrualTime(ctx, rewardPeriod.CollateralType)
|
||||
if rewardPeriod.CollateralType == "bkava" {
|
||||
k.accumulateEarnBkavaRewards(ctx, rewardPeriod)
|
||||
return
|
||||
}
|
||||
|
||||
k.accumulateEarnRewards(
|
||||
ctx,
|
||||
rewardPeriod.CollateralType,
|
||||
rewardPeriod.Start,
|
||||
rewardPeriod.End,
|
||||
sdk.NewDecCoinsFromCoins(rewardPeriod.RewardsPerSecond...),
|
||||
)
|
||||
}
|
||||
|
||||
func GetProportionalRewardsPerSecond(
|
||||
rewardPeriod types.MultiRewardPeriod,
|
||||
totalBkavaSupply sdk.Int,
|
||||
singleBkavaSupply sdk.Int,
|
||||
) sdk.DecCoins {
|
||||
// Rate per bkava-xxx = rewardsPerSecond * % of bkava-xxx
|
||||
// = rewardsPerSecond * (bkava-xxx / total bkava)
|
||||
// = (rewardsPerSecond * bkava-xxx) / total bkava
|
||||
|
||||
newRate := sdk.NewDecCoins()
|
||||
|
||||
// Prevent division by zero, if there are no total shares then there are no
|
||||
// rewards.
|
||||
if totalBkavaSupply.IsZero() {
|
||||
return newRate
|
||||
}
|
||||
|
||||
for _, rewardCoin := range rewardPeriod.RewardsPerSecond {
|
||||
scaledAmount := rewardCoin.Amount.ToDec().
|
||||
Mul(singleBkavaSupply.ToDec()).
|
||||
Quo(totalBkavaSupply.ToDec())
|
||||
|
||||
newRate = newRate.Add(sdk.NewDecCoinFromDec(rewardCoin.Denom, scaledAmount))
|
||||
}
|
||||
|
||||
return newRate
|
||||
}
|
||||
|
||||
// accumulateEarnBkavaRewards does the same as AccumulateEarnRewards but for
|
||||
// *all* bkava vaults.
|
||||
func (k Keeper) accumulateEarnBkavaRewards(ctx sdk.Context, rewardPeriod types.MultiRewardPeriod) {
|
||||
// TODO: Get staking rewards and distribute
|
||||
|
||||
// All bkava vault denoms
|
||||
bkavaVaultsDenoms := make(map[string]bool)
|
||||
|
||||
// bkava vault denoms from earn records (non-empty vaults)
|
||||
k.earnKeeper.IterateVaultRecords(ctx, func(record earntypes.VaultRecord) (stop bool) {
|
||||
// TODO: Replace with single bkava denom check method from liquid
|
||||
if strings.HasPrefix(record.TotalShares.Denom, "bkava-") {
|
||||
bkavaVaultsDenoms[record.TotalShares.Denom] = true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
// bkava vault denoms from past incentive indexes, may include vaults
|
||||
// that were fully withdrawn.
|
||||
k.IterateEarnRewardIndexes(ctx, func(vaultDenom string, indexes types.RewardIndexes) (stop bool) {
|
||||
if strings.HasPrefix(vaultDenom, "bkava-") {
|
||||
bkavaVaultsDenoms[vaultDenom] = true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
totalBkavaSupply := k.liquidKeeper.GetTotalDerivativeSupply(ctx)
|
||||
|
||||
i := 0
|
||||
sortedBkavaVaultsDenoms := make([]string, len(bkavaVaultsDenoms))
|
||||
for vaultDenom := range bkavaVaultsDenoms {
|
||||
sortedBkavaVaultsDenoms[i] = vaultDenom
|
||||
i++
|
||||
}
|
||||
|
||||
// Sort the vault denoms to ensure deterministic iteration order.
|
||||
sort.Strings(sortedBkavaVaultsDenoms)
|
||||
|
||||
// Accumulate rewards for each bkava vault.
|
||||
for _, bkavaDenom := range sortedBkavaVaultsDenoms {
|
||||
k.accumulateEarnRewards(
|
||||
ctx,
|
||||
bkavaDenom,
|
||||
rewardPeriod.Start,
|
||||
rewardPeriod.End,
|
||||
GetProportionalRewardsPerSecond(
|
||||
rewardPeriod,
|
||||
totalBkavaSupply,
|
||||
k.liquidKeeper.GetDerivativeSupply(ctx, bkavaDenom),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (k Keeper) accumulateEarnRewards(
|
||||
ctx sdk.Context,
|
||||
collateralType string,
|
||||
periodStart time.Time,
|
||||
periodEnd time.Time,
|
||||
periodRewardsPerSecond sdk.DecCoins,
|
||||
) {
|
||||
previousAccrualTime, found := k.GetEarnRewardAccrualTime(ctx, collateralType)
|
||||
if !found {
|
||||
previousAccrualTime = ctx.BlockTime()
|
||||
}
|
||||
|
||||
indexes, found := k.GetEarnRewardIndexes(ctx, rewardPeriod.CollateralType)
|
||||
indexes, found := k.GetEarnRewardIndexes(ctx, collateralType)
|
||||
if !found {
|
||||
indexes = types.RewardIndexes{}
|
||||
}
|
||||
|
||||
acc := types.NewAccumulator(previousAccrualTime, indexes)
|
||||
|
||||
totalSource := k.getEarnTotalSourceShares(ctx, rewardPeriod.CollateralType)
|
||||
totalSourceShares := k.getEarnTotalSourceShares(ctx, collateralType)
|
||||
|
||||
acc.Accumulate(rewardPeriod, totalSource, ctx.BlockTime())
|
||||
acc.AccumulateDecCoins(
|
||||
periodStart,
|
||||
periodEnd,
|
||||
periodRewardsPerSecond,
|
||||
totalSourceShares,
|
||||
ctx.BlockTime(),
|
||||
)
|
||||
|
||||
k.SetEarnRewardAccrualTime(ctx, rewardPeriod.CollateralType, acc.PreviousAccumulationTime)
|
||||
k.SetEarnRewardAccrualTime(ctx, collateralType, acc.PreviousAccumulationTime)
|
||||
if len(acc.Indexes) > 0 {
|
||||
// the store panics when setting empty or nil indexes
|
||||
k.SetEarnRewardIndexes(ctx, rewardPeriod.CollateralType, acc.Indexes)
|
||||
k.SetEarnRewardIndexes(ctx, collateralType, acc.Indexes)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,12 @@ type AccumulateEarnRewardsTests struct {
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) storedTimeEquals(vaultDenom string, expected time.Time) {
|
||||
storedTime, found := suite.keeper.GetEarnRewardAccrualTime(suite.ctx, vaultDenom)
|
||||
suite.True(found)
|
||||
suite.Equal(expected, storedTime)
|
||||
suite.Equal(found, expected != time.Time{}, "expected time is %v but time found = %v", expected, found)
|
||||
if found {
|
||||
suite.Equal(expected, storedTime)
|
||||
} else {
|
||||
suite.Empty(storedTime)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) storedIndexesEqual(vaultDenom string, expected types.RewardIndexes) {
|
||||
@ -38,7 +42,7 @@ func (suite *AccumulateEarnRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreas
|
||||
vaultDenom := "usdx"
|
||||
|
||||
earnKeeper := newFakeEarnKeeper().addVault(vaultDenom, earntypes.NewVaultShare(vaultDenom, d("1000000")))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
|
||||
suite.storeGlobalEarnIndexes(types.MultiRewardIndexes{
|
||||
{
|
||||
@ -86,11 +90,222 @@ func (suite *AccumulateEarnRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreas
|
||||
})
|
||||
}
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreased_bkava() {
|
||||
vaultDenom1 := "bkava-meow"
|
||||
vaultDenom2 := "bkava-woof"
|
||||
|
||||
earnKeeper := newFakeEarnKeeper().
|
||||
addVault(vaultDenom1, earntypes.NewVaultShare(vaultDenom1, d("800000"))).
|
||||
addVault(vaultDenom2, earntypes.NewVaultShare(vaultDenom2, d("200000")))
|
||||
|
||||
liquidKeeper := newFakeLiquidKeeper().
|
||||
addDerivative(vaultDenom1, i(800000)).
|
||||
addDerivative(vaultDenom2, i(200000))
|
||||
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, liquidKeeper, earnKeeper)
|
||||
|
||||
globalIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
CollateralType: vaultDenom1,
|
||||
RewardIndexes: types.RewardIndexes{
|
||||
{
|
||||
CollateralType: "earn",
|
||||
RewardFactor: d("0.02"),
|
||||
},
|
||||
{
|
||||
CollateralType: "ukava",
|
||||
RewardFactor: d("0.04"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
CollateralType: vaultDenom2,
|
||||
RewardIndexes: types.RewardIndexes{
|
||||
{
|
||||
CollateralType: "earn",
|
||||
RewardFactor: d("0.02"),
|
||||
},
|
||||
{
|
||||
CollateralType: "ukava",
|
||||
RewardFactor: d("0.04"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
suite.storeGlobalEarnIndexes(globalIndexes)
|
||||
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom1, previousAccrualTime)
|
||||
suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom2, previousAccrualTime)
|
||||
|
||||
newAccrualTime := previousAccrualTime.Add(1 * time.Hour)
|
||||
suite.ctx = suite.ctx.WithBlockTime(newAccrualTime)
|
||||
|
||||
rewardPeriod := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
"bkava", // reward period is set for "bkava" to apply to all vaults
|
||||
time.Unix(0, 0), // ensure the test is within start and end times
|
||||
distantFuture,
|
||||
cs(c("earn", 2000), c("ukava", 1000)), // same denoms as in global indexes
|
||||
)
|
||||
suite.keeper.AccumulateEarnRewards(suite.ctx, rewardPeriod)
|
||||
|
||||
// check time and factors
|
||||
|
||||
suite.storedTimeEquals(vaultDenom1, newAccrualTime)
|
||||
suite.storedTimeEquals(vaultDenom2, newAccrualTime)
|
||||
|
||||
// Each vault gets the same ukava per second, assuming shares prices are the same.
|
||||
// The share amount determines how much is actually distributed to the vault.
|
||||
expectedIndexes := types.RewardIndexes{
|
||||
{
|
||||
CollateralType: "earn",
|
||||
RewardFactor: d("7.22"),
|
||||
},
|
||||
{
|
||||
CollateralType: "ukava",
|
||||
RewardFactor: d("3.64"),
|
||||
},
|
||||
}
|
||||
|
||||
suite.storedIndexesEqual(vaultDenom1, expectedIndexes)
|
||||
suite.storedIndexesEqual(vaultDenom2, expectedIndexes)
|
||||
}
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreased_bkava_partialDeposit() {
|
||||
vaultDenom1 := "bkava-meow"
|
||||
vaultDenom2 := "bkava-woof"
|
||||
|
||||
vaultDenom1Supply := i(800000)
|
||||
vaultDenom2Supply := i(200000)
|
||||
|
||||
liquidKeeper := newFakeLiquidKeeper().
|
||||
addDerivative(vaultDenom1, vaultDenom1Supply).
|
||||
addDerivative(vaultDenom2, vaultDenom2Supply)
|
||||
|
||||
vault2Shares := d("100000")
|
||||
|
||||
// More bkava minted than deposited into earn
|
||||
// Rewards are higher per-share as a result
|
||||
earnKeeper := newFakeEarnKeeper().
|
||||
addVault(vaultDenom1, earntypes.NewVaultShare(vaultDenom1, d("700000"))).
|
||||
addVault(vaultDenom2, earntypes.NewVaultShare(vaultDenom2, vault2Shares))
|
||||
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, liquidKeeper, earnKeeper)
|
||||
|
||||
globalIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
CollateralType: vaultDenom1,
|
||||
RewardIndexes: types.RewardIndexes{
|
||||
{
|
||||
CollateralType: "earn",
|
||||
RewardFactor: d("0.02"),
|
||||
},
|
||||
{
|
||||
CollateralType: "ukava",
|
||||
RewardFactor: d("0.04"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
CollateralType: vaultDenom2,
|
||||
RewardIndexes: types.RewardIndexes{
|
||||
{
|
||||
CollateralType: "earn",
|
||||
RewardFactor: d("0.02"),
|
||||
},
|
||||
{
|
||||
CollateralType: "ukava",
|
||||
RewardFactor: d("0.04"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
suite.storeGlobalEarnIndexes(globalIndexes)
|
||||
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom1, previousAccrualTime)
|
||||
suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom2, previousAccrualTime)
|
||||
|
||||
newAccrualTime := previousAccrualTime.Add(1 * time.Hour)
|
||||
suite.ctx = suite.ctx.WithBlockTime(newAccrualTime)
|
||||
|
||||
rewardPeriod := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
"bkava", // reward period is set for "bkava" to apply to all vaults
|
||||
time.Unix(0, 0), // ensure the test is within start and end times
|
||||
distantFuture,
|
||||
cs(c("earn", 2000), c("ukava", 1000)), // same denoms as in global indexes
|
||||
)
|
||||
suite.keeper.AccumulateEarnRewards(suite.ctx, rewardPeriod)
|
||||
|
||||
// check time and factors
|
||||
|
||||
suite.storedTimeEquals(vaultDenom1, newAccrualTime)
|
||||
suite.storedTimeEquals(vaultDenom2, newAccrualTime)
|
||||
|
||||
// Slightly increased rewards due to less bkava deposited
|
||||
suite.storedIndexesEqual(vaultDenom1, types.RewardIndexes{
|
||||
{
|
||||
CollateralType: "earn",
|
||||
RewardFactor: d("8.248571428571428571"),
|
||||
},
|
||||
{
|
||||
CollateralType: "ukava",
|
||||
RewardFactor: d("4.154285714285714286"),
|
||||
},
|
||||
})
|
||||
|
||||
// Much higher rewards per share because only a small amount of bkava is
|
||||
// deposited. The **total** amount of incentives distributed to this vault
|
||||
// is still the same proportional amount.
|
||||
|
||||
// Fixed amount total rewards distributed to the vault
|
||||
// Fewer shares deposited -> higher rewards per share
|
||||
|
||||
// 7.2ukava shares per second for 1 hour (started with 0.04)
|
||||
// total rewards claimable = 7.2 * 100000 shares = 720000 ukava
|
||||
|
||||
// 720000ukava distributed which is 20% of total bkava ukava rewards
|
||||
// total rewards for *all* bkava vaults for 1 hour
|
||||
// = 1000ukava per second * 3600 == 3600000ukava
|
||||
// vaultDenom2 has 20% of the total bkava amount so it should get 20% of 3600000ukava == 720000ukava
|
||||
|
||||
vault2expectedIndexes := types.RewardIndexes{
|
||||
{
|
||||
CollateralType: "earn",
|
||||
RewardFactor: d("14.42"),
|
||||
},
|
||||
{
|
||||
CollateralType: "ukava",
|
||||
RewardFactor: d("7.24"),
|
||||
},
|
||||
}
|
||||
suite.storedIndexesEqual(vaultDenom2, vault2expectedIndexes)
|
||||
|
||||
// Verify math described above
|
||||
totalVault2DistributedUkava := i(int64(time.Hour.Seconds())).
|
||||
ToDec().
|
||||
Mul(rewardPeriod.RewardsPerSecond.AmountOf("ukava").ToDec()).
|
||||
// 20% of total rewards
|
||||
// vault 2 supply / (vault 1 supply + vault 2 supply)
|
||||
Mul(
|
||||
vaultDenom2Supply.ToDec().
|
||||
Quo(vaultDenom1Supply.Add(vaultDenom2Supply).ToDec()),
|
||||
)
|
||||
|
||||
totalVault2ClaimableRewards := vault2expectedIndexes[1].
|
||||
RewardFactor.Sub(d("0.04")). // Rewards per share for 1 hr, excluding the starting value
|
||||
Mul(vault2Shares) // * Shares in vault to get total rewards for entire vault
|
||||
|
||||
suite.Equal(totalVault2DistributedUkava, totalVault2ClaimableRewards)
|
||||
}
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIncreased() {
|
||||
vaultDenom := "usdx"
|
||||
|
||||
earnKeeper := newFakeEarnKeeper().addVault(vaultDenom, earntypes.NewVaultShare(vaultDenom, d("1000000")))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -131,11 +346,86 @@ func (suite *AccumulateEarnRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIn
|
||||
suite.storedIndexesEqual(vaultDenom, expected)
|
||||
}
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIncreased_bkava() {
|
||||
vaultDenom1 := "bkava-meow"
|
||||
vaultDenom2 := "bkava-woof"
|
||||
|
||||
earnKeeper := newFakeEarnKeeper().
|
||||
addVault(vaultDenom1, earntypes.NewVaultShare(vaultDenom1, d("1000000"))).
|
||||
addVault(vaultDenom2, earntypes.NewVaultShare(vaultDenom2, d("1000000")))
|
||||
|
||||
liquidKeeper := newFakeLiquidKeeper().
|
||||
addDerivative(vaultDenom1, i(1000000)).
|
||||
addDerivative(vaultDenom2, i(1000000))
|
||||
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, liquidKeeper, earnKeeper)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
CollateralType: vaultDenom1,
|
||||
RewardIndexes: types.RewardIndexes{
|
||||
{
|
||||
CollateralType: "earn",
|
||||
RewardFactor: d("0.02"),
|
||||
},
|
||||
{
|
||||
CollateralType: "ukava",
|
||||
RewardFactor: d("0.04"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
CollateralType: vaultDenom2,
|
||||
RewardIndexes: types.RewardIndexes{
|
||||
{
|
||||
CollateralType: "earn",
|
||||
RewardFactor: d("0.02"),
|
||||
},
|
||||
{
|
||||
CollateralType: "ukava",
|
||||
RewardFactor: d("0.04"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
suite.storeGlobalEarnIndexes(previousIndexes)
|
||||
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom1, previousAccrualTime)
|
||||
suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom2, previousAccrualTime)
|
||||
|
||||
suite.ctx = suite.ctx.WithBlockTime(previousAccrualTime)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
"bkava",
|
||||
time.Unix(0, 0), // ensure the test is within start and end times
|
||||
distantFuture,
|
||||
cs(c("earn", 2000), c("ukava", 1000)), // same denoms as in global indexes
|
||||
)
|
||||
|
||||
suite.keeper.AccumulateEarnRewards(suite.ctx, period)
|
||||
|
||||
// check time and factors
|
||||
|
||||
suite.storedTimeEquals(vaultDenom1, previousAccrualTime)
|
||||
suite.storedTimeEquals(vaultDenom2, previousAccrualTime)
|
||||
|
||||
expected, f := previousIndexes.Get(vaultDenom1)
|
||||
suite.True(f)
|
||||
suite.storedIndexesEqual(vaultDenom1, expected)
|
||||
|
||||
expected, f = previousIndexes.Get(vaultDenom2)
|
||||
suite.True(f)
|
||||
suite.storedIndexesEqual(vaultDenom2, expected)
|
||||
}
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) TestNoAccumulationWhenSourceSharesAreZero() {
|
||||
vaultDenom := "usdx"
|
||||
|
||||
earnKeeper := newFakeEarnKeeper() // no vault, so no source shares
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
liquidKeeper := newFakeLiquidKeeper()
|
||||
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, liquidKeeper, earnKeeper)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -177,11 +467,82 @@ func (suite *AccumulateEarnRewardsTests) TestNoAccumulationWhenSourceSharesAreZe
|
||||
suite.storedIndexesEqual(vaultDenom, expected)
|
||||
}
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) TestNoAccumulationWhenSourceSharesAreZero_bkava() {
|
||||
vaultDenom1 := "bkava-meow"
|
||||
vaultDenom2 := "bkava-woof"
|
||||
|
||||
earnKeeper := newFakeEarnKeeper() // no vault, so no source shares
|
||||
liquidKeeper := newFakeLiquidKeeper()
|
||||
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, liquidKeeper, earnKeeper)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
CollateralType: vaultDenom1,
|
||||
RewardIndexes: types.RewardIndexes{
|
||||
{
|
||||
CollateralType: "earn",
|
||||
RewardFactor: d("0.02"),
|
||||
},
|
||||
{
|
||||
CollateralType: "ukava",
|
||||
RewardFactor: d("0.04"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
CollateralType: vaultDenom2,
|
||||
RewardIndexes: types.RewardIndexes{
|
||||
{
|
||||
CollateralType: "earn",
|
||||
RewardFactor: d("0.02"),
|
||||
},
|
||||
{
|
||||
CollateralType: "ukava",
|
||||
RewardFactor: d("0.04"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
suite.storeGlobalEarnIndexes(previousIndexes)
|
||||
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom1, previousAccrualTime)
|
||||
suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom2, previousAccrualTime)
|
||||
|
||||
firstAccrualTime := previousAccrualTime.Add(7 * time.Second)
|
||||
suite.ctx = suite.ctx.WithBlockTime(firstAccrualTime)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
"bkava",
|
||||
time.Unix(0, 0), // ensure the test is within start and end times
|
||||
distantFuture,
|
||||
cs(c("earn", 2000), c("ukava", 1000)), // same denoms as in global indexes
|
||||
)
|
||||
|
||||
// TODO: There are no bkava vaults to iterate over, so the accrual times are
|
||||
// not updated
|
||||
suite.keeper.AccumulateEarnRewards(suite.ctx, period)
|
||||
|
||||
// check time and factors
|
||||
|
||||
suite.storedTimeEquals(vaultDenom1, firstAccrualTime)
|
||||
suite.storedTimeEquals(vaultDenom2, firstAccrualTime)
|
||||
|
||||
expected, f := previousIndexes.Get(vaultDenom1)
|
||||
suite.True(f)
|
||||
suite.storedIndexesEqual(vaultDenom1, expected)
|
||||
|
||||
expected, f = previousIndexes.Get(vaultDenom2)
|
||||
suite.True(f)
|
||||
suite.storedIndexesEqual(vaultDenom2, expected)
|
||||
}
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) TestStateAddedWhenStateDoesNotExist() {
|
||||
vaultDenom := "usdx"
|
||||
|
||||
earnKeeper := newFakeEarnKeeper().addVault(vaultDenom, earntypes.NewVaultShare(vaultDenom, d("1000000")))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
@ -220,11 +581,70 @@ func (suite *AccumulateEarnRewardsTests) TestStateAddedWhenStateDoesNotExist() {
|
||||
})
|
||||
}
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) TestStateAddedWhenStateDoesNotExist_bkava() {
|
||||
vaultDenom1 := "bkava-meow"
|
||||
vaultDenom2 := "bkava-woof"
|
||||
|
||||
earnKeeper := newFakeEarnKeeper().
|
||||
addVault(vaultDenom1, earntypes.NewVaultShare(vaultDenom1, d("1000000"))).
|
||||
addVault(vaultDenom2, earntypes.NewVaultShare(vaultDenom2, d("1000000")))
|
||||
|
||||
liquidKeeper := newFakeLiquidKeeper().
|
||||
addDerivative(vaultDenom1, i(1000000)).
|
||||
addDerivative(vaultDenom2, i(1000000))
|
||||
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, liquidKeeper, earnKeeper)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
"bkava",
|
||||
time.Unix(0, 0), // ensure the test is within start and end times
|
||||
distantFuture,
|
||||
cs(c("earn", 2000), c("ukava", 1000)),
|
||||
)
|
||||
|
||||
firstAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
suite.ctx = suite.ctx.WithBlockTime(firstAccrualTime)
|
||||
|
||||
suite.keeper.AccumulateEarnRewards(suite.ctx, period)
|
||||
|
||||
// After the first accumulation only the current block time should be stored.
|
||||
// The indexes will be empty as no time has passed since the previous block because it didn't exist.
|
||||
suite.storedTimeEquals(vaultDenom1, firstAccrualTime)
|
||||
suite.storedTimeEquals(vaultDenom2, firstAccrualTime)
|
||||
|
||||
suite.storedIndexesEqual(vaultDenom1, nil)
|
||||
suite.storedIndexesEqual(vaultDenom2, nil)
|
||||
|
||||
secondAccrualTime := firstAccrualTime.Add(10 * time.Second)
|
||||
suite.ctx = suite.ctx.WithBlockTime(secondAccrualTime)
|
||||
|
||||
suite.keeper.AccumulateEarnRewards(suite.ctx, period)
|
||||
|
||||
// After the second accumulation both current block time and indexes should be stored.
|
||||
suite.storedTimeEquals(vaultDenom1, secondAccrualTime)
|
||||
suite.storedTimeEquals(vaultDenom2, secondAccrualTime)
|
||||
|
||||
expectedIndexes := types.RewardIndexes{
|
||||
{
|
||||
CollateralType: "earn",
|
||||
RewardFactor: d("0.01"),
|
||||
},
|
||||
{
|
||||
CollateralType: "ukava",
|
||||
RewardFactor: d("0.005"),
|
||||
},
|
||||
}
|
||||
|
||||
suite.storedIndexesEqual(vaultDenom1, expectedIndexes)
|
||||
suite.storedIndexesEqual(vaultDenom2, expectedIndexes)
|
||||
}
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) TestNoPanicWhenStateDoesNotExist() {
|
||||
vaultDenom := "usdx"
|
||||
|
||||
earnKeeper := newFakeEarnKeeper()
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
@ -248,11 +668,47 @@ func (suite *AccumulateEarnRewardsTests) TestNoPanicWhenStateDoesNotExist() {
|
||||
suite.storedIndexesEqual(vaultDenom, nil)
|
||||
}
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) TestNoPanicWhenStateDoesNotExist_bkava() {
|
||||
vaultDenom1 := "bkava-meow"
|
||||
vaultDenom2 := "bkava-woof"
|
||||
|
||||
earnKeeper := newFakeEarnKeeper()
|
||||
liquidKeeper := newFakeLiquidKeeper()
|
||||
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, liquidKeeper, earnKeeper)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
"bkava",
|
||||
time.Unix(0, 0), // ensure the test is within start and end times
|
||||
distantFuture,
|
||||
cs(),
|
||||
)
|
||||
|
||||
accrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
suite.ctx = suite.ctx.WithBlockTime(accrualTime)
|
||||
|
||||
// Accumulate with no earn shares and no rewards per second will result in no increment to the indexes.
|
||||
// No increment and no previous indexes stored, results in an updated of nil. Setting this in the state panics.
|
||||
// Check there is no panic.
|
||||
suite.NotPanics(func() {
|
||||
// This does not update any state, as there are no bkava vaults
|
||||
// to iterate over, denoms are unknown
|
||||
suite.keeper.AccumulateEarnRewards(suite.ctx, period)
|
||||
})
|
||||
|
||||
// Times are not stored for vaults with no state
|
||||
suite.storedTimeEquals(vaultDenom1, time.Time{})
|
||||
suite.storedTimeEquals(vaultDenom2, time.Time{})
|
||||
suite.storedIndexesEqual(vaultDenom1, nil)
|
||||
suite.storedIndexesEqual(vaultDenom2, nil)
|
||||
}
|
||||
|
||||
func (suite *AccumulateEarnRewardsTests) TestNoAccumulationWhenBeforeStartTime() {
|
||||
vaultDenom := "usdx"
|
||||
|
||||
earnKeeper := newFakeEarnKeeper().addVault(vaultDenom, earntypes.NewVaultShare(vaultDenom, d("1000000")))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -298,7 +754,7 @@ func (suite *AccumulateEarnRewardsTests) TestPanicWhenCurrentTimeLessThanPreviou
|
||||
vaultDenom := "usdx"
|
||||
|
||||
earnKeeper := newFakeEarnKeeper().addVault(vaultDenom, earntypes.NewVaultShare(vaultDenom, d("1000000")))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
|
||||
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom, previousAccrualTime)
|
||||
|
86
x/incentive/keeper/rewards_earn_proportional_test.go
Normal file
86
x/incentive/keeper/rewards_earn_proportional_test.go
Normal file
@ -0,0 +1,86 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/kava-labs/kava/x/incentive/keeper"
|
||||
"github.com/kava-labs/kava/x/incentive/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetProportionalRewardPeriod(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
giveRewardPeriod types.MultiRewardPeriod
|
||||
giveTotalBkavaSupply sdk.Int
|
||||
giveSingleBkavaSupply sdk.Int
|
||||
wantRewardsPerSecond sdk.DecCoins
|
||||
}{
|
||||
{
|
||||
"full amount",
|
||||
types.NewMultiRewardPeriod(
|
||||
true,
|
||||
"",
|
||||
time.Time{},
|
||||
time.Time{},
|
||||
cs(c("ukava", 100), c("hard", 200)),
|
||||
),
|
||||
i(100),
|
||||
i(100),
|
||||
toDcs(c("ukava", 100), c("hard", 200)),
|
||||
},
|
||||
{
|
||||
"3/4 amount",
|
||||
types.NewMultiRewardPeriod(
|
||||
true,
|
||||
"",
|
||||
time.Time{},
|
||||
time.Time{},
|
||||
cs(c("ukava", 100), c("hard", 200)),
|
||||
),
|
||||
i(10_000000),
|
||||
i(7_500000),
|
||||
toDcs(c("ukava", 75), c("hard", 150)),
|
||||
},
|
||||
{
|
||||
"half amount",
|
||||
types.NewMultiRewardPeriod(
|
||||
true,
|
||||
"",
|
||||
time.Time{},
|
||||
time.Time{},
|
||||
cs(c("ukava", 100), c("hard", 200)),
|
||||
),
|
||||
i(100),
|
||||
i(50),
|
||||
toDcs(c("ukava", 50), c("hard", 100)),
|
||||
},
|
||||
{
|
||||
"under 1 unit",
|
||||
types.NewMultiRewardPeriod(
|
||||
true,
|
||||
"",
|
||||
time.Time{},
|
||||
time.Time{},
|
||||
cs(c("ukava", 100), c("hard", 200)),
|
||||
),
|
||||
i(1000), // total bkava
|
||||
i(1), // bkava supply of this specific vault
|
||||
dcs(dc("ukava", "0.1"), dc("hard", "0.2")), // rewards per second rounded to 0 if under 1ukava/1hard
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
rewardsPerSecond := keeper.GetProportionalRewardsPerSecond(
|
||||
tt.giveRewardPeriod,
|
||||
tt.giveTotalBkavaSupply,
|
||||
tt.giveSingleBkavaSupply,
|
||||
)
|
||||
|
||||
require.Equal(t, tt.wantRewardsPerSecond, rewardsPerSecond)
|
||||
})
|
||||
}
|
||||
}
|
@ -324,7 +324,7 @@ func (suite *SynchronizeEarnRewardTests) TestGetSyncedClaim_ClaimUnchangedWhenNo
|
||||
|
||||
earnKeeper := newFakeEarnKeeper().
|
||||
addDeposit(owner, earntypes.NewVaultShare("usdx", d("1000000000")))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
|
||||
claim := types.EarnClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
@ -357,7 +357,7 @@ func (suite *SynchronizeEarnRewardTests) TestGetSyncedClaim_ClaimUpdatedWhenMiss
|
||||
owner := arbitraryAddress()
|
||||
|
||||
// owner has no shares in any vault
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, newFakeEarnKeeper())
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, nil, newFakeEarnKeeper())
|
||||
|
||||
claim := types.EarnClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
@ -419,7 +419,7 @@ func (suite *SynchronizeEarnRewardTests) TestGetSyncedClaim_ClaimUpdatedWhenMiss
|
||||
addVault(VaultDenom_2, earntypes.NewVaultShare(VaultDenom_2, d("1000000000"))).
|
||||
addDeposit(owner, earntypes.NewVaultShare(VaultDenom_1, d("1000000000"))).
|
||||
addDeposit(owner, earntypes.NewVaultShare(VaultDenom_2, d("1000000000")))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, nil, earnKeeper)
|
||||
|
||||
claim := types.EarnClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
|
@ -38,7 +38,7 @@ func (suite *AccumulateSupplyRewardsTests) TestStateUpdatedWhenBlockTimeHasIncre
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
suite.storeGlobalSupplyIndexes(types.MultiRewardIndexes{
|
||||
{
|
||||
@ -90,7 +90,7 @@ func (suite *AccumulateSupplyRewardsTests) TestStateUnchangedWhenBlockTimeHasNot
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -135,7 +135,7 @@ func (suite *AccumulateSupplyRewardsTests) TestNoAccumulationWhenSourceSharesAre
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper() // zero total supplys
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -181,7 +181,7 @@ func (suite *AccumulateSupplyRewardsTests) TestStateAddedWhenStateDoesNotExist()
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
@ -224,7 +224,7 @@ func (suite *AccumulateSupplyRewardsTests) TestNoPanicWhenStateDoesNotExist() {
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper()
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
@ -252,7 +252,7 @@ func (suite *AccumulateSupplyRewardsTests) TestNoAccumulationWhenBeforeStartTime
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -298,7 +298,7 @@ func (suite *AccumulateSupplyRewardsTests) TestPanicWhenCurrentTimeLessThanPrevi
|
||||
denom := "bnb"
|
||||
|
||||
hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, denom, previousAccrualTime)
|
||||
|
@ -37,7 +37,7 @@ func (suite *AccumulateSwapRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreas
|
||||
pool := "btc:usdx"
|
||||
|
||||
swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil, nil)
|
||||
|
||||
suite.storeGlobalSwapIndexes(types.MultiRewardIndexes{
|
||||
{
|
||||
@ -89,7 +89,7 @@ func (suite *AccumulateSwapRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIn
|
||||
pool := "btc:usdx"
|
||||
|
||||
swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -134,7 +134,7 @@ func (suite *AccumulateSwapRewardsTests) TestNoAccumulationWhenSourceSharesAreZe
|
||||
pool := "btc:usdx"
|
||||
|
||||
swapKeeper := newFakeSwapKeeper() // no pools, so no source shares
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -180,7 +180,7 @@ func (suite *AccumulateSwapRewardsTests) TestStateAddedWhenStateDoesNotExist() {
|
||||
pool := "btc:usdx"
|
||||
|
||||
swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil, nil)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
@ -223,7 +223,7 @@ func (suite *AccumulateSwapRewardsTests) TestNoPanicWhenStateDoesNotExist() {
|
||||
pool := "btc:usdx"
|
||||
|
||||
swapKeeper := newFakeSwapKeeper()
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil, nil)
|
||||
|
||||
period := types.NewMultiRewardPeriod(
|
||||
true,
|
||||
@ -251,7 +251,7 @@ func (suite *AccumulateSwapRewardsTests) TestNoAccumulationWhenBeforeStartTime()
|
||||
pool := "btc:usdx"
|
||||
|
||||
swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.MultiRewardIndexes{
|
||||
{
|
||||
@ -297,7 +297,7 @@ func (suite *AccumulateSwapRewardsTests) TestPanicWhenCurrentTimeLessThanPreviou
|
||||
pool := "btc:usdx"
|
||||
|
||||
swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil, nil)
|
||||
|
||||
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
suite.keeper.SetSwapRewardAccrualTime(suite.ctx, pool, previousAccrualTime)
|
||||
|
@ -323,7 +323,7 @@ func (suite *SynchronizeSwapRewardTests) TestGetSyncedClaim_ClaimUnchangedWhenNo
|
||||
|
||||
swapKeeper := newFakeSwapKeeper().
|
||||
addDeposit(poolID_1, owner, i(1e9))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil, nil)
|
||||
|
||||
claim := types.SwapClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
@ -356,7 +356,7 @@ func (suite *SynchronizeSwapRewardTests) TestGetSyncedClaim_ClaimUpdatedWhenMiss
|
||||
owner := arbitraryAddress()
|
||||
|
||||
// owner has no shares in any pool
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, newFakeSwapKeeper(), nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, newFakeSwapKeeper(), nil, nil, nil)
|
||||
|
||||
claim := types.SwapClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
@ -416,7 +416,7 @@ func (suite *SynchronizeSwapRewardTests) TestGetSyncedClaim_ClaimUpdatedWhenMiss
|
||||
swapKeeper := newFakeSwapKeeper().
|
||||
addDeposit(poolID_1, owner, i(1e9)).
|
||||
addDeposit(poolID_2, owner, i(1e9))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil, nil)
|
||||
|
||||
claim := types.SwapClaim{
|
||||
BaseMultiClaim: types.BaseMultiClaim{
|
||||
|
@ -34,7 +34,7 @@ func (suite *AccumulateUSDXRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreas
|
||||
cType := "bnb-a"
|
||||
|
||||
cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
suite.storeGlobalUSDXIndexes(types.RewardIndexes{
|
||||
{
|
||||
@ -68,7 +68,7 @@ func (suite *AccumulateUSDXRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIn
|
||||
cType := "bnb-a"
|
||||
|
||||
cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.RewardIndexes{
|
||||
{
|
||||
@ -104,7 +104,7 @@ func (suite *AccumulateUSDXRewardsTests) TestNoAccumulationWhenSourceSharesAreZe
|
||||
cType := "bnb-a"
|
||||
|
||||
cdpKeeper := newFakeCDPKeeper() // zero total borrows
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.RewardIndexes{
|
||||
{
|
||||
@ -141,7 +141,7 @@ func (suite *AccumulateUSDXRewardsTests) TestStateAddedWhenStateDoesNotExist() {
|
||||
cType := "bnb-a"
|
||||
|
||||
cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
period := types.NewRewardPeriod(
|
||||
true,
|
||||
@ -174,7 +174,7 @@ func (suite *AccumulateUSDXRewardsTests) TestNoAccumulationWhenBeforeStartTime()
|
||||
cType := "bnb-a"
|
||||
|
||||
cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
previousIndexes := types.RewardIndexes{
|
||||
{
|
||||
@ -211,7 +211,7 @@ func (suite *AccumulateUSDXRewardsTests) TestPanicWhenCurrentTimeLessThanPreviou
|
||||
cType := "bnb-a"
|
||||
|
||||
cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1"))
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, cType, previousAccrualTime)
|
||||
|
@ -2,6 +2,7 @@ package keeper_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
@ -59,7 +60,7 @@ func (suite *unitTester) SetupSuite() {
|
||||
|
||||
func (suite *unitTester) SetupTest() {
|
||||
suite.ctx = NewTestContext(suite.incentiveStoreKey)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, nil)
|
||||
suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, nil, nil)
|
||||
}
|
||||
|
||||
func (suite *unitTester) TearDownTest() {
|
||||
@ -67,8 +68,13 @@ func (suite *unitTester) TearDownTest() {
|
||||
suite.ctx = sdk.Context{}
|
||||
}
|
||||
|
||||
func (suite *unitTester) NewKeeper(paramSubspace types.ParamSubspace, bk types.BankKeeper, cdpk types.CdpKeeper, hk types.HardKeeper, ak types.AccountKeeper, stk types.StakingKeeper, swk types.SwapKeeper, svk types.SavingsKeeper, ek types.EarnKeeper) keeper.Keeper {
|
||||
return keeper.NewKeeper(suite.cdc, suite.incentiveStoreKey, paramSubspace, bk, cdpk, hk, ak, stk, swk, svk, ek)
|
||||
func (suite *unitTester) NewKeeper(
|
||||
paramSubspace types.ParamSubspace,
|
||||
bk types.BankKeeper, cdpk types.CdpKeeper, hk types.HardKeeper,
|
||||
ak types.AccountKeeper, stk types.StakingKeeper, swk types.SwapKeeper,
|
||||
svk types.SavingsKeeper, lqk types.LiquidKeeper, ek types.EarnKeeper,
|
||||
) keeper.Keeper {
|
||||
return keeper.NewKeeper(suite.cdc, suite.incentiveStoreKey, paramSubspace, bk, cdpk, hk, ak, stk, swk, svk, lqk, ek)
|
||||
}
|
||||
|
||||
func (suite *unitTester) storeGlobalBorrowIndexes(indexes types.MultiRewardIndexes) {
|
||||
@ -412,6 +418,66 @@ func (k *fakeEarnKeeper) GetVaultAccountShares(
|
||||
return accShares, found
|
||||
}
|
||||
|
||||
func (k *fakeEarnKeeper) IterateVaultRecords(
|
||||
ctx sdk.Context,
|
||||
cb func(record earntypes.VaultRecord) (stop bool),
|
||||
) {
|
||||
for _, vaultShares := range k.vaultShares {
|
||||
cb(earntypes.VaultRecord{
|
||||
TotalShares: vaultShares,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// fakeLiquidKeeper is a stub liquid keeper.
|
||||
// It can be used to return values to the incentive keeper without having to initialize a full liquid keeper.
|
||||
type fakeLiquidKeeper struct {
|
||||
derivatives map[string]sdk.Int
|
||||
}
|
||||
|
||||
var _ types.LiquidKeeper = newFakeLiquidKeeper()
|
||||
|
||||
func newFakeLiquidKeeper() *fakeLiquidKeeper {
|
||||
return &fakeLiquidKeeper{
|
||||
derivatives: map[string]sdk.Int{},
|
||||
}
|
||||
}
|
||||
|
||||
func (k *fakeLiquidKeeper) addDerivative(denom string, supply sdk.Int) *fakeLiquidKeeper {
|
||||
k.derivatives[denom] = supply
|
||||
return k
|
||||
}
|
||||
|
||||
func (k *fakeLiquidKeeper) IsDerivativeDenom(ctx sdk.Context, denom string) bool {
|
||||
return strings.HasPrefix(denom, "bkava-")
|
||||
}
|
||||
|
||||
func (k *fakeLiquidKeeper) GetAllDerivativeDenoms(ctx sdk.Context) (denoms []string) {
|
||||
for denom := range k.derivatives {
|
||||
denoms = append(denoms, denom)
|
||||
}
|
||||
|
||||
return denoms
|
||||
}
|
||||
|
||||
func (k *fakeLiquidKeeper) GetTotalDerivativeSupply(ctx sdk.Context) sdk.Int {
|
||||
totalSupply := sdk.ZeroInt()
|
||||
for _, supply := range k.derivatives {
|
||||
totalSupply = totalSupply.Add(supply)
|
||||
}
|
||||
|
||||
return totalSupply
|
||||
}
|
||||
|
||||
func (k *fakeLiquidKeeper) GetDerivativeSupply(ctx sdk.Context, denom string) sdk.Int {
|
||||
supply, found := k.derivatives[denom]
|
||||
if !found {
|
||||
return sdk.ZeroInt()
|
||||
}
|
||||
|
||||
return supply
|
||||
}
|
||||
|
||||
// Assorted Testing Data
|
||||
|
||||
// note: amino panics when encoding times ≥ the start of year 10000.
|
||||
|
@ -31,12 +31,29 @@ func NewAccumulator(previousAccrual time.Time, indexes RewardIndexes) *Accumulat
|
||||
//
|
||||
// totalSourceShares is the sum of all users' source shares. For example:total btcb supplied to hard, total usdx borrowed from all bnb CDPs, or total shares in a swap pool.
|
||||
func (acc *Accumulator) Accumulate(period MultiRewardPeriod, totalSourceShares sdk.Dec, currentTime time.Time) {
|
||||
accumulationDuration := acc.getTimeElapsedWithinLimits(acc.PreviousAccumulationTime, currentTime, period.Start, period.End)
|
||||
acc.AccumulateDecCoins(
|
||||
period.Start,
|
||||
period.End,
|
||||
sdk.NewDecCoinsFromCoins(period.RewardsPerSecond...),
|
||||
totalSourceShares,
|
||||
currentTime,
|
||||
)
|
||||
}
|
||||
|
||||
indexesIncrement := acc.calculateNewRewards(period.RewardsPerSecond, totalSourceShares, accumulationDuration)
|
||||
// AccumulateDecCoins
|
||||
func (acc *Accumulator) AccumulateDecCoins(
|
||||
periodStart time.Time,
|
||||
periodEnd time.Time,
|
||||
periodRewardsPerSecond sdk.DecCoins,
|
||||
totalSourceShares sdk.Dec,
|
||||
currentTime time.Time,
|
||||
) {
|
||||
accumulationDuration := acc.getTimeElapsedWithinLimits(acc.PreviousAccumulationTime, currentTime, periodStart, periodEnd)
|
||||
|
||||
indexesIncrement := acc.calculateNewRewards(periodRewardsPerSecond, totalSourceShares, accumulationDuration)
|
||||
|
||||
acc.Indexes = acc.Indexes.Add(indexesIncrement)
|
||||
acc.PreviousAccumulationTime = minTime(period.End, currentTime)
|
||||
acc.PreviousAccumulationTime = minTime(periodEnd, currentTime)
|
||||
}
|
||||
|
||||
// getTimeElapsedWithinLimits returns the duration between start and end times, capped by min and max times.
|
||||
@ -59,7 +76,7 @@ func (*Accumulator) getTimeElapsedWithinLimits(start, end, limitMin, limitMax ti
|
||||
// The total rewards to distribute in this block are given by reward rate * duration. This value divided by the sum of all source shares to give
|
||||
// total rewards per source share, which is what the indexes store.
|
||||
// Note, duration is rounded to the nearest second to keep rewards calculation consistent with kava-7.
|
||||
func (*Accumulator) calculateNewRewards(rewardsPerSecond sdk.Coins, totalSourceShares sdk.Dec, duration time.Duration) RewardIndexes {
|
||||
func (*Accumulator) calculateNewRewards(rewardsPerSecond sdk.DecCoins, totalSourceShares sdk.Dec, duration time.Duration) RewardIndexes {
|
||||
if totalSourceShares.LTE(sdk.ZeroDec()) {
|
||||
// When there is zero source shares, there is no users with deposits/borrows/delegations to pay out the current block's rewards to.
|
||||
// So drop the rewards and pay out nothing.
|
||||
@ -93,10 +110,10 @@ func maxTime(t1, t2 time.Time) time.Time {
|
||||
}
|
||||
|
||||
// newRewardIndexesFromCoins is a helper function to initialize a RewardIndexes slice with the values from a Coins slice.
|
||||
func newRewardIndexesFromCoins(coins sdk.Coins) RewardIndexes {
|
||||
func newRewardIndexesFromCoins(coins sdk.DecCoins) RewardIndexes {
|
||||
var indexes RewardIndexes
|
||||
for _, coin := range coins {
|
||||
indexes = append(indexes, NewRewardIndex(coin.Denom, coin.Amount.ToDec()))
|
||||
indexes = append(indexes, NewRewardIndex(coin.Denom, coin.Amount))
|
||||
}
|
||||
return indexes
|
||||
}
|
||||
|
@ -187,7 +187,11 @@ func TestAccumulator(t *testing.T) {
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
acc := &Accumulator{}
|
||||
indexes := acc.calculateNewRewards(tc.args.rewardsPerSecond, tc.args.totalSourceShares, tc.args.duration)
|
||||
indexes := acc.calculateNewRewards(
|
||||
sdk.NewDecCoinsFromCoins(tc.args.rewardsPerSecond...),
|
||||
tc.args.totalSourceShares,
|
||||
tc.args.duration,
|
||||
)
|
||||
|
||||
require.Equal(t, tc.expected, indexes)
|
||||
})
|
||||
|
@ -68,6 +68,14 @@ type SavingsKeeper interface {
|
||||
type EarnKeeper interface {
|
||||
GetVaultTotalShares(ctx sdk.Context, denom string) (shares earntypes.VaultShare, found bool)
|
||||
GetVaultAccountShares(ctx sdk.Context, acc sdk.AccAddress) (shares earntypes.VaultShares, found bool)
|
||||
IterateVaultRecords(ctx sdk.Context, cb func(record earntypes.VaultRecord) (stop bool))
|
||||
}
|
||||
|
||||
// LiquidKeeper defines the required methods needed by this modules keeper
|
||||
type LiquidKeeper interface {
|
||||
IsDerivativeDenom(ctx sdk.Context, denom string) bool
|
||||
GetTotalDerivativeSupply(ctx sdk.Context) sdk.Int
|
||||
GetDerivativeSupply(ctx sdk.Context, denom string) sdk.Int
|
||||
}
|
||||
|
||||
// AccountKeeper expected interface for the account keeper (noalias)
|
||||
|
Loading…
Reference in New Issue
Block a user