2018-09-04 23:41:17 -07:00
|
|
|
package keeper
|
|
|
|
|
|
|
|
import (
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2019-01-16 13:38:05 -08:00
|
|
|
|
2018-09-04 23:41:17 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
|
|
|
)
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// initialize starting info for a new delegation
|
|
|
|
func (k Keeper) initializeDelegation(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) {
|
|
|
|
// period has already been incremented
|
|
|
|
period := k.GetValidatorCurrentRewards(ctx, val).Period
|
|
|
|
validator := k.stakingKeeper.Validator(ctx, val)
|
|
|
|
delegation := k.stakingKeeper.Delegation(ctx, del, val)
|
|
|
|
// calculate delegation stake in tokens
|
|
|
|
// we don't store directly, so multiply delegation shares * (tokens per share)
|
|
|
|
stake := delegation.GetShares().Mul(validator.GetDelegatorShareExRate())
|
|
|
|
k.SetDelegatorStartingInfo(ctx, val, del, types.NewDelegatorStartingInfo(period-1, stake, uint64(ctx.BlockHeight())))
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculate the rewards accrued by a delegation between two periods
|
|
|
|
func (k Keeper) calculateDelegationRewardsBetween(ctx sdk.Context, val sdk.Validator,
|
|
|
|
startingPeriod, endingPeriod uint64, staking sdk.Dec) (rewards sdk.DecCoins) {
|
|
|
|
// sanity check
|
|
|
|
if startingPeriod > endingPeriod {
|
|
|
|
panic("startingPeriod cannot be greater than endingPeriod")
|
2018-09-04 23:41:17 -07:00
|
|
|
}
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// return staking * (ending - starting)
|
|
|
|
starting := k.GetValidatorHistoricalRewards(ctx, val.GetOperator(), startingPeriod)
|
|
|
|
ending := k.GetValidatorHistoricalRewards(ctx, val.GetOperator(), endingPeriod)
|
|
|
|
difference := ending.Minus(starting)
|
|
|
|
rewards = difference.MulDec(staking)
|
2018-09-04 23:41:17 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// calculate the total rewards accrued by a delegation
|
|
|
|
func (k Keeper) calculateDelegationRewards(ctx sdk.Context, val sdk.Validator, del sdk.Delegation, endingPeriod uint64) (rewards sdk.DecCoins) {
|
|
|
|
// fetch starting info for delegation
|
|
|
|
startingInfo := k.GetDelegatorStartingInfo(ctx, del.GetValidatorAddr(), del.GetDelegatorAddr())
|
|
|
|
startingPeriod := startingInfo.PreviousPeriod
|
|
|
|
stake := startingInfo.Stake
|
|
|
|
|
|
|
|
// iterate through slashes and withdraw with calculated staking for sub-intervals
|
|
|
|
// these offsets are dependent on *when* slashes happen - namely, in BeginBlock, after rewards are allocated...
|
|
|
|
// ... so we don't reduce stake for slashes which happened in the *first* block, because the delegation wouldn't have existed
|
|
|
|
startingHeight := startingInfo.Height + 1
|
|
|
|
// ... or slashes which happened in *this* block, since they would have happened after reward allocation
|
|
|
|
endingHeight := uint64(ctx.BlockHeight()) - 1
|
|
|
|
if endingHeight >= startingHeight {
|
|
|
|
k.IterateValidatorSlashEventsBetween(ctx, del.GetValidatorAddr(), startingHeight, endingHeight,
|
|
|
|
func(height uint64, event types.ValidatorSlashEvent) (stop bool) {
|
|
|
|
endingPeriod := event.ValidatorPeriod - 1
|
|
|
|
rewards = rewards.Plus(k.calculateDelegationRewardsBetween(ctx, val, startingPeriod, endingPeriod, stake))
|
|
|
|
stake = stake.Mul(sdk.OneDec().Sub(event.Fraction))
|
|
|
|
startingPeriod = endingPeriod
|
|
|
|
return false
|
|
|
|
},
|
|
|
|
)
|
2018-11-26 04:21:23 -08:00
|
|
|
}
|
2018-10-26 04:42:53 -07:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// calculate rewards for final period
|
|
|
|
rewards = rewards.Plus(k.calculateDelegationRewardsBetween(ctx, val, startingPeriod, endingPeriod, stake))
|
2018-09-10 15:37:58 -07:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
return
|
2018-10-26 04:42:53 -07:00
|
|
|
}
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val sdk.Validator, del sdk.Delegation) sdk.Error {
|
2018-10-26 04:42:53 -07:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// end current period and calculate rewards
|
|
|
|
endingPeriod := k.incrementValidatorPeriod(ctx, val)
|
|
|
|
rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod)
|
2018-10-26 04:42:53 -07:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// truncate coins, return remainder to community pool
|
|
|
|
coins, remainder := rewards.TruncateDecimal()
|
|
|
|
outstanding := k.GetOutstandingRewards(ctx)
|
|
|
|
k.SetOutstandingRewards(ctx, outstanding.Minus(rewards))
|
|
|
|
feePool := k.GetFeePool(ctx)
|
|
|
|
feePool.CommunityPool = feePool.CommunityPool.Plus(remainder)
|
2018-10-18 12:58:57 -07:00
|
|
|
k.SetFeePool(ctx, feePool)
|
2018-10-26 04:42:53 -07:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// add coins to user account
|
|
|
|
withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, del.GetDelegatorAddr())
|
|
|
|
if _, _, err := k.bankKeeper.AddCoins(ctx, withdrawAddr, coins); err != nil {
|
|
|
|
return err
|
2018-09-28 01:02:07 -07:00
|
|
|
}
|
2018-10-26 04:42:53 -07:00
|
|
|
|
|
|
|
return nil
|
2018-09-04 23:41:17 -07:00
|
|
|
}
|