forked from crescent-network/crescent
-
Notifications
You must be signed in to change notification settings - Fork 0
/
invariants.go
115 lines (103 loc) 路 3.96 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
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
package keeper
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/jesse-pinkman-cre/crescent/x/liquidstaking/types"
)
// RegisterInvariants registers all liquidstaking invariants.
func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
ir.RegisterRoute(types.ModuleName, "net-amount",
NetAmountInvariant(k))
ir.RegisterRoute(types.ModuleName, "total-liquid-tokens",
TotalLiquidTokensInvariant(k))
ir.RegisterRoute(types.ModuleName, "liquid-delegation",
LiquidDelegationInvariant(k))
}
// AllInvariants runs all invariants of the liquidstaking module.
func AllInvariants(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
for _, inv := range []func(Keeper) sdk.Invariant{
NetAmountInvariant,
TotalLiquidTokensInvariant,
LiquidDelegationInvariant,
} {
res, stop := inv(k)(ctx)
if stop {
return res, stop
}
}
return "", false
}
}
// NetAmountInvariant checks that the amount of btoken supply with NetAmount.
func NetAmountInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
msg := ""
broken := false
lvs := k.GetAllLiquidValidators(ctx)
if lvs.Len() == 0 {
return msg, broken
}
nas := k.GetNetAmountState(ctx)
balance := k.GetProxyAccBalance(ctx, types.LiquidStakingProxyAcc).Amount
NetAmountExceptBalance := nas.NetAmount.Sub(balance.ToDec())
liquidBondDenom := k.LiquidBondDenom(ctx)
bTokenTotalSupply := k.bankKeeper.GetSupply(ctx, liquidBondDenom)
if bTokenTotalSupply.IsPositive() && !NetAmountExceptBalance.IsPositive() {
msg = "found positive btoken supply with non-positive net amount"
broken = true
}
if !bTokenTotalSupply.IsPositive() && NetAmountExceptBalance.IsPositive() {
msg = "found positive net amount with non-positive btoken supply"
broken = true
}
return sdk.FormatInvariant(
types.ModuleName, "btoken supply with net amount invariant broken",
msg,
), broken
}
}
// TotalLiquidTokensInvariant checks equal total liquid tokens of proxy account with total liquid tokens of liquid validators.
func TotalLiquidTokensInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
lvs := k.GetAllLiquidValidators(ctx)
if lvs.Len() == 0 {
return "", false
}
_, _, totalDelegationTokensOfProxyAcc := k.CheckDelegationStates(ctx, types.LiquidStakingProxyAcc)
totalLiquidTokensOfLiquidValidators, _ := lvs.TotalLiquidTokens(ctx, k.stakingKeeper, false)
broken := !totalDelegationTokensOfProxyAcc.Equal(totalLiquidTokensOfLiquidValidators)
return sdk.FormatInvariant(
types.ModuleName, "total liquid tokens invariant broken",
fmt.Sprintf("found unmatched total delegation tokens of proxy account %s with total liquid tokens of all liquid validators %s\n",
totalDelegationTokensOfProxyAcc.String(), totalLiquidTokensOfLiquidValidators.String()),
), broken
}
}
// LiquidDelegationInvariant checks all delegation of proxy account involved liquid validators.
func LiquidDelegationInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
msg := ""
count := 0
liquidValidatorMap := k.GetAllLiquidValidators(ctx).Map()
// remove delegation condition -> Unbond(slash, undelegate, redelegate)
// remove validator condition -> Unbond(slash, undelegate, redelegate), UnbondAllMatureValidators(BlockValidatorUpdates on staking endblock)
k.stakingKeeper.IterateDelegations(
ctx, types.LiquidStakingProxyAcc,
func(_ int64, del stakingtypes.DelegationI) (stop bool) {
delAddr := del.GetValidatorAddr().String()
if _, ok := liquidValidatorMap[delAddr]; !ok {
msg += fmt.Sprintf("\t%s has delegation but not liquid validator\n", delAddr)
count++
}
return false
},
)
broken := count != 0
return sdk.FormatInvariant(
types.ModuleName, "total liquid tokens invariant broken",
fmt.Sprintf("found %d delegation of proxy account for not liquid validators\n%s", count, msg),
), broken
}
}