/
rewards_swap.go
130 lines (105 loc) · 5.07 KB
/
rewards_swap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package keeper
import (
"fmt"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/elysium-station/black/x/incentive/types"
)
// AccumulateSwapRewards 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) AccumulateSwapRewards(ctx sdk.Context, rewardPeriod types.MultiRewardPeriod) {
previousAccrualTime, found := k.GetSwapRewardAccrualTime(ctx, rewardPeriod.CollateralType)
if !found {
previousAccrualTime = ctx.BlockTime()
}
indexes, found := k.GetSwapRewardIndexes(ctx, rewardPeriod.CollateralType)
if !found {
indexes = types.RewardIndexes{}
}
acc := types.NewAccumulator(previousAccrualTime, indexes)
totalSource := k.getSwapTotalSourceShares(ctx, rewardPeriod.CollateralType)
acc.Accumulate(rewardPeriod, totalSource, ctx.BlockTime())
k.SetSwapRewardAccrualTime(ctx, rewardPeriod.CollateralType, acc.PreviousAccumulationTime)
if len(acc.Indexes) > 0 {
// the store panics when setting empty or nil indexes
k.SetSwapRewardIndexes(ctx, rewardPeriod.CollateralType, acc.Indexes)
}
}
// getSwapTotalSourceShares fetches the sum of all source shares for a swap reward.
// In the case of swap, these are the total (swap module) shares in a particular pool.
func (k Keeper) getSwapTotalSourceShares(ctx sdk.Context, poolID string) sdk.Dec {
totalShares, found := k.swapKeeper.GetPoolShares(ctx, poolID)
if !found {
totalShares = sdk.ZeroInt()
}
return sdk.NewDecFromInt(totalShares)
}
// InitializeSwapReward creates a new claim with zero rewards and indexes matching the global indexes.
// If the claim already exists it just updates the indexes.
func (k Keeper) InitializeSwapReward(ctx sdk.Context, poolID string, owner sdk.AccAddress) {
claim, found := k.GetSwapClaim(ctx, owner)
if !found {
claim = types.NewSwapClaim(owner, sdk.Coins{}, nil)
}
globalRewardIndexes, found := k.GetSwapRewardIndexes(ctx, poolID)
if !found {
globalRewardIndexes = types.RewardIndexes{}
}
claim.RewardIndexes = claim.RewardIndexes.With(poolID, globalRewardIndexes)
k.SetSwapClaim(ctx, claim)
}
// SynchronizeSwapReward updates the claim object by adding any accumulated rewards
// and updating the reward index value.
func (k Keeper) SynchronizeSwapReward(ctx sdk.Context, poolID string, owner sdk.AccAddress, shares sdkmath.Int) {
claim, found := k.GetSwapClaim(ctx, owner)
if !found {
return
}
claim = k.synchronizeSwapReward(ctx, claim, poolID, owner, shares)
k.SetSwapClaim(ctx, claim)
}
// synchronizeSwapReward updates the reward and indexes in a swap claim for one pool.
func (k *Keeper) synchronizeSwapReward(ctx sdk.Context, claim types.SwapClaim, poolID string, owner sdk.AccAddress, shares sdkmath.Int) types.SwapClaim {
globalRewardIndexes, found := k.GetSwapRewardIndexes(ctx, poolID)
if !found {
// The global factor is only not found if
// - the pool has not started accumulating rewards yet (either there is no reward specified in params, or the reward start time hasn't been hit)
// - OR it was wrongly deleted from state (factors should never be removed while unsynced claims exist)
// If not found we could either skip this sync, or assume the global factor is zero.
// Skipping will avoid storing unnecessary factors in the claim for non rewarded pools.
// And in the event a global factor is wrongly deleted, it will avoid this function panicking when calculating rewards.
return claim
}
userRewardIndexes, found := claim.RewardIndexes.Get(poolID)
if !found {
// Normally the reward indexes should always be found.
// But if a pool was not rewarded then becomes rewarded (ie a reward period is added to params), then the indexes will be missing from claims for that pool.
// So given the reward period was just added, assume the starting value for any global reward indexes, which is an empty slice.
userRewardIndexes = types.RewardIndexes{}
}
newRewards, err := k.CalculateRewards(userRewardIndexes, globalRewardIndexes, sdk.NewDecFromInt(shares))
if err != nil {
// Global reward factors should never decrease, as it would lead to a negative update to claim.Rewards.
// This panics if a global reward factor decreases or disappears between the old and new indexes.
panic(fmt.Sprintf("corrupted global reward indexes found: %v", err))
}
claim.Reward = claim.Reward.Add(newRewards...)
claim.RewardIndexes = claim.RewardIndexes.With(poolID, globalRewardIndexes)
return claim
}
// GetSynchronizedSwapClaim fetches a swap claim from the store and syncs rewards for all rewarded pools.
func (k Keeper) GetSynchronizedSwapClaim(ctx sdk.Context, owner sdk.AccAddress) (types.SwapClaim, bool) {
claim, found := k.GetSwapClaim(ctx, owner)
if !found {
return types.SwapClaim{}, false
}
k.IterateSwapRewardIndexes(ctx, func(poolID string, _ types.RewardIndexes) bool {
shares, found := k.swapKeeper.GetDepositorSharesAmount(ctx, owner, poolID)
if !found {
shares = sdk.ZeroInt()
}
claim = k.synchronizeSwapReward(ctx, claim, poolID, owner, shares)
return false
})
return claim, true
}