| 
									
										
										
										
											2024-05-10 16:30:28 +00:00
										 |  |  | package keeper | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2024-05-16 22:30:31 +00:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sdkmath "cosmossdk.io/math" | 
					
						
							| 
									
										
										
										
											2024-05-10 16:30:28 +00:00
										 |  |  | 	sdk "github.com/cosmos/cosmos-sdk/types" | 
					
						
							|  |  |  | 	"github.com/kava-labs/kava/x/precisebank/types" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RegisterInvariants registers the x/precisebank module invariants
 | 
					
						
							|  |  |  | func RegisterInvariants( | 
					
						
							|  |  |  | 	ir sdk.InvariantRegistry, | 
					
						
							|  |  |  | 	k Keeper, | 
					
						
							|  |  |  | 	bk types.BankKeeper, | 
					
						
							|  |  |  | ) { | 
					
						
							| 
									
										
										
										
											2024-05-16 22:30:31 +00:00
										 |  |  | 	ir.RegisterRoute(types.ModuleName, "balance-remainder-total", BalancedFractionalTotalInvariant(k)) | 
					
						
							|  |  |  | 	ir.RegisterRoute(types.ModuleName, "valid-fractional-balances", ValidFractionalAmountsInvariant(k)) | 
					
						
							|  |  |  | 	ir.RegisterRoute(types.ModuleName, "valid-remainder-amount", ValidRemainderAmountInvariant(k)) | 
					
						
							| 
									
										
										
										
											2024-05-10 16:30:28 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AllInvariants runs all invariants of the X/precisebank module.
 | 
					
						
							|  |  |  | func AllInvariants(k Keeper) sdk.Invariant { | 
					
						
							|  |  |  | 	return func(ctx sdk.Context) (string, bool) { | 
					
						
							| 
									
										
										
										
											2024-05-16 22:30:31 +00:00
										 |  |  | 		res, stop := BalancedFractionalTotalInvariant(k)(ctx) | 
					
						
							|  |  |  | 		if stop { | 
					
						
							|  |  |  | 			return res, stop | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		res, stop = ValidFractionalAmountsInvariant(k)(ctx) | 
					
						
							|  |  |  | 		if stop { | 
					
						
							|  |  |  | 			return res, stop | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		res, stop = ValidRemainderAmountInvariant(k)(ctx) | 
					
						
							|  |  |  | 		if stop { | 
					
						
							|  |  |  | 			return res, stop | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-10 16:30:28 +00:00
										 |  |  | 		return "", false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-05-16 22:30:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ValidFractionalAmountsInvariant checks that all individual fractional
 | 
					
						
							|  |  |  | // balances are valid.
 | 
					
						
							|  |  |  | func ValidFractionalAmountsInvariant(k Keeper) sdk.Invariant { | 
					
						
							|  |  |  | 	return func(ctx sdk.Context) (string, bool) { | 
					
						
							|  |  |  | 		var ( | 
					
						
							|  |  |  | 			msg   string | 
					
						
							|  |  |  | 			count int | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		k.IterateFractionalBalances(ctx, func(addr sdk.AccAddress, amount sdkmath.Int) bool { | 
					
						
							|  |  |  | 			if err := types.NewFractionalAmountFromInt(amount).Validate(); err != nil { | 
					
						
							|  |  |  | 				count++ | 
					
						
							|  |  |  | 				msg += fmt.Sprintf("\t%s has an invalid fractional amount of %s\n", addr, amount) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		broken := count != 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return sdk.FormatInvariant( | 
					
						
							|  |  |  | 			types.ModuleName, "valid-fractional-balances", | 
					
						
							|  |  |  | 			fmt.Sprintf("amount of invalid fractional balances found %d\n%s", count, msg), | 
					
						
							|  |  |  | 		), broken | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ValidRemainderAmountInvariant checks that the remainder amount is valid.
 | 
					
						
							|  |  |  | func ValidRemainderAmountInvariant(k Keeper) sdk.Invariant { | 
					
						
							|  |  |  | 	return func(ctx sdk.Context) (string, bool) { | 
					
						
							|  |  |  | 		var ( | 
					
						
							|  |  |  | 			msg    string | 
					
						
							|  |  |  | 			broken bool | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		remainderAmount := k.GetRemainderAmount(ctx) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if !remainderAmount.IsZero() { | 
					
						
							|  |  |  | 			// Only validate if non-zero, as zero is default value
 | 
					
						
							|  |  |  | 			if err := types.NewFractionalAmountFromInt(remainderAmount).Validate(); err != nil { | 
					
						
							|  |  |  | 				broken = true | 
					
						
							|  |  |  | 				msg = fmt.Sprintf("remainder amount is invalid: %s", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return sdk.FormatInvariant( | 
					
						
							|  |  |  | 			types.ModuleName, "valid-remainder-amount", | 
					
						
							|  |  |  | 			msg, | 
					
						
							|  |  |  | 		), broken | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // BalancedFractionalTotalInvariant checks that the sum of fractional balances
 | 
					
						
							|  |  |  | // and the remainder amount is divisible by the conversion factor without any
 | 
					
						
							|  |  |  | // leftover amount.
 | 
					
						
							|  |  |  | func BalancedFractionalTotalInvariant(k Keeper) sdk.Invariant { | 
					
						
							|  |  |  | 	return func(ctx sdk.Context) (string, bool) { | 
					
						
							|  |  |  | 		fractionalBalSum := k.GetTotalSumFractionalBalances(ctx) | 
					
						
							|  |  |  | 		remainderAmount := k.GetRemainderAmount(ctx) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		total := fractionalBalSum.Add(remainderAmount) | 
					
						
							|  |  |  | 		fractionalAmount := total.Mod(types.ConversionFactor()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		broken := false | 
					
						
							|  |  |  | 		msg := "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if !fractionalAmount.IsZero() { | 
					
						
							|  |  |  | 			broken = true | 
					
						
							|  |  |  | 			msg = fmt.Sprintf( | 
					
						
							|  |  |  | 				"(sum(FractionalBalances) + remainder) %% conversionFactor should be 0 but got %v", | 
					
						
							|  |  |  | 				fractionalAmount, | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return sdk.FormatInvariant( | 
					
						
							|  |  |  | 			types.ModuleName, "balance-remainder-total", | 
					
						
							|  |  |  | 			msg, | 
					
						
							|  |  |  | 		), broken | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |