2022-04-21 20:16:28 +00:00
|
|
|
package keeper
|
|
|
|
|
|
|
|
import (
|
2023-06-05 18:39:53 +00:00
|
|
|
"fmt"
|
|
|
|
|
2022-04-21 20:16:28 +00:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
|
|
|
2024-05-01 03:17:24 +00:00
|
|
|
"github.com/0glabs/0g-chain/x/evmutil/types"
|
2022-04-21 20:16:28 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// RegisterInvariants registers the swap module invariants
|
|
|
|
func RegisterInvariants(ir sdk.InvariantRegistry, bankK types.BankKeeper, k Keeper) {
|
2023-06-05 18:39:53 +00:00
|
|
|
ir.RegisterRoute(types.ModuleName, "cosmos-coins-fully-backed", CosmosCoinsFullyBackedInvariant(bankK, k))
|
2022-08-23 17:04:40 +00:00
|
|
|
// Disable this invariant due to some issues with it requiring some staking params to be set in genesis.
|
|
|
|
// ir.RegisterRoute(types.ModuleName, "backed-conversion-coins", BackedCoinsInvariant(bankK, k))
|
2022-04-21 20:16:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// AllInvariants runs all invariants of the swap module
|
|
|
|
func AllInvariants(bankK types.BankKeeper, k Keeper) sdk.Invariant {
|
|
|
|
return func(ctx sdk.Context) (string, bool) {
|
2022-08-23 17:04:40 +00:00
|
|
|
if res, stop := BackedCoinsInvariant(bankK, k)(ctx); stop {
|
|
|
|
return res, stop
|
|
|
|
}
|
2022-04-21 20:16:28 +00:00
|
|
|
|
2024-07-10 21:20:12 +00:00
|
|
|
return CosmosCoinsFullyBackedInvariant(bankK, k)(ctx)
|
2022-04-21 20:16:28 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-23 17:04:40 +00:00
|
|
|
|
|
|
|
// BackedCoinsInvariant iterates all conversion pairs and asserts that the
|
|
|
|
// sdk.Coin balances are less than the module ERC20 balance.
|
|
|
|
// **Note:** This compares <= and not == as anyone can send tokens to the
|
|
|
|
// ERC20 contract address and break the invariant if a strict equal check.
|
|
|
|
func BackedCoinsInvariant(_ types.BankKeeper, k Keeper) sdk.Invariant {
|
|
|
|
broken := false
|
|
|
|
message := sdk.FormatInvariant(
|
|
|
|
types.ModuleName,
|
|
|
|
"backed coins broken",
|
|
|
|
"coin supply is greater than module account ERC20 tokens",
|
|
|
|
)
|
|
|
|
|
|
|
|
return func(ctx sdk.Context) (string, bool) {
|
|
|
|
params := k.GetParams(ctx)
|
|
|
|
for _, pair := range params.EnabledConversionPairs {
|
|
|
|
erc20Balance, err := k.QueryERC20BalanceOf(
|
|
|
|
ctx,
|
|
|
|
pair.GetAddress(),
|
|
|
|
types.NewInternalEVMAddress(types.ModuleEVMAddress),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
supply := k.bankKeeper.GetSupply(ctx, pair.Denom)
|
|
|
|
|
|
|
|
// Must be true: sdk.Coin supply < ERC20 balanceOf(module account)
|
|
|
|
if supply.Amount.BigInt().Cmp(erc20Balance) > 0 {
|
|
|
|
broken = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return message, broken
|
|
|
|
}
|
|
|
|
}
|
2023-06-05 18:39:53 +00:00
|
|
|
|
|
|
|
// CosmosCoinsFullyBackedInvariant ensures the total supply of ERC20 representations of sdk.Coins
|
|
|
|
// match the balances in the module account.
|
|
|
|
//
|
|
|
|
// This invariant depends on the fact that coins can only become part of the balance through
|
|
|
|
// conversion to ERC20s.
|
|
|
|
// If in the future sdk.Coins can be sent directly to the module account,
|
|
|
|
// or the module account balance can be increased in any other way,
|
|
|
|
// this invariant should be changed from checking that the balance equals the total supply,
|
|
|
|
// to check that the balance is greater than or equal to the total supply.
|
|
|
|
func CosmosCoinsFullyBackedInvariant(bankK types.BankKeeper, k Keeper) sdk.Invariant {
|
|
|
|
broken := false
|
|
|
|
message := sdk.FormatInvariant(
|
|
|
|
types.ModuleName,
|
|
|
|
"cosmos coins fully-backed broken",
|
|
|
|
"ERC20 total supply is not equal to module account balance",
|
|
|
|
)
|
|
|
|
maccAddress := authtypes.NewModuleAddress(types.ModuleName)
|
|
|
|
|
|
|
|
return func(ctx sdk.Context) (string, bool) {
|
|
|
|
k.IterateAllDeployedCosmosCoinContracts(ctx, func(c types.DeployedCosmosCoinContract) bool {
|
|
|
|
moduleBalance := bankK.GetBalance(ctx, maccAddress, c.CosmosDenom).Amount
|
|
|
|
totalSupply, err := k.QueryERC20TotalSupply(ctx, *c.Address)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Sprintf("failed to query total supply for %+v", c))
|
|
|
|
}
|
|
|
|
// expect total supply to equal balance in the module
|
|
|
|
if totalSupply.Cmp(moduleBalance.BigInt()) != 0 {
|
|
|
|
broken = true
|
|
|
|
}
|
|
|
|
return broken
|
|
|
|
})
|
|
|
|
return message, broken
|
|
|
|
}
|
|
|
|
}
|