2020-04-24 15:20:34 +00:00
package keeper
import (
2021-03-23 04:31:21 +00:00
"fmt"
2021-01-18 19:12:37 +00:00
"math"
2020-04-24 15:20:34 +00:00
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
2020-04-30 14:13:31 +00:00
2020-04-24 15:20:34 +00:00
cdptypes "github.com/kava-labs/kava/x/cdp/types"
2021-01-21 13:52:09 +00:00
hardtypes "github.com/kava-labs/kava/x/hard/types"
2020-04-24 15:20:34 +00:00
"github.com/kava-labs/kava/x/incentive/types"
)
2021-01-21 13:52:09 +00:00
// AccumulateUSDXMintingRewards updates the rewards accumulated for the input reward period
func ( k Keeper ) AccumulateUSDXMintingRewards ( ctx sdk . Context , rewardPeriod types . RewardPeriod ) error {
previousAccrualTime , found := k . GetPreviousUSDXMintingAccrualTime ( ctx , rewardPeriod . CollateralType )
2021-01-18 19:12:37 +00:00
if ! found {
2021-01-21 13:52:09 +00:00
k . SetPreviousUSDXMintingAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
2021-01-18 19:12:37 +00:00
return nil
}
2021-02-02 16:17:46 +00:00
timeElapsed := CalculateTimeElapsed ( rewardPeriod . Start , rewardPeriod . End , ctx . BlockTime ( ) , previousAccrualTime )
2021-01-18 19:12:37 +00:00
if timeElapsed . IsZero ( ) {
return nil
}
if rewardPeriod . RewardsPerSecond . Amount . IsZero ( ) {
2021-01-21 13:52:09 +00:00
k . SetPreviousUSDXMintingAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
2021-01-18 19:12:37 +00:00
return nil
}
totalPrincipal := k . cdpKeeper . GetTotalPrincipal ( ctx , rewardPeriod . CollateralType , types . PrincipalDenom ) . ToDec ( )
if totalPrincipal . IsZero ( ) {
2021-01-21 13:52:09 +00:00
k . SetPreviousUSDXMintingAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
2021-01-18 19:12:37 +00:00
return nil
}
newRewards := timeElapsed . Mul ( rewardPeriod . RewardsPerSecond . Amount )
cdpFactor , found := k . cdpKeeper . GetInterestFactor ( ctx , rewardPeriod . CollateralType )
if ! found {
2021-01-21 13:52:09 +00:00
k . SetPreviousUSDXMintingAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
2021-01-18 19:12:37 +00:00
return nil
}
rewardFactor := newRewards . ToDec ( ) . Mul ( cdpFactor ) . Quo ( totalPrincipal )
2020-05-07 17:46:40 +00:00
2021-01-21 13:52:09 +00:00
previousRewardFactor , found := k . GetUSDXMintingRewardFactor ( ctx , rewardPeriod . CollateralType )
2021-01-18 19:12:37 +00:00
if ! found {
previousRewardFactor = sdk . ZeroDec ( )
}
newRewardFactor := previousRewardFactor . Add ( rewardFactor )
2021-01-21 13:52:09 +00:00
k . SetUSDXMintingRewardFactor ( ctx , rewardPeriod . CollateralType , newRewardFactor )
k . SetPreviousUSDXMintingAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
return nil
}
// AccumulateHardBorrowRewards updates the rewards accumulated for the input reward period
2021-02-02 16:17:46 +00:00
func ( k Keeper ) AccumulateHardBorrowRewards ( ctx sdk . Context , rewardPeriod types . MultiRewardPeriod ) error {
2021-01-21 13:52:09 +00:00
previousAccrualTime , found := k . GetPreviousHardBorrowRewardAccrualTime ( ctx , rewardPeriod . CollateralType )
if ! found {
k . SetPreviousHardBorrowRewardAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
return nil
}
2021-02-02 16:17:46 +00:00
timeElapsed := CalculateTimeElapsed ( rewardPeriod . Start , rewardPeriod . End , ctx . BlockTime ( ) , previousAccrualTime )
2021-01-21 13:52:09 +00:00
if timeElapsed . IsZero ( ) {
return nil
}
2021-02-02 16:17:46 +00:00
if rewardPeriod . RewardsPerSecond . IsZero ( ) {
2021-01-21 13:52:09 +00:00
k . SetPreviousHardBorrowRewardAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
return nil
}
2021-02-02 16:17:46 +00:00
2021-01-21 13:52:09 +00:00
totalBorrowedCoins , foundTotalBorrowedCoins := k . hardKeeper . GetBorrowedCoins ( ctx )
2021-02-02 16:17:46 +00:00
if ! foundTotalBorrowedCoins {
k . SetPreviousHardBorrowRewardAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
return nil
}
totalBorrowed := totalBorrowedCoins . AmountOf ( rewardPeriod . CollateralType ) . ToDec ( )
if totalBorrowed . IsZero ( ) {
k . SetPreviousHardBorrowRewardAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
return nil
}
previousRewardIndexes , found := k . GetHardBorrowRewardIndexes ( ctx , rewardPeriod . CollateralType )
if ! found {
for _ , rewardCoin := range rewardPeriod . RewardsPerSecond {
rewardIndex := types . NewRewardIndex ( rewardCoin . Denom , sdk . ZeroDec ( ) )
previousRewardIndexes = append ( previousRewardIndexes , rewardIndex )
2021-01-21 13:52:09 +00:00
}
2021-02-02 16:17:46 +00:00
k . SetHardBorrowRewardIndexes ( ctx , rewardPeriod . CollateralType , previousRewardIndexes )
}
hardFactor , found := k . hardKeeper . GetBorrowInterestFactor ( ctx , rewardPeriod . CollateralType )
if ! found {
k . SetPreviousHardBorrowRewardAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
return nil
}
newRewardIndexes := previousRewardIndexes
for _ , rewardCoin := range rewardPeriod . RewardsPerSecond {
newRewards := rewardCoin . Amount . ToDec ( ) . Mul ( timeElapsed . ToDec ( ) )
previousRewardIndex , found := previousRewardIndexes . GetRewardIndex ( rewardCoin . Denom )
2021-01-21 13:52:09 +00:00
if ! found {
2021-02-02 16:17:46 +00:00
previousRewardIndex = types . NewRewardIndex ( rewardCoin . Denom , sdk . ZeroDec ( ) )
2021-01-21 13:52:09 +00:00
}
2021-02-02 16:17:46 +00:00
// Calculate new reward factor and update reward index
rewardFactor := newRewards . Mul ( hardFactor ) . Quo ( totalBorrowed )
newRewardFactorValue := previousRewardIndex . RewardFactor . Add ( rewardFactor )
newRewardIndex := types . NewRewardIndex ( rewardCoin . Denom , newRewardFactorValue )
i , found := newRewardIndexes . GetFactorIndex ( rewardCoin . Denom )
if found {
newRewardIndexes [ i ] = newRewardIndex
} else {
newRewardIndexes = append ( newRewardIndexes , newRewardIndex )
2021-01-21 13:52:09 +00:00
}
}
2021-02-02 16:17:46 +00:00
k . SetHardBorrowRewardIndexes ( ctx , rewardPeriod . CollateralType , newRewardIndexes )
2021-01-21 13:52:09 +00:00
k . SetPreviousHardBorrowRewardAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
return nil
}
// AccumulateHardSupplyRewards updates the rewards accumulated for the input reward period
2021-02-02 16:17:46 +00:00
func ( k Keeper ) AccumulateHardSupplyRewards ( ctx sdk . Context , rewardPeriod types . MultiRewardPeriod ) error {
2021-01-21 13:52:09 +00:00
previousAccrualTime , found := k . GetPreviousHardSupplyRewardAccrualTime ( ctx , rewardPeriod . CollateralType )
if ! found {
k . SetPreviousHardSupplyRewardAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
return nil
}
2021-02-02 16:17:46 +00:00
timeElapsed := CalculateTimeElapsed ( rewardPeriod . Start , rewardPeriod . End , ctx . BlockTime ( ) , previousAccrualTime )
2021-01-21 13:52:09 +00:00
if timeElapsed . IsZero ( ) {
return nil
}
2021-02-02 16:17:46 +00:00
if rewardPeriod . RewardsPerSecond . IsZero ( ) {
2021-01-21 13:52:09 +00:00
k . SetPreviousHardSupplyRewardAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
return nil
}
totalSuppliedCoins , foundTotalSuppliedCoins := k . hardKeeper . GetSuppliedCoins ( ctx )
2021-02-02 16:17:46 +00:00
if ! foundTotalSuppliedCoins {
k . SetPreviousHardSupplyRewardAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
return nil
}
totalSupplied := totalSuppliedCoins . AmountOf ( rewardPeriod . CollateralType ) . ToDec ( )
if totalSupplied . IsZero ( ) {
k . SetPreviousHardSupplyRewardAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
return nil
}
previousRewardIndexes , found := k . GetHardSupplyRewardIndexes ( ctx , rewardPeriod . CollateralType )
if ! found {
for _ , rewardCoin := range rewardPeriod . RewardsPerSecond {
rewardIndex := types . NewRewardIndex ( rewardCoin . Denom , sdk . ZeroDec ( ) )
previousRewardIndexes = append ( previousRewardIndexes , rewardIndex )
2021-01-21 13:52:09 +00:00
}
2021-02-02 16:17:46 +00:00
k . SetHardSupplyRewardIndexes ( ctx , rewardPeriod . CollateralType , previousRewardIndexes )
}
hardFactor , found := k . hardKeeper . GetSupplyInterestFactor ( ctx , rewardPeriod . CollateralType )
if ! found {
k . SetPreviousHardSupplyRewardAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
return nil
}
newRewardIndexes := previousRewardIndexes
for _ , rewardCoin := range rewardPeriod . RewardsPerSecond {
newRewards := rewardCoin . Amount . ToDec ( ) . Mul ( timeElapsed . ToDec ( ) )
previousRewardIndex , found := previousRewardIndexes . GetRewardIndex ( rewardCoin . Denom )
2021-01-21 13:52:09 +00:00
if ! found {
2021-02-02 16:17:46 +00:00
previousRewardIndex = types . NewRewardIndex ( rewardCoin . Denom , sdk . ZeroDec ( ) )
2021-01-21 13:52:09 +00:00
}
2021-02-02 16:17:46 +00:00
// Calculate new reward factor and update reward index
rewardFactor := newRewards . Mul ( hardFactor ) . Quo ( totalSupplied )
newRewardFactorValue := previousRewardIndex . RewardFactor . Add ( rewardFactor )
newRewardIndex := types . NewRewardIndex ( rewardCoin . Denom , newRewardFactorValue )
i , found := newRewardIndexes . GetFactorIndex ( rewardCoin . Denom )
if found {
newRewardIndexes [ i ] = newRewardIndex
} else {
newRewardIndexes = append ( newRewardIndexes , newRewardIndex )
2021-01-21 13:52:09 +00:00
}
}
2021-02-02 16:17:46 +00:00
k . SetHardSupplyRewardIndexes ( ctx , rewardPeriod . CollateralType , newRewardIndexes )
2021-01-21 13:52:09 +00:00
k . SetPreviousHardSupplyRewardAccrualTime ( ctx , rewardPeriod . CollateralType , ctx . BlockTime ( ) )
2021-01-18 19:12:37 +00:00
return nil
2020-04-24 15:20:34 +00:00
}
2021-01-21 13:52:09 +00:00
// InitializeUSDXMintingClaim creates or updates a claim such that no new rewards are accrued, but any existing rewards are not lost.
2021-01-18 19:12:37 +00:00
// this function should be called after a cdp is created. If a user previously had a cdp, then closed it, they shouldn't
// accrue rewards during the period the cdp was closed. By setting the reward factor to the current global reward factor,
// any unclaimed rewards are preserved, but no new rewards are added.
2021-01-21 13:52:09 +00:00
func ( k Keeper ) InitializeUSDXMintingClaim ( ctx sdk . Context , cdp cdptypes . CDP ) {
_ , found := k . GetUSDXMintingRewardPeriod ( ctx , cdp . Type )
2021-01-18 19:12:37 +00:00
if ! found {
// this collateral type is not incentivized, do nothing
return
2020-04-24 15:20:34 +00:00
}
2021-01-21 13:52:09 +00:00
rewardFactor , found := k . GetUSDXMintingRewardFactor ( ctx , cdp . Type )
2021-01-18 19:12:37 +00:00
if ! found {
rewardFactor = sdk . ZeroDec ( )
}
2021-01-21 13:52:09 +00:00
claim , found := k . GetUSDXMintingClaim ( ctx , cdp . Owner )
2021-01-18 19:12:37 +00:00
if ! found { // this is the owner's first usdx minting reward claim
claim = types . NewUSDXMintingClaim ( cdp . Owner , sdk . NewCoin ( types . USDXMintingRewardDenom , sdk . ZeroInt ( ) ) , types . RewardIndexes { types . NewRewardIndex ( cdp . Type , rewardFactor ) } )
2021-01-21 13:52:09 +00:00
k . SetUSDXMintingClaim ( ctx , claim )
2021-01-18 19:12:37 +00:00
return
}
// the owner has an existing usdx minting reward claim
index , hasRewardIndex := claim . HasRewardIndex ( cdp . Type )
if ! hasRewardIndex { // this is the owner's first usdx minting reward for this collateral type
claim . RewardIndexes = append ( claim . RewardIndexes , types . NewRewardIndex ( cdp . Type , rewardFactor ) )
} else { // the owner has a previous usdx minting reward for this collateral type
claim . RewardIndexes [ index ] = types . NewRewardIndex ( cdp . Type , rewardFactor )
}
2021-01-21 13:52:09 +00:00
k . SetUSDXMintingClaim ( ctx , claim )
2020-04-24 15:20:34 +00:00
}
2021-01-21 13:52:09 +00:00
// SynchronizeUSDXMintingReward updates the claim object by adding any accumulated rewards and updating the reward index value.
2021-01-18 19:12:37 +00:00
// this should be called before a cdp is modified, immediately after the 'SynchronizeInterest' method is called in the cdp module
2021-01-21 13:52:09 +00:00
func ( k Keeper ) SynchronizeUSDXMintingReward ( ctx sdk . Context , cdp cdptypes . CDP ) {
_ , found := k . GetUSDXMintingRewardPeriod ( ctx , cdp . Type )
2020-04-24 15:20:34 +00:00
if ! found {
2021-01-18 19:12:37 +00:00
// this collateral type is not incentivized, do nothing
2020-04-24 15:20:34 +00:00
return
}
2020-06-17 09:09:44 +00:00
2021-01-21 13:52:09 +00:00
globalRewardFactor , found := k . GetUSDXMintingRewardFactor ( ctx , cdp . Type )
2021-01-18 19:12:37 +00:00
if ! found {
globalRewardFactor = sdk . ZeroDec ( )
}
2021-01-21 13:52:09 +00:00
claim , found := k . GetUSDXMintingClaim ( ctx , cdp . Owner )
2021-01-18 19:12:37 +00:00
if ! found {
claim = types . NewUSDXMintingClaim ( cdp . Owner , sdk . NewCoin ( types . USDXMintingRewardDenom , sdk . ZeroInt ( ) ) , types . RewardIndexes { types . NewRewardIndex ( cdp . Type , globalRewardFactor ) } )
2021-01-21 13:52:09 +00:00
k . SetUSDXMintingClaim ( ctx , claim )
2021-01-18 19:12:37 +00:00
return
}
2020-06-17 09:09:44 +00:00
2021-01-18 19:12:37 +00:00
// the owner has an existing usdx minting reward claim
index , hasRewardIndex := claim . HasRewardIndex ( cdp . Type )
if ! hasRewardIndex { // this is the owner's first usdx minting reward for this collateral type
claim . RewardIndexes = append ( claim . RewardIndexes , types . NewRewardIndex ( cdp . Type , globalRewardFactor ) )
2021-01-21 13:52:09 +00:00
k . SetUSDXMintingClaim ( ctx , claim )
2021-01-18 19:12:37 +00:00
return
}
userRewardFactor := claim . RewardIndexes [ index ] . RewardFactor
rewardsAccumulatedFactor := globalRewardFactor . Sub ( userRewardFactor )
if rewardsAccumulatedFactor . IsZero ( ) {
return
}
claim . RewardIndexes [ index ] . RewardFactor = globalRewardFactor
2021-01-21 13:52:09 +00:00
newRewardsAmount := rewardsAccumulatedFactor . Mul ( cdp . GetTotalPrincipal ( ) . Amount . ToDec ( ) ) . RoundInt ( )
2021-01-18 19:12:37 +00:00
if newRewardsAmount . IsZero ( ) {
2021-01-21 13:52:09 +00:00
k . SetUSDXMintingClaim ( ctx , claim )
2021-01-18 19:12:37 +00:00
return
}
newRewardsCoin := sdk . NewCoin ( types . USDXMintingRewardDenom , newRewardsAmount )
claim . Reward = claim . Reward . Add ( newRewardsCoin )
2021-01-21 13:52:09 +00:00
k . SetUSDXMintingClaim ( ctx , claim )
2021-01-18 19:12:37 +00:00
}
2020-06-17 09:09:44 +00:00
2021-01-21 13:52:09 +00:00
// InitializeHardSupplyReward initializes the supply-side of a hard liquidity provider claim
// by creating the claim and setting the supply reward factor index
func ( k Keeper ) InitializeHardSupplyReward ( ctx sdk . Context , deposit hardtypes . Deposit ) {
2021-02-02 16:17:46 +00:00
var supplyRewardIndexes types . MultiRewardIndexes
2021-01-21 13:52:09 +00:00
for _ , coin := range deposit . Amount {
2021-02-02 16:17:46 +00:00
globalRewardIndexes , foundGlobalRewardIndexes := k . GetHardSupplyRewardIndexes ( ctx , coin . Denom )
2021-02-19 20:02:51 +00:00
var multiRewardIndex types . MultiRewardIndex
if foundGlobalRewardIndexes {
multiRewardIndex = types . NewMultiRewardIndex ( coin . Denom , globalRewardIndexes )
} else {
multiRewardIndex = types . NewMultiRewardIndex ( coin . Denom , types . RewardIndexes { } )
2021-01-21 13:52:09 +00:00
}
2021-02-02 16:17:46 +00:00
supplyRewardIndexes = append ( supplyRewardIndexes , multiRewardIndex )
2021-01-21 13:52:09 +00:00
}
claim , found := k . GetHardLiquidityProviderClaim ( ctx , deposit . Depositor )
2021-03-25 06:10:13 +00:00
if ! found {
2021-01-21 13:52:09 +00:00
// Instantiate claim object
2021-02-02 16:17:46 +00:00
claim = types . NewHardLiquidityProviderClaim ( deposit . Depositor , sdk . Coins { } , nil , nil , nil )
2021-01-21 13:52:09 +00:00
}
claim . SupplyRewardIndexes = supplyRewardIndexes
k . SetHardLiquidityProviderClaim ( ctx , claim )
}
// SynchronizeHardSupplyReward updates the claim object by adding any accumulated rewards
// and updating the reward index value
func ( k Keeper ) SynchronizeHardSupplyReward ( ctx sdk . Context , deposit hardtypes . Deposit ) {
claim , found := k . GetHardLiquidityProviderClaim ( ctx , deposit . Depositor )
if ! found {
return
}
for _ , coin := range deposit . Amount {
2021-02-02 16:17:46 +00:00
globalRewardIndexes , foundGlobalRewardIndexes := k . GetHardSupplyRewardIndexes ( ctx , coin . Denom )
if ! foundGlobalRewardIndexes {
2021-01-21 13:52:09 +00:00
continue
}
2021-02-19 20:02:51 +00:00
userMultiRewardIndex , foundUserMultiRewardIndex := claim . SupplyRewardIndexes . GetRewardIndex ( coin . Denom )
if ! foundUserMultiRewardIndex {
2021-01-21 13:52:09 +00:00
continue
}
2021-02-03 22:23:53 +00:00
userRewardIndexIndex , foundUserRewardIndexIndex := claim . SupplyRewardIndexes . GetRewardIndexIndex ( coin . Denom )
if ! foundUserRewardIndexIndex {
continue
}
2021-02-02 16:17:46 +00:00
for _ , globalRewardIndex := range globalRewardIndexes {
2021-02-19 20:02:51 +00:00
userRewardIndex , foundUserRewardIndex := userMultiRewardIndex . RewardIndexes . GetRewardIndex ( globalRewardIndex . CollateralType )
2021-02-02 16:17:46 +00:00
if ! foundUserRewardIndex {
2021-02-19 20:02:51 +00:00
// User deposited this coin type before it had rewards. When new rewards are added, legacy depositors
// should immediately begin earning rewards. Enable users to do so by updating their claim with the global
// reward index denom and start their reward factor at 0.0
userRewardIndex = types . NewRewardIndex ( globalRewardIndex . CollateralType , sdk . ZeroDec ( ) )
userMultiRewardIndex . RewardIndexes = append ( userMultiRewardIndex . RewardIndexes , userRewardIndex )
claim . SupplyRewardIndexes [ userRewardIndexIndex ] = userMultiRewardIndex
2021-02-02 16:17:46 +00:00
}
2021-01-21 13:52:09 +00:00
2021-02-02 16:17:46 +00:00
globalRewardFactor := globalRewardIndex . RewardFactor
userRewardFactor := userRewardIndex . RewardFactor
rewardsAccumulatedFactor := globalRewardFactor . Sub ( userRewardFactor )
2021-03-23 04:31:21 +00:00
if rewardsAccumulatedFactor . IsNegative ( ) {
panic ( fmt . Sprintf ( "reward accumulation factor cannot be negative: %s" , rewardsAccumulatedFactor ) )
2021-02-02 16:17:46 +00:00
}
2021-03-23 04:31:21 +00:00
2021-02-02 16:17:46 +00:00
newRewardsAmount := rewardsAccumulatedFactor . Mul ( deposit . Amount . AmountOf ( coin . Denom ) . ToDec ( ) ) . RoundInt ( )
2021-01-21 13:52:09 +00:00
2021-02-19 20:02:51 +00:00
factorIndex , foundFactorIndex := userMultiRewardIndex . RewardIndexes . GetFactorIndex ( globalRewardIndex . CollateralType )
2021-03-23 04:31:21 +00:00
if ! foundFactorIndex { // should never trigger, as we basically do this check at the start of this loop
2021-02-02 16:17:46 +00:00
continue
}
claim . SupplyRewardIndexes [ userRewardIndexIndex ] . RewardIndexes [ factorIndex ] . RewardFactor = globalRewardIndex . RewardFactor
2021-03-23 04:31:21 +00:00
2021-02-02 16:17:46 +00:00
newRewardsCoin := sdk . NewCoin ( userRewardIndex . CollateralType , newRewardsAmount )
claim . Reward = claim . Reward . Add ( newRewardsCoin )
}
2021-01-21 13:52:09 +00:00
}
k . SetHardLiquidityProviderClaim ( ctx , claim )
}
// InitializeHardBorrowReward initializes the borrow-side of a hard liquidity provider claim
// by creating the claim and setting the borrow reward factor index
func ( k Keeper ) InitializeHardBorrowReward ( ctx sdk . Context , borrow hardtypes . Borrow ) {
claim , found := k . GetHardLiquidityProviderClaim ( ctx , borrow . Borrower )
if ! found {
2021-02-02 16:17:46 +00:00
claim = types . NewHardLiquidityProviderClaim ( borrow . Borrower , sdk . Coins { } , nil , nil , nil )
2021-01-21 13:52:09 +00:00
}
2021-02-02 16:17:46 +00:00
var borrowRewardIndexes types . MultiRewardIndexes
2021-01-21 13:52:09 +00:00
for _ , coin := range borrow . Amount {
2021-02-02 16:17:46 +00:00
globalRewardIndexes , foundGlobalRewardIndexes := k . GetHardBorrowRewardIndexes ( ctx , coin . Denom )
2021-02-19 20:02:51 +00:00
var multiRewardIndex types . MultiRewardIndex
if foundGlobalRewardIndexes {
multiRewardIndex = types . NewMultiRewardIndex ( coin . Denom , globalRewardIndexes )
} else {
multiRewardIndex = types . NewMultiRewardIndex ( coin . Denom , types . RewardIndexes { } )
2021-01-21 13:52:09 +00:00
}
2021-02-02 16:17:46 +00:00
borrowRewardIndexes = append ( borrowRewardIndexes , multiRewardIndex )
2021-01-21 13:52:09 +00:00
}
claim . BorrowRewardIndexes = borrowRewardIndexes
k . SetHardLiquidityProviderClaim ( ctx , claim )
}
// SynchronizeHardBorrowReward updates the claim object by adding any accumulated rewards
// and updating the reward index value
func ( k Keeper ) SynchronizeHardBorrowReward ( ctx sdk . Context , borrow hardtypes . Borrow ) {
claim , found := k . GetHardLiquidityProviderClaim ( ctx , borrow . Borrower )
if ! found {
return
}
for _ , coin := range borrow . Amount {
2021-02-02 16:17:46 +00:00
globalRewardIndexes , foundGlobalRewardIndexes := k . GetHardBorrowRewardIndexes ( ctx , coin . Denom )
if ! foundGlobalRewardIndexes {
2021-01-21 13:52:09 +00:00
continue
}
2021-02-19 20:02:51 +00:00
userMultiRewardIndex , foundUserMultiRewardIndex := claim . BorrowRewardIndexes . GetRewardIndex ( coin . Denom )
if ! foundUserMultiRewardIndex {
2021-01-21 13:52:09 +00:00
continue
}
2021-02-03 22:23:53 +00:00
userRewardIndexIndex , foundUserRewardIndexIndex := claim . BorrowRewardIndexes . GetRewardIndexIndex ( coin . Denom )
if ! foundUserRewardIndexIndex {
continue
}
2021-02-02 16:17:46 +00:00
for _ , globalRewardIndex := range globalRewardIndexes {
2021-02-19 20:02:51 +00:00
userRewardIndex , foundUserRewardIndex := userMultiRewardIndex . RewardIndexes . GetRewardIndex ( globalRewardIndex . CollateralType )
2021-02-02 16:17:46 +00:00
if ! foundUserRewardIndex {
2021-02-19 20:02:51 +00:00
// User borrowed this coin type before it had rewards. When new rewards are added, legacy borrowers
// should immediately begin earning rewards. Enable users to do so by updating their claim with the global
// reward index denom and start their reward factor at 0.0
userRewardIndex = types . NewRewardIndex ( globalRewardIndex . CollateralType , sdk . ZeroDec ( ) )
userMultiRewardIndex . RewardIndexes = append ( userMultiRewardIndex . RewardIndexes , userRewardIndex )
claim . BorrowRewardIndexes [ userRewardIndexIndex ] = userMultiRewardIndex
2021-02-02 16:17:46 +00:00
}
2021-01-21 13:52:09 +00:00
2021-02-02 16:17:46 +00:00
globalRewardFactor := globalRewardIndex . RewardFactor
userRewardFactor := userRewardIndex . RewardFactor
rewardsAccumulatedFactor := globalRewardFactor . Sub ( userRewardFactor )
2021-03-23 04:31:21 +00:00
if rewardsAccumulatedFactor . IsNegative ( ) {
panic ( fmt . Sprintf ( "reward accumulation factor cannot be negative: %s" , rewardsAccumulatedFactor ) )
2021-02-02 16:17:46 +00:00
}
2021-03-23 04:31:21 +00:00
2021-02-02 16:17:46 +00:00
newRewardsAmount := rewardsAccumulatedFactor . Mul ( borrow . Amount . AmountOf ( coin . Denom ) . ToDec ( ) ) . RoundInt ( )
2021-01-21 13:52:09 +00:00
2021-02-19 20:02:51 +00:00
factorIndex , foundFactorIndex := userMultiRewardIndex . RewardIndexes . GetFactorIndex ( globalRewardIndex . CollateralType )
2021-03-23 04:31:21 +00:00
if ! foundFactorIndex { // should never trigger
2021-02-02 16:17:46 +00:00
continue
}
claim . BorrowRewardIndexes [ userRewardIndexIndex ] . RewardIndexes [ factorIndex ] . RewardFactor = globalRewardIndex . RewardFactor
newRewardsCoin := sdk . NewCoin ( userRewardIndex . CollateralType , newRewardsAmount )
claim . Reward = claim . Reward . Add ( newRewardsCoin )
}
2021-01-21 13:52:09 +00:00
}
k . SetHardLiquidityProviderClaim ( ctx , claim )
}
// UpdateHardSupplyIndexDenoms adds any new deposit denoms to the claim's supply reward index
func ( k Keeper ) UpdateHardSupplyIndexDenoms ( ctx sdk . Context , deposit hardtypes . Deposit ) {
claim , found := k . GetHardLiquidityProviderClaim ( ctx , deposit . Depositor )
if ! found {
2021-02-02 16:17:46 +00:00
claim = types . NewHardLiquidityProviderClaim ( deposit . Depositor , sdk . Coins { } , nil , nil , nil )
2021-01-21 13:52:09 +00:00
}
2021-03-23 23:28:03 +00:00
depositDenoms := getDenoms ( deposit . Amount )
supplyRewardIndexDenoms := claim . SupplyRewardIndexes . GetCollateralTypes ( )
uniqueDepositDenoms := setDifference ( depositDenoms , supplyRewardIndexDenoms )
uniqueSupplyRewardDenoms := setDifference ( supplyRewardIndexDenoms , depositDenoms )
2021-01-21 13:52:09 +00:00
supplyRewardIndexes := claim . SupplyRewardIndexes
2021-03-23 23:28:03 +00:00
// Create a new multi-reward index in the claim for every new deposit denom
for _ , denom := range uniqueDepositDenoms {
_ , foundUserRewardIndexes := claim . SupplyRewardIndexes . GetRewardIndex ( denom )
2021-02-02 16:17:46 +00:00
if ! foundUserRewardIndexes {
2021-03-23 23:28:03 +00:00
globalSupplyRewardIndexes , foundGlobalSupplyRewardIndexes := k . GetHardSupplyRewardIndexes ( ctx , denom )
2021-02-19 20:02:51 +00:00
var multiRewardIndex types . MultiRewardIndex
if foundGlobalSupplyRewardIndexes {
2021-03-23 23:28:03 +00:00
multiRewardIndex = types . NewMultiRewardIndex ( denom , globalSupplyRewardIndexes )
2021-02-19 20:02:51 +00:00
} else {
2021-03-23 23:28:03 +00:00
multiRewardIndex = types . NewMultiRewardIndex ( denom , types . RewardIndexes { } )
2021-01-21 13:52:09 +00:00
}
2021-02-02 16:17:46 +00:00
supplyRewardIndexes = append ( supplyRewardIndexes , multiRewardIndex )
2021-01-21 13:52:09 +00:00
}
}
2021-03-23 23:28:03 +00:00
// Delete multi-reward index from claim if the collateral type is no longer deposited
for _ , denom := range uniqueSupplyRewardDenoms {
supplyRewardIndexes = supplyRewardIndexes . RemoveRewardIndex ( denom )
2021-01-21 13:52:09 +00:00
}
2021-03-23 23:28:03 +00:00
2021-01-21 13:52:09 +00:00
claim . SupplyRewardIndexes = supplyRewardIndexes
k . SetHardLiquidityProviderClaim ( ctx , claim )
}
2021-03-23 23:28:03 +00:00
// UpdateHardBorrowIndexDenoms adds any new borrow denoms to the claim's borrow reward index
2021-01-21 13:52:09 +00:00
func ( k Keeper ) UpdateHardBorrowIndexDenoms ( ctx sdk . Context , borrow hardtypes . Borrow ) {
claim , found := k . GetHardLiquidityProviderClaim ( ctx , borrow . Borrower )
if ! found {
2021-02-02 16:17:46 +00:00
claim = types . NewHardLiquidityProviderClaim ( borrow . Borrower , sdk . Coins { } , nil , nil , nil )
2021-01-21 13:52:09 +00:00
}
2021-03-23 23:28:03 +00:00
borrowDenoms := getDenoms ( borrow . Amount )
borrowRewardIndexDenoms := claim . BorrowRewardIndexes . GetCollateralTypes ( )
uniqueBorrowDenoms := setDifference ( borrowDenoms , borrowRewardIndexDenoms )
uniqueBorrowRewardDenoms := setDifference ( borrowRewardIndexDenoms , borrowDenoms )
2021-01-21 13:52:09 +00:00
borrowRewardIndexes := claim . BorrowRewardIndexes
2021-03-23 23:28:03 +00:00
// Create a new multi-reward index in the claim for every new borrow denom
for _ , denom := range uniqueBorrowDenoms {
_ , foundUserRewardIndexes := claim . BorrowRewardIndexes . GetRewardIndex ( denom )
2021-02-02 16:17:46 +00:00
if ! foundUserRewardIndexes {
2021-03-23 23:28:03 +00:00
globalBorrowRewardIndexes , foundGlobalBorrowRewardIndexes := k . GetHardBorrowRewardIndexes ( ctx , denom )
2021-02-19 20:02:51 +00:00
var multiRewardIndex types . MultiRewardIndex
if foundGlobalBorrowRewardIndexes {
2021-03-23 23:28:03 +00:00
multiRewardIndex = types . NewMultiRewardIndex ( denom , globalBorrowRewardIndexes )
2021-02-19 20:02:51 +00:00
} else {
2021-03-23 23:28:03 +00:00
multiRewardIndex = types . NewMultiRewardIndex ( denom , types . RewardIndexes { } )
2021-01-21 13:52:09 +00:00
}
2021-02-02 16:17:46 +00:00
borrowRewardIndexes = append ( borrowRewardIndexes , multiRewardIndex )
2021-01-21 13:52:09 +00:00
}
}
2021-03-23 23:28:03 +00:00
// Delete multi-reward index from claim if the collateral type is no longer borrowed
for _ , denom := range uniqueBorrowRewardDenoms {
borrowRewardIndexes = borrowRewardIndexes . RemoveRewardIndex ( denom )
2021-01-21 13:52:09 +00:00
}
2021-03-23 23:28:03 +00:00
2021-01-21 13:52:09 +00:00
claim . BorrowRewardIndexes = borrowRewardIndexes
k . SetHardLiquidityProviderClaim ( ctx , claim )
}
2021-03-25 06:10:13 +00:00
// SynchronizeHardDelegatorRewards updates the claim object by adding any accumulated rewards, and setting the reward indexes to the global values.
// valAddr and shouldIncludeValidator are used to ignore or include delegations to a particular validator when summing up the total delegation.
// Normally only delegations to Bonded validators are included in the total. This is needed as staking hooks are sometimes called on the wrong side of a validator's state update (from this module's perspective).
func ( k Keeper ) SynchronizeHardDelegatorRewards ( ctx sdk . Context , delegator sdk . AccAddress , valAddr sdk . ValAddress , shouldIncludeValidator bool ) {
2021-01-25 12:58:12 +00:00
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 )
2021-03-23 23:44:37 +00:00
if rewardsAccumulatedFactor . IsNegative ( ) {
panic ( fmt . Sprintf ( "reward accumulation factor cannot be negative: %s" , rewardsAccumulatedFactor ) )
2021-01-25 12:58:12 +00:00
}
claim . DelegatorRewardIndexes [ delegatorIndex ] . RewardFactor = delagatorFactor
totalDelegated := sdk . ZeroDec ( )
2021-03-02 01:36:40 +00:00
delegations := k . stakingKeeper . GetDelegatorDelegations ( ctx , delegator , 200 )
2021-01-25 12:58:12 +00:00
for _ , delegation := range delegations {
validator , found := k . stakingKeeper . GetValidator ( ctx , delegation . GetValidatorAddr ( ) )
if ! found {
continue
}
2021-03-25 06:10:13 +00:00
if valAddr == nil {
// Delegators don't accumulate rewards if their validator is unbonded
if validator . GetStatus ( ) != sdk . Bonded {
continue
}
} else {
if ! shouldIncludeValidator && validator . OperatorAddress . Equals ( valAddr ) {
// ignore tokens delegated to the validator
continue
}
2021-01-25 12:58:12 +00:00
}
if validator . GetTokens ( ) . IsZero ( ) {
continue
}
delegatedTokens := validator . TokensFromShares ( delegation . GetShares ( ) )
2021-03-23 23:44:37 +00:00
if delegatedTokens . IsNegative ( ) {
2021-01-25 12:58:12 +00:00
continue
}
totalDelegated = totalDelegated . Add ( delegatedTokens )
}
rewardsEarned := rewardsAccumulatedFactor . Mul ( totalDelegated ) . RoundInt ( )
// 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
}
2021-02-02 16:17:46 +00:00
timeElapsed := CalculateTimeElapsed ( rewardPeriod . Start , rewardPeriod . End , ctx . BlockTime ( ) , previousAccrualTime )
2021-01-25 12:58:12 +00:00
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
2021-02-02 16:17:46 +00:00
claim = types . NewHardLiquidityProviderClaim ( delegator , sdk . Coins { } , nil , nil , nil )
2021-03-02 01:36:40 +00:00
} else {
2021-03-25 06:10:13 +00:00
k . SynchronizeHardDelegatorRewards ( ctx , delegator , nil , false )
2021-03-02 01:36:40 +00:00
claim , _ = k . GetHardLiquidityProviderClaim ( ctx , delegator )
2021-01-25 12:58:12 +00:00
}
claim . DelegatorRewardIndexes = types . RewardIndexes { delegatorRewardIndexes }
k . SetHardLiquidityProviderClaim ( ctx , claim )
}
2021-01-26 11:52:34 +00:00
// ZeroUSDXMintingClaim zeroes out the claim object's rewards and returns the updated claim object
func ( k Keeper ) ZeroUSDXMintingClaim ( ctx sdk . Context , claim types . USDXMintingClaim ) types . USDXMintingClaim {
2021-01-18 19:12:37 +00:00
claim . Reward = sdk . NewCoin ( claim . Reward . Denom , sdk . ZeroInt ( ) )
2021-01-21 13:52:09 +00:00
k . SetUSDXMintingClaim ( ctx , claim )
2021-01-18 19:12:37 +00:00
return claim
2020-04-24 15:20:34 +00:00
}
2021-01-26 11:52:34 +00:00
// SynchronizeUSDXMintingClaim updates the claim object by adding any rewards that have accumulated.
2021-01-18 19:12:37 +00:00
// Returns the updated claim object
2021-01-26 11:52:34 +00:00
func ( k Keeper ) SynchronizeUSDXMintingClaim ( ctx sdk . Context , claim types . USDXMintingClaim ) ( types . USDXMintingClaim , error ) {
2021-01-18 19:12:37 +00:00
for _ , ri := range claim . RewardIndexes {
cdp , found := k . cdpKeeper . GetCdpByOwnerAndCollateralType ( ctx , claim . Owner , ri . CollateralType )
if ! found {
// if the cdp for this collateral type has been closed, no updates are needed
continue
}
claim = k . synchronizeRewardAndReturnClaim ( ctx , cdp )
}
return claim , nil
}
// this function assumes a claim already exists, so don't call it if that's not the case
func ( k Keeper ) synchronizeRewardAndReturnClaim ( ctx sdk . Context , cdp cdptypes . CDP ) types . USDXMintingClaim {
2021-01-21 13:52:09 +00:00
k . SynchronizeUSDXMintingReward ( ctx , cdp )
claim , _ := k . GetUSDXMintingClaim ( ctx , cdp . Owner )
2021-01-18 19:12:37 +00:00
return claim
2020-04-24 15:20:34 +00:00
}
2021-01-26 11:52:34 +00:00
// SynchronizeHardLiquidityProviderClaim adds any accumulated rewards
func ( k Keeper ) SynchronizeHardLiquidityProviderClaim ( ctx sdk . Context , owner sdk . AccAddress ) {
// Synchronize any hard liquidity supply-side rewards
deposit , foundDeposit := k . hardKeeper . GetDeposit ( ctx , owner )
if foundDeposit {
k . SynchronizeHardSupplyReward ( ctx , deposit )
}
2021-02-03 22:23:53 +00:00
// Synchronize any hard liquidity borrow-side rewards
borrow , foundBorrow := k . hardKeeper . GetBorrow ( ctx , owner )
if foundBorrow {
k . SynchronizeHardBorrowReward ( ctx , borrow )
}
2021-01-26 11:52:34 +00:00
// Synchronize any hard delegator rewards
2021-03-25 06:10:13 +00:00
k . SynchronizeHardDelegatorRewards ( ctx , owner , nil , false )
2021-01-26 11:52:34 +00:00
}
// ZeroHardLiquidityProviderClaim zeroes out the claim object's rewards and returns the updated claim object
func ( k Keeper ) ZeroHardLiquidityProviderClaim ( ctx sdk . Context , claim types . HardLiquidityProviderClaim ) types . HardLiquidityProviderClaim {
2021-03-25 04:21:26 +00:00
claim . Reward = sdk . NewCoins ( )
2021-01-26 11:52:34 +00:00
k . SetHardLiquidityProviderClaim ( ctx , claim )
return claim
}
2021-01-18 19:12:37 +00:00
// CalculateTimeElapsed calculates the number of reward-eligible seconds that have passed since the previous
// time rewards were accrued, taking into account the end time of the reward period
2021-02-02 16:17:46 +00:00
func CalculateTimeElapsed ( start , end , blockTime time . Time , previousAccrualTime time . Time ) sdk . Int {
2021-02-12 15:30:10 +00:00
if ( end . Before ( blockTime ) &&
( end . Before ( previousAccrualTime ) || end . Equal ( previousAccrualTime ) ) ) ||
2021-02-24 18:25:40 +00:00
( start . After ( blockTime ) ) ||
2021-02-12 15:30:10 +00:00
( start . Equal ( blockTime ) ) {
2021-01-18 19:12:37 +00:00
return sdk . ZeroInt ( )
2020-04-24 15:20:34 +00:00
}
2021-02-12 15:30:10 +00:00
if start . After ( previousAccrualTime ) && start . Before ( blockTime ) {
previousAccrualTime = start
}
2021-02-02 16:17:46 +00:00
if end . Before ( blockTime ) {
2021-02-28 17:33:56 +00:00
return sdk . MaxInt ( sdk . ZeroInt ( ) , sdk . NewInt ( int64 ( math . RoundToEven (
2021-02-02 16:17:46 +00:00
end . Sub ( previousAccrualTime ) . Seconds ( ) ,
2021-02-28 17:33:56 +00:00
) ) ) )
2021-01-18 19:12:37 +00:00
}
2021-02-28 17:33:56 +00:00
return sdk . MaxInt ( sdk . ZeroInt ( ) , sdk . NewInt ( int64 ( math . RoundToEven (
2021-01-18 19:12:37 +00:00
blockTime . Sub ( previousAccrualTime ) . Seconds ( ) ,
2021-02-28 17:33:56 +00:00
) ) ) )
2020-04-24 15:20:34 +00:00
}
2021-01-29 20:32:07 +00:00
// SimulateHardSynchronization calculates a user's outstanding hard rewards by simulating reward synchronization
func ( k Keeper ) SimulateHardSynchronization ( ctx sdk . Context , claim types . HardLiquidityProviderClaim ) types . HardLiquidityProviderClaim {
// 1. Simulate Hard supply-side rewards
for _ , ri := range claim . SupplyRewardIndexes {
2021-02-02 21:42:01 +00:00
globalRewardIndexes , foundGlobalRewardIndexes := k . GetHardSupplyRewardIndexes ( ctx , ri . CollateralType )
if ! foundGlobalRewardIndexes {
2021-01-29 20:32:07 +00:00
continue
}
2021-02-02 21:42:01 +00:00
userRewardIndexes , foundUserRewardIndexes := claim . SupplyRewardIndexes . GetRewardIndex ( ri . CollateralType )
if ! foundUserRewardIndexes {
2021-01-29 20:32:07 +00:00
continue
}
2021-02-03 22:23:53 +00:00
userRewardIndexIndex , foundUserRewardIndexIndex := claim . SupplyRewardIndexes . GetRewardIndexIndex ( ri . CollateralType )
if ! foundUserRewardIndexIndex {
continue
}
2021-02-02 21:42:01 +00:00
for _ , globalRewardIndex := range globalRewardIndexes {
userRewardIndex , foundUserRewardIndex := userRewardIndexes . RewardIndexes . GetRewardIndex ( globalRewardIndex . CollateralType )
if ! foundUserRewardIndex {
2021-02-19 20:02:51 +00:00
userRewardIndex = types . NewRewardIndex ( globalRewardIndex . CollateralType , sdk . ZeroDec ( ) )
userRewardIndexes . RewardIndexes = append ( userRewardIndexes . RewardIndexes , userRewardIndex )
claim . SupplyRewardIndexes [ userRewardIndexIndex ] . RewardIndexes = append ( claim . SupplyRewardIndexes [ userRewardIndexIndex ] . RewardIndexes , userRewardIndex )
2021-02-02 21:42:01 +00:00
}
2021-01-29 20:32:07 +00:00
2021-02-02 21:42:01 +00:00
globalRewardFactor := globalRewardIndex . RewardFactor
userRewardFactor := userRewardIndex . RewardFactor
rewardsAccumulatedFactor := globalRewardFactor . Sub ( userRewardFactor )
if rewardsAccumulatedFactor . IsZero ( ) {
continue
}
deposit , found := k . hardKeeper . GetDeposit ( ctx , claim . GetOwner ( ) )
if ! found {
continue
}
newRewardsAmount := rewardsAccumulatedFactor . Mul ( deposit . Amount . AmountOf ( ri . CollateralType ) . ToDec ( ) ) . RoundInt ( )
2021-01-29 20:32:07 +00:00
if newRewardsAmount . IsZero ( ) || newRewardsAmount . IsNegative ( ) {
continue
}
2021-02-02 21:42:01 +00:00
factorIndex , foundFactorIndex := userRewardIndexes . RewardIndexes . GetFactorIndex ( globalRewardIndex . CollateralType )
if ! foundFactorIndex {
continue
}
claim . SupplyRewardIndexes [ userRewardIndexIndex ] . RewardIndexes [ factorIndex ] . RewardFactor = globalRewardIndex . RewardFactor
newRewardsCoin := sdk . NewCoin ( userRewardIndex . CollateralType , newRewardsAmount )
claim . Reward = claim . Reward . Add ( newRewardsCoin )
2021-01-29 20:32:07 +00:00
}
}
// 2. Simulate Hard borrow-side rewards
for _ , ri := range claim . BorrowRewardIndexes {
2021-02-02 21:42:01 +00:00
globalRewardIndexes , foundGlobalRewardIndexes := k . GetHardBorrowRewardIndexes ( ctx , ri . CollateralType )
if ! foundGlobalRewardIndexes {
2021-01-29 20:32:07 +00:00
continue
}
2021-02-02 21:42:01 +00:00
userRewardIndexes , foundUserRewardIndexes := claim . BorrowRewardIndexes . GetRewardIndex ( ri . CollateralType )
if ! foundUserRewardIndexes {
2021-01-29 20:32:07 +00:00
continue
}
2021-02-03 22:23:53 +00:00
userRewardIndexIndex , foundUserRewardIndexIndex := claim . BorrowRewardIndexes . GetRewardIndexIndex ( ri . CollateralType )
if ! foundUserRewardIndexIndex {
continue
}
2021-02-02 21:42:01 +00:00
for _ , globalRewardIndex := range globalRewardIndexes {
userRewardIndex , foundUserRewardIndex := userRewardIndexes . RewardIndexes . GetRewardIndex ( globalRewardIndex . CollateralType )
if ! foundUserRewardIndex {
2021-02-19 20:02:51 +00:00
userRewardIndex = types . NewRewardIndex ( globalRewardIndex . CollateralType , sdk . ZeroDec ( ) )
userRewardIndexes . RewardIndexes = append ( userRewardIndexes . RewardIndexes , userRewardIndex )
claim . BorrowRewardIndexes [ userRewardIndexIndex ] . RewardIndexes = append ( claim . BorrowRewardIndexes [ userRewardIndexIndex ] . RewardIndexes , userRewardIndex )
2021-02-02 21:42:01 +00:00
}
2021-01-29 20:32:07 +00:00
2021-02-02 21:42:01 +00:00
globalRewardFactor := globalRewardIndex . RewardFactor
userRewardFactor := userRewardIndex . RewardFactor
rewardsAccumulatedFactor := globalRewardFactor . Sub ( userRewardFactor )
if rewardsAccumulatedFactor . IsZero ( ) {
continue
}
borrow , found := k . hardKeeper . GetBorrow ( ctx , claim . GetOwner ( ) )
if ! found {
continue
}
newRewardsAmount := rewardsAccumulatedFactor . Mul ( borrow . Amount . AmountOf ( ri . CollateralType ) . ToDec ( ) ) . RoundInt ( )
2021-01-29 20:32:07 +00:00
if newRewardsAmount . IsZero ( ) || newRewardsAmount . IsNegative ( ) {
continue
}
2021-02-02 21:42:01 +00:00
factorIndex , foundFactorIndex := userRewardIndexes . RewardIndexes . GetFactorIndex ( globalRewardIndex . CollateralType )
if ! foundFactorIndex {
continue
}
2021-02-03 22:23:53 +00:00
claim . BorrowRewardIndexes [ userRewardIndexIndex ] . RewardIndexes [ factorIndex ] . RewardFactor = globalRewardIndex . RewardFactor
2021-02-02 21:42:01 +00:00
newRewardsCoin := sdk . NewCoin ( userRewardIndex . CollateralType , newRewardsAmount )
claim . Reward = claim . Reward . Add ( newRewardsCoin )
2021-01-29 20:32:07 +00:00
}
}
// 3. Simulate Hard delegator rewards
delagatorFactor , found := k . GetHardDelegatorRewardFactor ( ctx , types . BondDenom )
if ! found {
return claim
}
delegatorIndex , hasDelegatorRewardIndex := claim . HasDelegatorRewardIndex ( types . BondDenom )
if ! hasDelegatorRewardIndex {
return claim
}
userRewardFactor := claim . DelegatorRewardIndexes [ delegatorIndex ] . RewardFactor
rewardsAccumulatedFactor := delagatorFactor . Sub ( userRewardFactor )
if rewardsAccumulatedFactor . IsZero ( ) {
return claim
}
claim . DelegatorRewardIndexes [ delegatorIndex ] . RewardFactor = delagatorFactor
totalDelegated := sdk . ZeroDec ( )
2021-03-02 01:36:40 +00:00
delegations := k . stakingKeeper . GetDelegatorDelegations ( ctx , claim . GetOwner ( ) , 200 )
2021-01-29 20:32:07 +00:00
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 claim
}
// Add rewards to delegator's hard claim
newRewardsCoin := sdk . NewCoin ( types . HardLiquidityRewardDenom , rewardsEarned )
claim . Reward = claim . Reward . Add ( newRewardsCoin )
return claim
}
// SimulateUSDXMintingSynchronization calculates a user's outstanding USDX minting rewards by simulating reward synchronization
func ( k Keeper ) SimulateUSDXMintingSynchronization ( ctx sdk . Context , claim types . USDXMintingClaim ) types . USDXMintingClaim {
for _ , ri := range claim . RewardIndexes {
_ , found := k . GetUSDXMintingRewardPeriod ( ctx , ri . CollateralType )
if ! found {
continue
}
globalRewardFactor , found := k . GetUSDXMintingRewardFactor ( ctx , ri . CollateralType )
if ! found {
globalRewardFactor = sdk . ZeroDec ( )
}
// the owner has an existing usdx minting reward claim
index , hasRewardIndex := claim . HasRewardIndex ( ri . CollateralType )
if ! hasRewardIndex { // this is the owner's first usdx minting reward for this collateral type
claim . RewardIndexes = append ( claim . RewardIndexes , types . NewRewardIndex ( ri . CollateralType , globalRewardFactor ) )
}
userRewardFactor := claim . RewardIndexes [ index ] . RewardFactor
rewardsAccumulatedFactor := globalRewardFactor . Sub ( userRewardFactor )
if rewardsAccumulatedFactor . IsZero ( ) {
continue
}
claim . RewardIndexes [ index ] . RewardFactor = globalRewardFactor
cdp , found := k . cdpKeeper . GetCdpByOwnerAndCollateralType ( ctx , claim . GetOwner ( ) , ri . CollateralType )
if ! found {
continue
}
newRewardsAmount := rewardsAccumulatedFactor . Mul ( cdp . GetTotalPrincipal ( ) . Amount . ToDec ( ) ) . RoundInt ( )
if newRewardsAmount . IsZero ( ) {
continue
}
newRewardsCoin := sdk . NewCoin ( types . USDXMintingRewardDenom , newRewardsAmount )
claim . Reward = claim . Reward . Add ( newRewardsCoin )
}
return claim
}
2021-03-23 23:28:03 +00:00
// Set setDifference: A - B
func setDifference ( a , b [ ] string ) ( diff [ ] string ) {
m := make ( map [ string ] bool )
for _ , item := range b {
m [ item ] = true
}
for _ , item := range a {
if _ , ok := m [ item ] ; ! ok {
diff = append ( diff , item )
}
}
return
}
func getDenoms ( coins sdk . Coins ) [ ] string {
denoms := [ ] string { }
for _ , coin := range coins {
denoms = append ( denoms , coin . Denom )
}
return denoms
}