mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-10-31 22:37:26 +00:00 
			
		
		
		
	Add Invariants for Swap Module (#979)
* add swap module invariants * typo * update alias file for invariants * typo in test name * fix typo - method iterates share record, not pools
This commit is contained in:
		
							parent
							
								
									56463eca14
								
							
						
					
					
						commit
						b86cfc9f14
					
				| @ -24,6 +24,7 @@ const ( | |||||||
| 	EventTypeSwapWithdraw      = types.EventTypeSwapWithdraw | 	EventTypeSwapWithdraw      = types.EventTypeSwapWithdraw | ||||||
| 	ModuleAccountName          = types.ModuleAccountName | 	ModuleAccountName          = types.ModuleAccountName | ||||||
| 	ModuleName                 = types.ModuleName | 	ModuleName                 = types.ModuleName | ||||||
|  | 	PoolIDSep                  = types.PoolIDSep | ||||||
| 	QuerierRoute               = types.QuerierRoute | 	QuerierRoute               = types.QuerierRoute | ||||||
| 	QueryGetDeposits           = types.QueryGetDeposits | 	QueryGetDeposits           = types.QueryGetDeposits | ||||||
| 	QueryGetParams             = types.QueryGetParams | 	QueryGetParams             = types.QueryGetParams | ||||||
| @ -35,8 +36,14 @@ const ( | |||||||
| 
 | 
 | ||||||
| var ( | var ( | ||||||
| 	// function aliases
 | 	// function aliases
 | ||||||
|  | 	AllInvariants                        = keeper.AllInvariants | ||||||
| 	NewKeeper                            = keeper.NewKeeper | 	NewKeeper                            = keeper.NewKeeper | ||||||
| 	NewQuerier                           = keeper.NewQuerier | 	NewQuerier                           = keeper.NewQuerier | ||||||
|  | 	PoolRecordsInvariant                 = keeper.PoolRecordsInvariant | ||||||
|  | 	PoolReservesInvariant                = keeper.PoolReservesInvariant | ||||||
|  | 	PoolSharesInvariant                  = keeper.PoolSharesInvariant | ||||||
|  | 	RegisterInvariants                   = keeper.RegisterInvariants | ||||||
|  | 	ShareRecordsInvariant                = keeper.ShareRecordsInvariant | ||||||
| 	DefaultGenesisState                  = types.DefaultGenesisState | 	DefaultGenesisState                  = types.DefaultGenesisState | ||||||
| 	DefaultParams                        = types.DefaultParams | 	DefaultParams                        = types.DefaultParams | ||||||
| 	DepositorPoolSharesKey               = types.DepositorPoolSharesKey | 	DepositorPoolSharesKey               = types.DepositorPoolSharesKey | ||||||
|  | |||||||
| @ -1,19 +0,0 @@ | |||||||
| package keeper_test |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"testing" |  | ||||||
| 
 |  | ||||||
| 	//"github.com/kava-labs/kava/x/swap"
 |  | ||||||
| 	"github.com/kava-labs/kava/x/swap/testutil" |  | ||||||
| 	//"github.com/kava-labs/kava/x/swap/types"
 |  | ||||||
| 	"github.com/stretchr/testify/suite" |  | ||||||
| 	//sdk "github.com/cosmos/cosmos-sdk/types"
 |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| type invariantTestSuite struct { |  | ||||||
| 	testutil.Suite |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestGenesisTestSuite(t *testing.T) { |  | ||||||
| 	suite.Run(t, new(invariantTestSuite)) |  | ||||||
| } |  | ||||||
							
								
								
									
										138
									
								
								x/swap/keeper/invariants.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								x/swap/keeper/invariants.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,138 @@ | |||||||
|  | package keeper | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"github.com/kava-labs/kava/x/swap/types" | ||||||
|  | 
 | ||||||
|  | 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // RegisterInvariants registers the swap module invariants
 | ||||||
|  | func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { | ||||||
|  | 	ir.RegisterRoute(types.ModuleName, "pool-records", PoolRecordsInvariant(k)) | ||||||
|  | 	ir.RegisterRoute(types.ModuleName, "share-records", ShareRecordsInvariant(k)) | ||||||
|  | 	ir.RegisterRoute(types.ModuleName, "pool-reserves", PoolReservesInvariant(k)) | ||||||
|  | 	ir.RegisterRoute(types.ModuleName, "pool-shares", PoolSharesInvariant(k)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // AllInvariants runs all invariants of the swap module
 | ||||||
|  | func AllInvariants(k Keeper) sdk.Invariant { | ||||||
|  | 	return func(ctx sdk.Context) (string, bool) { | ||||||
|  | 		if res, stop := PoolRecordsInvariant(k)(ctx); stop { | ||||||
|  | 			return res, stop | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if res, stop := ShareRecordsInvariant(k)(ctx); stop { | ||||||
|  | 			return res, stop | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if res, stop := PoolReservesInvariant(k)(ctx); stop { | ||||||
|  | 			return res, stop | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		res, stop := PoolSharesInvariant(k)(ctx) | ||||||
|  | 		return res, stop | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PoolRecordsInvariant iterates all pool records and asserts that they are valid
 | ||||||
|  | func PoolRecordsInvariant(k Keeper) sdk.Invariant { | ||||||
|  | 	broken := false | ||||||
|  | 	message := sdk.FormatInvariant(types.ModuleName, "validate pool records broken", "pool record invalid") | ||||||
|  | 
 | ||||||
|  | 	return func(ctx sdk.Context) (string, bool) { | ||||||
|  | 		k.IteratePools(ctx, func(record types.PoolRecord) bool { | ||||||
|  | 			if err := record.Validate(); err != nil { | ||||||
|  | 				broken = true | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 			return false | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		return message, broken | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ShareRecordsInvariant iterates all share records and asserts that they are valid
 | ||||||
|  | func ShareRecordsInvariant(k Keeper) sdk.Invariant { | ||||||
|  | 	broken := false | ||||||
|  | 	message := sdk.FormatInvariant(types.ModuleName, "validate share records broken", "share record invalid") | ||||||
|  | 
 | ||||||
|  | 	return func(ctx sdk.Context) (string, bool) { | ||||||
|  | 		k.IterateDepositorShares(ctx, func(record types.ShareRecord) bool { | ||||||
|  | 			if err := record.Validate(); err != nil { | ||||||
|  | 				broken = true | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 			return false | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		return message, broken | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PoolReservesInvariant iterates all pools and ensures the total reserves matches the module account coins
 | ||||||
|  | func PoolReservesInvariant(k Keeper) sdk.Invariant { | ||||||
|  | 	message := sdk.FormatInvariant(types.ModuleName, "pool reserves broken", "pool reserves do not match module account") | ||||||
|  | 
 | ||||||
|  | 	return func(ctx sdk.Context) (string, bool) { | ||||||
|  | 		mAcc := k.supplyKeeper.GetModuleAccount(ctx, types.ModuleName) | ||||||
|  | 
 | ||||||
|  | 		reserves := sdk.Coins{} | ||||||
|  | 		k.IteratePools(ctx, func(record types.PoolRecord) bool { | ||||||
|  | 			for _, coin := range record.Reserves() { | ||||||
|  | 				reserves = reserves.Add(coin) | ||||||
|  | 			} | ||||||
|  | 			return false | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		broken := !reserves.IsEqual(mAcc.GetCoins()) | ||||||
|  | 		return message, broken | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type poolShares struct { | ||||||
|  | 	totalShares      sdk.Int | ||||||
|  | 	totalSharesOwned sdk.Int | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PoolSharesInvariant iterates all pools and shares and ensures the total pool shares match the sum of depositor shares
 | ||||||
|  | func PoolSharesInvariant(k Keeper) sdk.Invariant { | ||||||
|  | 	broken := false | ||||||
|  | 	message := sdk.FormatInvariant(types.ModuleName, "pool shares broken", "pool shares do not match depositor shares") | ||||||
|  | 
 | ||||||
|  | 	return func(ctx sdk.Context) (string, bool) { | ||||||
|  | 		totalShares := make(map[string]poolShares) | ||||||
|  | 
 | ||||||
|  | 		k.IteratePools(ctx, func(pr types.PoolRecord) bool { | ||||||
|  | 			totalShares[pr.PoolID] = poolShares{ | ||||||
|  | 				totalShares:      pr.TotalShares, | ||||||
|  | 				totalSharesOwned: sdk.ZeroInt(), | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return false | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		k.IterateDepositorShares(ctx, func(sr types.ShareRecord) bool { | ||||||
|  | 			if shares, found := totalShares[sr.PoolID]; found { | ||||||
|  | 				shares.totalSharesOwned = shares.totalSharesOwned.Add(sr.SharesOwned) | ||||||
|  | 				totalShares[sr.PoolID] = shares | ||||||
|  | 			} else { | ||||||
|  | 				totalShares[sr.PoolID] = poolShares{ | ||||||
|  | 					totalShares:      sdk.ZeroInt(), | ||||||
|  | 					totalSharesOwned: sr.SharesOwned, | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return false | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		for _, ps := range totalShares { | ||||||
|  | 			if !ps.totalShares.Equal(ps.totalSharesOwned) { | ||||||
|  | 				broken = true | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return message, broken | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										235
									
								
								x/swap/keeper/invariants_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								x/swap/keeper/invariants_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,235 @@ | |||||||
|  | package keeper_test | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/kava-labs/kava/x/swap/keeper" | ||||||
|  | 	"github.com/kava-labs/kava/x/swap/testutil" | ||||||
|  | 	"github.com/kava-labs/kava/x/swap/types" | ||||||
|  | 
 | ||||||
|  | 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||||
|  | 	"github.com/stretchr/testify/suite" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type invariantTestSuite struct { | ||||||
|  | 	testutil.Suite | ||||||
|  | 	invariants map[string]map[string]sdk.Invariant | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *invariantTestSuite) SetupTest() { | ||||||
|  | 	suite.Suite.SetupTest() | ||||||
|  | 	suite.invariants = make(map[string]map[string]sdk.Invariant) | ||||||
|  | 	keeper.RegisterInvariants(suite, suite.Keeper) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *invariantTestSuite) SetupValidState() { | ||||||
|  | 	suite.Keeper.SetPool(suite.Ctx, types.NewPoolRecord( | ||||||
|  | 		sdk.NewCoins( | ||||||
|  | 			sdk.NewCoin("ukava", sdk.NewInt(1e6)), | ||||||
|  | 			sdk.NewCoin("usdx", sdk.NewInt(5e6)), | ||||||
|  | 		), | ||||||
|  | 		sdk.NewInt(3e6), | ||||||
|  | 	)) | ||||||
|  | 	suite.AddCoinsToModule( | ||||||
|  | 		sdk.NewCoins( | ||||||
|  | 			sdk.NewCoin("ukava", sdk.NewInt(1e6)), | ||||||
|  | 			sdk.NewCoin("usdx", sdk.NewInt(5e6)), | ||||||
|  | 		), | ||||||
|  | 	) | ||||||
|  | 	suite.Keeper.SetDepositorShares(suite.Ctx, types.NewShareRecord( | ||||||
|  | 		sdk.AccAddress("depositor 1"), | ||||||
|  | 		types.PoolID("ukava", "usdx"), | ||||||
|  | 		sdk.NewInt(2e6), | ||||||
|  | 	)) | ||||||
|  | 	suite.Keeper.SetDepositorShares(suite.Ctx, types.NewShareRecord( | ||||||
|  | 		sdk.AccAddress("depositor 2"), | ||||||
|  | 		types.PoolID("ukava", "usdx"), | ||||||
|  | 		sdk.NewInt(1e6), | ||||||
|  | 	)) | ||||||
|  | 
 | ||||||
|  | 	suite.Keeper.SetPool(suite.Ctx, types.NewPoolRecord( | ||||||
|  | 		sdk.NewCoins( | ||||||
|  | 			sdk.NewCoin("hard", sdk.NewInt(1e6)), | ||||||
|  | 			sdk.NewCoin("usdx", sdk.NewInt(2e6)), | ||||||
|  | 		), | ||||||
|  | 		sdk.NewInt(1e6), | ||||||
|  | 	)) | ||||||
|  | 	suite.AddCoinsToModule( | ||||||
|  | 		sdk.NewCoins( | ||||||
|  | 			sdk.NewCoin("hard", sdk.NewInt(1e6)), | ||||||
|  | 			sdk.NewCoin("usdx", sdk.NewInt(2e6)), | ||||||
|  | 		), | ||||||
|  | 	) | ||||||
|  | 	suite.Keeper.SetDepositorShares(suite.Ctx, types.NewShareRecord( | ||||||
|  | 		sdk.AccAddress("depositor 1"), | ||||||
|  | 		types.PoolID("hard", "usdx"), | ||||||
|  | 		sdk.NewInt(1e6), | ||||||
|  | 	)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *invariantTestSuite) RegisterRoute(moduleName string, route string, invariant sdk.Invariant) { | ||||||
|  | 	_, exists := suite.invariants[moduleName] | ||||||
|  | 
 | ||||||
|  | 	if !exists { | ||||||
|  | 		suite.invariants[moduleName] = make(map[string]sdk.Invariant) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	suite.invariants[moduleName][route] = invariant | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *invariantTestSuite) runInvariant(route string, invariant func(k keeper.Keeper) sdk.Invariant) (string, bool) { | ||||||
|  | 	ctx := suite.Ctx | ||||||
|  | 	registeredInvariant := suite.invariants[types.ModuleName][route] | ||||||
|  | 	suite.Require().NotNil(registeredInvariant) | ||||||
|  | 
 | ||||||
|  | 	// direct call
 | ||||||
|  | 	dMessage, dBroken := invariant(suite.Keeper)(ctx) | ||||||
|  | 	// registered call
 | ||||||
|  | 	rMessage, rBroken := registeredInvariant(ctx) | ||||||
|  | 	// all call
 | ||||||
|  | 	aMessage, aBroken := keeper.AllInvariants(suite.Keeper)(ctx) | ||||||
|  | 
 | ||||||
|  | 	// require matching values for direct call and registered call
 | ||||||
|  | 	suite.Require().Equal(dMessage, rMessage, "expected registered invariant message to match") | ||||||
|  | 	suite.Require().Equal(dBroken, rBroken, "expected registered invariant broken to match") | ||||||
|  | 	// require matching values for direct call and all invariants call if broken
 | ||||||
|  | 	suite.Require().Equal(dBroken, aBroken, "expected all invariant broken to match") | ||||||
|  | 	if dBroken { | ||||||
|  | 		suite.Require().Equal(dMessage, aMessage, "expected all invariant message to match") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// return message, broken
 | ||||||
|  | 	return dMessage, dBroken | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *invariantTestSuite) TestPoolRecordsInvariant() { | ||||||
|  | 
 | ||||||
|  | 	// default state is valid
 | ||||||
|  | 	message, broken := suite.runInvariant("pool-records", keeper.PoolRecordsInvariant) | ||||||
|  | 	suite.Equal("swap: validate pool records broken invariant\npool record invalid\n", message) | ||||||
|  | 	suite.Equal(false, broken) | ||||||
|  | 
 | ||||||
|  | 	suite.SetupValidState() | ||||||
|  | 	message, broken = suite.runInvariant("pool-records", keeper.PoolRecordsInvariant) | ||||||
|  | 	suite.Equal("swap: validate pool records broken invariant\npool record invalid\n", message) | ||||||
|  | 	suite.Equal(false, broken) | ||||||
|  | 
 | ||||||
|  | 	// broken with invalid pool record
 | ||||||
|  | 	suite.Keeper.SetPool_Raw(suite.Ctx, types.NewPoolRecord( | ||||||
|  | 		sdk.NewCoins( | ||||||
|  | 			sdk.NewCoin("ukava", sdk.NewInt(1e6)), | ||||||
|  | 			sdk.NewCoin("usdx", sdk.NewInt(5e6)), | ||||||
|  | 		), | ||||||
|  | 		sdk.NewInt(-1e6), | ||||||
|  | 	)) | ||||||
|  | 	message, broken = suite.runInvariant("pool-records", keeper.PoolRecordsInvariant) | ||||||
|  | 	suite.Equal("swap: validate pool records broken invariant\npool record invalid\n", message) | ||||||
|  | 	suite.Equal(true, broken) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *invariantTestSuite) TestShareRecordsInvariant() { | ||||||
|  | 	message, broken := suite.runInvariant("share-records", keeper.ShareRecordsInvariant) | ||||||
|  | 	suite.Equal("swap: validate share records broken invariant\nshare record invalid\n", message) | ||||||
|  | 	suite.Equal(false, broken) | ||||||
|  | 
 | ||||||
|  | 	suite.SetupValidState() | ||||||
|  | 	message, broken = suite.runInvariant("share-records", keeper.ShareRecordsInvariant) | ||||||
|  | 	suite.Equal("swap: validate share records broken invariant\nshare record invalid\n", message) | ||||||
|  | 	suite.Equal(false, broken) | ||||||
|  | 
 | ||||||
|  | 	// broken with invalid share record
 | ||||||
|  | 	suite.Keeper.SetDepositorShares_Raw(suite.Ctx, types.NewShareRecord( | ||||||
|  | 		sdk.AccAddress("depositor 1"), | ||||||
|  | 		types.PoolID("ukava", "usdx"), | ||||||
|  | 		sdk.NewInt(-1e6), | ||||||
|  | 	)) | ||||||
|  | 	message, broken = suite.runInvariant("share-records", keeper.ShareRecordsInvariant) | ||||||
|  | 	suite.Equal("swap: validate share records broken invariant\nshare record invalid\n", message) | ||||||
|  | 	suite.Equal(true, broken) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *invariantTestSuite) TestPoolReservesInvariant() { | ||||||
|  | 	message, broken := suite.runInvariant("pool-reserves", keeper.PoolReservesInvariant) | ||||||
|  | 	suite.Equal("swap: pool reserves broken invariant\npool reserves do not match module account\n", message) | ||||||
|  | 	suite.Equal(false, broken) | ||||||
|  | 
 | ||||||
|  | 	suite.SetupValidState() | ||||||
|  | 	message, broken = suite.runInvariant("pool-reserves", keeper.PoolReservesInvariant) | ||||||
|  | 	suite.Equal("swap: pool reserves broken invariant\npool reserves do not match module account\n", message) | ||||||
|  | 	suite.Equal(false, broken) | ||||||
|  | 
 | ||||||
|  | 	// broken when reserves are greater than module balance
 | ||||||
|  | 	suite.Keeper.SetPool(suite.Ctx, types.NewPoolRecord( | ||||||
|  | 		sdk.NewCoins( | ||||||
|  | 			sdk.NewCoin("ukava", sdk.NewInt(2e6)), | ||||||
|  | 			sdk.NewCoin("usdx", sdk.NewInt(10e6)), | ||||||
|  | 		), | ||||||
|  | 		sdk.NewInt(5e6), | ||||||
|  | 	)) | ||||||
|  | 	message, broken = suite.runInvariant("pool-reserves", keeper.PoolReservesInvariant) | ||||||
|  | 	suite.Equal("swap: pool reserves broken invariant\npool reserves do not match module account\n", message) | ||||||
|  | 	suite.Equal(true, broken) | ||||||
|  | 
 | ||||||
|  | 	// broken when reserves are less than the module balance
 | ||||||
|  | 	suite.Keeper.SetPool(suite.Ctx, types.NewPoolRecord( | ||||||
|  | 		sdk.NewCoins( | ||||||
|  | 			sdk.NewCoin("ukava", sdk.NewInt(1e5)), | ||||||
|  | 			sdk.NewCoin("usdx", sdk.NewInt(5e5)), | ||||||
|  | 		), | ||||||
|  | 		sdk.NewInt(3e5), | ||||||
|  | 	)) | ||||||
|  | 	message, broken = suite.runInvariant("pool-reserves", keeper.PoolReservesInvariant) | ||||||
|  | 	suite.Equal("swap: pool reserves broken invariant\npool reserves do not match module account\n", message) | ||||||
|  | 	suite.Equal(true, broken) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *invariantTestSuite) TestPoolSharesInvariant() { | ||||||
|  | 	message, broken := suite.runInvariant("pool-shares", keeper.PoolSharesInvariant) | ||||||
|  | 	suite.Equal("swap: pool shares broken invariant\npool shares do not match depositor shares\n", message) | ||||||
|  | 	suite.Equal(false, broken) | ||||||
|  | 
 | ||||||
|  | 	suite.SetupValidState() | ||||||
|  | 	message, broken = suite.runInvariant("pool-shares", keeper.PoolSharesInvariant) | ||||||
|  | 	suite.Equal("swap: pool shares broken invariant\npool shares do not match depositor shares\n", message) | ||||||
|  | 	suite.Equal(false, broken) | ||||||
|  | 
 | ||||||
|  | 	// broken when total shares are greater than depositor shares
 | ||||||
|  | 	suite.Keeper.SetPool(suite.Ctx, types.NewPoolRecord( | ||||||
|  | 		sdk.NewCoins( | ||||||
|  | 			sdk.NewCoin("ukava", sdk.NewInt(1e6)), | ||||||
|  | 			sdk.NewCoin("usdx", sdk.NewInt(5e6)), | ||||||
|  | 		), | ||||||
|  | 		sdk.NewInt(5e6), | ||||||
|  | 	)) | ||||||
|  | 	message, broken = suite.runInvariant("pool-shares", keeper.PoolSharesInvariant) | ||||||
|  | 	suite.Equal("swap: pool shares broken invariant\npool shares do not match depositor shares\n", message) | ||||||
|  | 	suite.Equal(true, broken) | ||||||
|  | 
 | ||||||
|  | 	// broken when total shares are less than the depositor shares
 | ||||||
|  | 	suite.Keeper.SetPool(suite.Ctx, types.NewPoolRecord( | ||||||
|  | 		sdk.NewCoins( | ||||||
|  | 			sdk.NewCoin("ukava", sdk.NewInt(1e6)), | ||||||
|  | 			sdk.NewCoin("usdx", sdk.NewInt(5e6)), | ||||||
|  | 		), | ||||||
|  | 		sdk.NewInt(1e5), | ||||||
|  | 	)) | ||||||
|  | 	message, broken = suite.runInvariant("pool-shares", keeper.PoolSharesInvariant) | ||||||
|  | 	suite.Equal("swap: pool shares broken invariant\npool shares do not match depositor shares\n", message) | ||||||
|  | 	suite.Equal(true, broken) | ||||||
|  | 
 | ||||||
|  | 	// broken when pool record is missing
 | ||||||
|  | 	suite.Keeper.DeletePool(suite.Ctx, types.PoolID("ukava", "usdx")) | ||||||
|  | 	suite.RemoveCoinsFromModule( | ||||||
|  | 		sdk.NewCoins( | ||||||
|  | 			sdk.NewCoin("ukava", sdk.NewInt(1e6)), | ||||||
|  | 			sdk.NewCoin("usdx", sdk.NewInt(5e6)), | ||||||
|  | 		), | ||||||
|  | 	) | ||||||
|  | 	message, broken = suite.runInvariant("pool-shares", keeper.PoolSharesInvariant) | ||||||
|  | 	suite.Equal("swap: pool shares broken invariant\npool shares do not match depositor shares\n", message) | ||||||
|  | 	suite.Equal(true, broken) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestInvariantTestSuite(t *testing.T) { | ||||||
|  | 	suite.Run(t, new(invariantTestSuite)) | ||||||
|  | } | ||||||
| @ -96,7 +96,9 @@ func (AppModule) Name() string { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // RegisterInvariants register module invariants
 | // RegisterInvariants register module invariants
 | ||||||
| func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} | func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { | ||||||
|  | 	keeper.RegisterInvariants(ir, am.keeper) | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| // Route module message route name
 | // Route module message route name
 | ||||||
| func (AppModule) Route() string { | func (AppModule) Route() string { | ||||||
|  | |||||||
							
								
								
									
										40
									
								
								x/swap/module_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								x/swap/module_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | package swap_test | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/kava-labs/kava/x/swap" | ||||||
|  | 	"github.com/kava-labs/kava/x/swap/testutil" | ||||||
|  | 
 | ||||||
|  | 	"github.com/cosmos/cosmos-sdk/x/crisis" | ||||||
|  | 	"github.com/stretchr/testify/suite" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type moduleTestSuite struct { | ||||||
|  | 	testutil.Suite | ||||||
|  | 	crisisKeeper crisis.Keeper | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *moduleTestSuite) SetupTest() { | ||||||
|  | 	suite.Suite.SetupTest() | ||||||
|  | 	suite.crisisKeeper = suite.App.GetCrisisKeeper() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *moduleTestSuite) TestRegisterInvariants() { | ||||||
|  | 	swapRoutes := []string{} | ||||||
|  | 
 | ||||||
|  | 	for _, route := range suite.crisisKeeper.Routes() { | ||||||
|  | 		if route.ModuleName == swap.ModuleName { | ||||||
|  | 			swapRoutes = append(swapRoutes, route.Route) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	suite.Contains(swapRoutes, "pool-records") | ||||||
|  | 	suite.Contains(swapRoutes, "share-records") | ||||||
|  | 	suite.Contains(swapRoutes, "pool-reserves") | ||||||
|  | 	suite.Contains(swapRoutes, "pool-shares") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestModuleTestSuite(t *testing.T) { | ||||||
|  | 	suite.Run(t, new(moduleTestSuite)) | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Nick DeLuca
						Nick DeLuca