/
invariants.go
79 lines (68 loc) · 3.35 KB
/
invariants.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
package keeper
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/osmosis-labs/osmosis/v9/x/superfluid/types"
)
const totalSuperfluidDelegationInvariantName = "total-superfluid-delegation-invariant-name"
// RegisterInvariants registers all governance invariants.
func RegisterInvariants(ir sdk.InvariantRegistry, keeper Keeper) {
ir.RegisterRoute(types.ModuleName, totalSuperfluidDelegationInvariantName, TotalSuperfluidDelegationInvariant(keeper))
}
// AllInvariants runs all invariants of the gamm module.
func AllInvariants(keeper Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
return TotalSuperfluidDelegationInvariant(keeper)(ctx)
}
}
// TotalSuperfluidDelegationInvariant checks the sum of intermediary account delegation is same as sum of individual lockup delegation.
func TotalSuperfluidDelegationInvariant(keeper Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
accs := keeper.GetAllIntermediaryAccounts(ctx)
totalSuperfluidDelegationTokens := sdk.ZeroDec()
// Compute the total amount delegated from all intermediary accounts
for _, acc := range accs {
valAddr, err := sdk.ValAddressFromBech32(acc.ValAddr)
if err != nil {
return sdk.FormatInvariant(types.ModuleName, totalSuperfluidDelegationInvariantName,
"\tinvalid validator address exists"), true
}
validator, found := keeper.sk.GetValidator(ctx, valAddr)
if !found {
return sdk.FormatInvariant(types.ModuleName, totalSuperfluidDelegationInvariantName,
"\tvalidator does not exists for specified validator address on intermediary account"), true
}
delegation, found := keeper.sk.GetDelegation(ctx, acc.GetAccAddress(), valAddr)
if found {
tokens := validator.TokensFromShares(delegation.Shares)
totalSuperfluidDelegationTokens = totalSuperfluidDelegationTokens.Add(tokens)
}
}
// Compute the total delegation amount expected
// from every lockID intermediary account connections
totalExpectedSuperfluidAmount := sdk.ZeroInt()
connections := keeper.GetAllLockIdIntermediaryAccountConnections(ctx)
for _, connection := range connections {
lockId := connection.LockId
lock, err := keeper.lk.GetLockByID(ctx, lockId)
if err != nil || lock == nil {
return sdk.FormatInvariant(types.ModuleName, totalSuperfluidDelegationInvariantName,
"\tinvalid superfluid lock id exists with no actual lockup"), true
}
if len(lock.Coins) != 1 {
return sdk.FormatInvariant(types.ModuleName, totalSuperfluidDelegationInvariantName,
"\tonly single coin lockup is eligible for superfluid staking"), true
}
amount := keeper.GetSuperfluidOSMOTokens(ctx, lock.Coins[0].Denom, lock.Coins[0].Amount)
totalExpectedSuperfluidAmount = totalExpectedSuperfluidAmount.Add(amount)
}
if !totalExpectedSuperfluidAmount.Equal(totalSuperfluidDelegationTokens.TruncateInt()) {
return sdk.FormatInvariant(types.ModuleName,
totalSuperfluidDelegationInvariantName,
fmt.Sprintf("\ttotal superfluid intermediary account delegation amount does not match total sum of lockup delegations: %s != %s\n", totalExpectedSuperfluidAmount.String(), totalSuperfluidDelegationTokens.String())),
true
}
return sdk.FormatInvariant(types.ModuleName, totalSuperfluidDelegationInvariantName,
"\ttotal superfluid intermediary account delegation amount matches total sum of lockup delegations\n"), false
}
}