-
Notifications
You must be signed in to change notification settings - Fork 0
/
keeper.go
138 lines (117 loc) · 5.23 KB
/
keeper.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
131
132
133
134
135
136
137
138
package keeper
import (
"fmt"
"math"
"github.com/tendermint/tendermint/libs/log"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/osmosis-labs/osmosis/osmomath"
"github.com/fury-labs/furya/v20/x/valset-pref/types"
)
type Keeper struct {
storeKey sdk.StoreKey
paramSpace paramtypes.Subspace
stakingKeeper types.StakingInterface
distirbutionKeeper types.DistributionKeeper
lockupKeeper types.LockupKeeper
}
func NewKeeper(storeKey sdk.StoreKey,
paramSpace paramtypes.Subspace,
stakingKeeper types.StakingInterface,
distirbutionKeeper types.DistributionKeeper,
lockupKeeper types.LockupKeeper,
) Keeper {
return Keeper{
storeKey: storeKey,
paramSpace: paramSpace,
stakingKeeper: stakingKeeper,
distirbutionKeeper: distirbutionKeeper,
lockupKeeper: lockupKeeper,
}
}
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
}
// GetDelegationPreferences checks if valset position exists, if it does return that
// else return existing delegation that's not valset.
func (k Keeper) GetDelegationPreferences(ctx sdk.Context, delegator string) (types.ValidatorSetPreferences, error) {
valSet, exists := k.GetValidatorSetPreference(ctx, delegator)
if !exists {
delAddr, err := sdk.AccAddressFromBech32(delegator)
if err != nil {
return types.ValidatorSetPreferences{}, err
}
existingDelegations := k.stakingKeeper.GetDelegatorDelegations(ctx, delAddr, math.MaxUint16)
if len(existingDelegations) == 0 {
return types.ValidatorSetPreferences{}, types.ErrNoDelegation
}
preferences, err := k.formatToValPrefArr(ctx, existingDelegations)
if err != nil {
return types.ValidatorSetPreferences{}, err
}
return types.ValidatorSetPreferences{Preferences: preferences}, nil
}
return valSet, nil
}
// GetValSetPreferencesWithDelegations fetches the delegator's validator set preferences
// considering their existing delegations.
// -If validator set preference does not exist and there are no existing delegations, it returns an error.
// -If validator set preference exists and there are no existing delegations, it returns the existing preference.
// -If there is any existing delegation:
// calculates the delegator's shares in each delegation
// as a ratio of the total shares and returns it as part of ValidatorSetPreferences.
func (k Keeper) GetValSetPreferencesWithDelegations(ctx sdk.Context, delegator string) (types.ValidatorSetPreferences, error) {
delAddr, err := sdk.AccAddressFromBech32(delegator)
if err != nil {
return types.ValidatorSetPreferences{}, err
}
valSet, exists := k.GetValidatorSetPreference(ctx, delegator)
existingDelegations := k.stakingKeeper.GetDelegatorDelegations(ctx, delAddr, math.MaxUint16)
// No existing delegations for a delegator when valSet does not exist
if !exists && len(existingDelegations) == 0 {
return types.ValidatorSetPreferences{}, fmt.Errorf("No Existing delegation to unbond from")
}
// Returning existing valSet when there are no existing delegations
if exists && len(existingDelegations) == 0 {
return valSet, nil
}
// when existing delegation exists, have it based upon the existing delegation
// regardless of the delegator having valset pref or not
preferences, err := k.formatToValPrefArr(ctx, existingDelegations)
if err != nil {
return types.ValidatorSetPreferences{}, err
}
return types.ValidatorSetPreferences{Preferences: preferences}, nil
}
// formatToValPrefArr iterates over given delegations array, formats it into ValidatorPreference array.
// Used to calculate weights for the each delegation towards validator.
// CONTRACT: This method assumes no duplicated ValOperAddress exists in the given delegation.
func (k Keeper) formatToValPrefArr(ctx sdk.Context, delegations []stakingtypes.Delegation) ([]types.ValidatorPreference, error) {
totalTokens := osmomath.NewDec(0)
// We cache token amounts for each delegation to avoid a second set of reads
tokenDelegations := make(map[stakingtypes.Delegation]osmomath.Dec)
for _, existingDelegation := range delegations {
// Fetch validator corresponding to current delegation
validator, found := k.stakingKeeper.GetValidator(ctx, existingDelegation.GetValidatorAddr())
if !found {
return []types.ValidatorPreference{}, types.ValidatorNotFoundError{ValidatorAddr: existingDelegation.ValidatorAddress}
}
// Convert shares to underlying token amounts
currentDelegationTokens := validator.TokensFromShares(existingDelegation.Shares)
// Cache token amounts for each delegation and track total tokens
tokenDelegations[existingDelegation] = currentDelegationTokens
totalTokens = totalTokens.Add(currentDelegationTokens)
}
// Build ValidatorPreference array from delegations
valPrefs := make([]types.ValidatorPreference, len(delegations))
for i, delegation := range delegations {
valPrefs[i] = types.ValidatorPreference{
ValOperAddress: delegation.ValidatorAddress,
// We accept bankers rounding here as rounding direction is not critical
// and we want to minimize rounding error.
Weight: tokenDelegations[delegation].Quo(totalTokens),
}
}
return valPrefs, nil
}